We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Telegram connector needs update for event message
# Description
The telegram connector uses message.target['id'] instead of message.target.  This leads to problems when trying to use default_target per normal configuration and usage of the event flow logic.

## Steps to Reproduce
Setup telegram as the default connector... call the telegram connector.send with a target...  
```
await self.opsdroid.send(Message(text='hello', target='<useridhere>') 
```
The default_target is also always None.
```
await self.opsdroid.send(Message(text='hello')  
```
You can hack around it with..
```
sillytarget = { 'id': <useridhere> }
await self.opsdroid.send(Message(text='hello', target=sillytarget) 
```
## Expected Functionality
message.target should work like the other core connectors

## Experienced Functionality
Errors out.
```
opsdroid    | ERROR opsdroid.connector.telegram.send_message(): Unable to respond.   
```
## Versions

- opsdroid: latest/stable
- python 3.7.6
- docker image: opsdroid/opsdroid:latest

## Configuration File
```yaml
connectors:
## Telegram (core)
  telegram:
    token: "......"
   # optional
    update-interval: 0.5  # Interval between checking for messages
    whitelisted-users:  # List of users who can speak to the bot, if not set anyone can speak
      - ......
```
## Additional Details
None

<!-- Love opsdroid? Please consider supporting our collective:
 +👉  https://opencollective.com/opsdroid/donate -->


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `opsdroid/connector/telegram/__init__.py`
Content:
```
1 """A connector for Telegram."""
2 import asyncio
3 import logging
4 import aiohttp
5 from voluptuous import Required
6 
7 from opsdroid.connector import Connector, register_event
8 from opsdroid.events import Message, Image
9 
10 
11 _LOGGER = logging.getLogger(__name__)
12 CONFIG_SCHEMA = {
13     Required("token"): str,
14     "update-interval": float,
15     "default-user": str,
16     "whitelisted-users": list,
17 }
18 
19 
20 class ConnectorTelegram(Connector):
21     """A connector the the char service Telegram."""
22 
23     def __init__(self, config, opsdroid=None):
24         """Create the connector.
25 
26         Args:
27             config (dict): configuration settings from the
28                 file config.yaml.
29             opsdroid (OpsDroid): An instance of opsdroid.core.
30 
31         """
32         _LOGGER.debug(_("Loaded Telegram Connector"))
33         super().__init__(config, opsdroid=opsdroid)
34         self.name = "telegram"
35         self.opsdroid = opsdroid
36         self.latest_update = None
37         self.default_target = None
38         self.listening = True
39         self.default_user = config.get("default-user", None)
40         self.whitelisted_users = config.get("whitelisted-users", None)
41         self.update_interval = config.get("update-interval", 1)
42         self.session = None
43         self._closing = asyncio.Event()
44         self.loop = asyncio.get_event_loop()
45 
46         try:
47             self.token = config["token"]
48         except (KeyError, AttributeError):
49             _LOGGER.error(
50                 _(
51                     "Unable to login: Access token is missing. Telegram connector will be unavailable."
52                 )
53             )
54 
55     @staticmethod
56     def get_user(response):
57         """Get user from response.
58 
59         The API response is different depending on how
60         the bot is set up and where the message is coming
61         from. This method was created to keep if/else
62         statements to a minium on  _parse_message.
63 
64         Args:
65             response (dict): Response returned by aiohttp.ClientSession.
66 
67         """
68         user = None
69         user_id = None
70 
71         if "username" in response["message"]["from"]:
72             user = response["message"]["from"]["username"]
73 
74         elif "first_name" in response["message"]["from"]:
75             user = response["message"]["from"]["first_name"]
76         user_id = response["message"]["from"]["id"]
77 
78         return user, user_id
79 
80     def handle_user_permission(self, response, user):
81         """Handle user permissions.
82 
83         This will check if the user that tried to talk with
84         the bot is allowed to do so. It will also work with
85         userid to improve security.
86 
87         """
88         user_id = response["message"]["from"]["id"]
89 
90         if (
91             not self.whitelisted_users
92             or user in self.whitelisted_users
93             or user_id in self.whitelisted_users
94         ):
95             return True
96 
97         return False
98 
99     def build_url(self, method):
100         """Build the url to connect to the API.
101 
102         Args:
103             method (string): API call end point.
104 
105         Return:
106             String that represents the full API url.
107 
108         """
109         return "https://api.telegram.org/bot{}/{}".format(self.token, method)
110 
111     async def delete_webhook(self):
112         """Delete Telegram webhook.
113 
114         The Telegram api will thrown an 409 error when an webhook is
115         active and a call to getUpdates is made. This method will
116         try to request the deletion of the webhook to make the getUpdate
117         request possible.
118 
119         """
120         _LOGGER.debug(_("Sending deleteWebhook request to Telegram..."))
121         resp = await self.session.get(self.build_url("deleteWebhook"))
122 
123         if resp.status == 200:
124             _LOGGER.debug(_("Telegram webhook deleted successfully."))
125         else:
126             _LOGGER.debug(_("Unable to delete webhook."))
127 
128     async def connect(self):
129         """Connect to Telegram.
130 
131         This method is not an authorization call. It basically
132         checks if the API token was provided and makes an API
133         call to Telegram and evaluates the status of the call.
134 
135         """
136 
137         _LOGGER.debug(_("Connecting to Telegram."))
138         self.session = aiohttp.ClientSession()
139 
140         resp = await self.session.get(self.build_url("getMe"))
141 
142         if resp.status != 200:
143             _LOGGER.error(_("Unable to connect."))
144             _LOGGER.error(_("Telegram error %s, %s."), resp.status, resp.text)
145         else:
146             json = await resp.json()
147             _LOGGER.debug(json)
148             _LOGGER.debug(_("Connected to Telegram as %s."), json["result"]["username"])
149 
150     async def _parse_message(self, response):
151         """Handle logic to parse a received message.
152 
153         Since everyone can send a private message to any user/bot
154         in Telegram, this method allows to set a list of whitelisted
155         users that can interact with the bot. If any other user tries
156         to interact with the bot the command is not parsed and instead
157         the bot will inform that user that he is not allowed to talk
158         with the bot.
159 
160         We also set self.latest_update to +1 in order to get the next
161         available message (or an empty {} if no message has been received
162         yet) with the method self._get_messages().
163 
164         Args:
165             response (dict): Response returned by aiohttp.ClientSession.
166 
167         """
168         for result in response["result"]:
169             _LOGGER.debug(result)
170             if result.get("edited_message", None):
171                 result["message"] = result.pop("edited_message")
172             if "channel" in result["message"]["chat"]["type"]:
173                 _LOGGER.debug(
174                     _("Channel message parsing not supported " "- Ignoring message.")
175                 )
176             elif "message" in result and "text" in result["message"]:
177                 user, user_id = self.get_user(result)
178                 message = Message(
179                     text=result["message"]["text"],
180                     user=user,
181                     user_id=user_id,
182                     target=result["message"]["chat"],
183                     connector=self,
184                 )
185 
186                 if self.handle_user_permission(result, user):
187                     await self.opsdroid.parse(message)
188                 else:
189                     message.text = (
190                         "Sorry, you're not allowed " "to speak with this bot."
191                     )
192                     await self.send(message)
193                 self.latest_update = result["update_id"] + 1
194             elif (
195                 "message" in result
196                 and "sticker" in result["message"]
197                 and "emoji" in result["message"]["sticker"]
198             ):
199                 self.latest_update = result["update_id"] + 1
200                 _LOGGER.debug(
201                     _("Emoji message parsing not supported - Ignoring message.")
202                 )
203             else:
204                 _LOGGER.error(_("Unable to parse the message."))
205 
206     async def _get_messages(self):
207         """Connect to the Telegram API.
208 
209         Uses an aiohttp ClientSession to connect to Telegram API
210         and get the latest messages from the chat service.
211 
212         The data["offset"] is used to consume every new message, the API
213         returns an  int - "update_id" value. In order to get the next
214         message this value needs to be increased by 1 the next time
215         the API is called. If no new messages exists the API will just
216         return an empty {}.
217 
218         """
219         data = {}
220         if self.latest_update is not None:
221             data["offset"] = self.latest_update
222 
223         await asyncio.sleep(self.update_interval)
224         resp = await self.session.get(self.build_url("getUpdates"), params=data)
225 
226         if resp.status == 409:
227             _LOGGER.info(
228                 _(
229                     "Can't get updates because previous webhook is still active. Will try to delete webhook."
230                 )
231             )
232             await self.delete_webhook()
233 
234         if resp.status != 200:
235             _LOGGER.error(_("Telegram error %s, %s."), resp.status, resp.text)
236             self.listening = False
237         else:
238             json = await resp.json()
239 
240             await self._parse_message(json)
241 
242     async def get_messages_loop(self):
243         """Listen for and parse new messages.
244 
245         The bot will always listen to all opened chat windows,
246         as long as opsdroid is running. Since anyone can start
247         a new chat with the bot is recommended that a list of
248         users to be whitelisted be provided in config.yaml.
249 
250         The method will sleep asynchronously at the end of
251         every loop. The time can either be specified in the
252         config.yaml with the param update-interval - this
253         defaults to 1 second.
254 
255         """
256         while self.listening:
257             await self._get_messages()
258 
259     async def listen(self):
260         """Listen method of the connector.
261 
262         Every connector has to implement the listen method. When an
263         infinite loop is running, it becomes hard to cancel this task.
264         So we are creating a task and set it on a variable so we can
265         cancel the task.
266 
267         """
268         message_getter = self.loop.create_task(await self.get_messages_loop())
269         await self._closing.wait()
270         message_getter.cancel()
271 
272     @register_event(Message)
273     async def send_message(self, message):
274         """Respond with a message.
275 
276         Args:
277             message (object): An instance of Message.
278 
279         """
280         _LOGGER.debug(_("Responding with: %s."), message.text)
281 
282         data = dict()
283         data["chat_id"] = message.target["id"]
284         data["text"] = message.text
285         resp = await self.session.post(self.build_url("sendMessage"), data=data)
286         if resp.status == 200:
287             _LOGGER.debug(_("Successfully responded."))
288         else:
289             _LOGGER.error(_("Unable to respond."))
290 
291     @register_event(Image)
292     async def send_image(self, file_event):
293         """Send Image to Telegram.
294 
295         Gets the chat id from the channel and then
296         sends the bytes of the image as multipart/form-data.
297 
298         """
299         data = aiohttp.FormData()
300         data.add_field(
301             "chat_id", str(file_event.target["id"]), content_type="multipart/form-data"
302         )
303         data.add_field(
304             "photo",
305             await file_event.get_file_bytes(),
306             content_type="multipart/form-data",
307         )
308 
309         resp = await self.session.post(self.build_url("sendPhoto"), data=data)
310         if resp.status == 200:
311             _LOGGER.debug(_("Sent %s image successfully."), file_event.name)
312         else:
313             _LOGGER.debug(_("Unable to send image - Status Code %s."), resp.status)
314 
315     async def disconnect(self):
316         """Disconnect from Telegram.
317 
318         Stops the infinite loop found in self._listen(), closes
319         aiohttp session.
320 
321         """
322         self.listening = False
323         self._closing.set()
324         await self.session.close()
325
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/opsdroid/connector/telegram/__init__.py b/opsdroid/connector/telegram/__init__.py
--- a/opsdroid/connector/telegram/__init__.py
+++ b/opsdroid/connector/telegram/__init__.py
@@ -34,9 +34,9 @@
         self.name = "telegram"
         self.opsdroid = opsdroid
         self.latest_update = None
-        self.default_target = None
         self.listening = True
         self.default_user = config.get("default-user", None)
+        self.default_target = self.default_user
         self.whitelisted_users = config.get("whitelisted-users", None)
         self.update_interval = config.get("update-interval", 1)
         self.session = None
@@ -167,9 +167,13 @@
         """
         for result in response["result"]:
             _LOGGER.debug(result)
+
             if result.get("edited_message", None):
                 result["message"] = result.pop("edited_message")
-            if "channel" in result["message"]["chat"]["type"]:
+            if result.get("channel_post", None) or result.get(
+                "edited_channel_post", None
+            ):
+                self.latest_update = result["update_id"] + 1
                 _LOGGER.debug(
                     _("Channel message parsing not supported " "- Ignoring message.")
                 )
@@ -179,7 +183,7 @@
                     text=result["message"]["text"],
                     user=user,
                     user_id=user_id,
-                    target=result["message"]["chat"],
+                    target=result["message"]["chat"]["id"],
                     connector=self,
                 )
 
@@ -277,10 +281,12 @@
             message (object): An instance of Message.
 
         """
-        _LOGGER.debug(_("Responding with: %s."), message.text)
+        _LOGGER.debug(
+            _("Responding with: '%s' at target: '%s'"), message.text, message.target
+        )
 
         data = dict()
-        data["chat_id"] = message.target["id"]
+        data["chat_id"] = message.target
         data["text"] = message.text
         resp = await self.session.post(self.build_url("sendMessage"), data=data)
         if resp.status == 200:

{"golden_diff": "diff --git a/opsdroid/connector/telegram/__init__.py b/opsdroid/connector/telegram/__init__.py\n--- a/opsdroid/connector/telegram/__init__.py\n+++ b/opsdroid/connector/telegram/__init__.py\n@@ -34,9 +34,9 @@\n         self.name = \"telegram\"\n         self.opsdroid = opsdroid\n         self.latest_update = None\n-        self.default_target = None\n         self.listening = True\n         self.default_user = config.get(\"default-user\", None)\n+        self.default_target = self.default_user\n         self.whitelisted_users = config.get(\"whitelisted-users\", None)\n         self.update_interval = config.get(\"update-interval\", 1)\n         self.session = None\n@@ -167,9 +167,13 @@\n         \"\"\"\n         for result in response[\"result\"]:\n             _LOGGER.debug(result)\n+\n             if result.get(\"edited_message\", None):\n                 result[\"message\"] = result.pop(\"edited_message\")\n-            if \"channel\" in result[\"message\"][\"chat\"][\"type\"]:\n+            if result.get(\"channel_post\", None) or result.get(\n+                \"edited_channel_post\", None\n+            ):\n+                self.latest_update = result[\"update_id\"] + 1\n                 _LOGGER.debug(\n                     _(\"Channel message parsing not supported \" \"- Ignoring message.\")\n                 )\n@@ -179,7 +183,7 @@\n                     text=result[\"message\"][\"text\"],\n                     user=user,\n                     user_id=user_id,\n-                    target=result[\"message\"][\"chat\"],\n+                    target=result[\"message\"][\"chat\"][\"id\"],\n                     connector=self,\n                 )\n \n@@ -277,10 +281,12 @@\n             message (object): An instance of Message.\n \n         \"\"\"\n-        _LOGGER.debug(_(\"Responding with: %s.\"), message.text)\n+        _LOGGER.debug(\n+            _(\"Responding with: '%s' at target: '%s'\"), message.text, message.target\n+        )\n \n         data = dict()\n-        data[\"chat_id\"] = message.target[\"id\"]\n+        data[\"chat_id\"] = message.target\n         data[\"text\"] = message.text\n         resp = await self.session.post(self.build_url(\"sendMessage\"), data=data)\n         if resp.status == 200:\n", "issue": "Telegram connector needs update for event message\n# Description\r\nThe telegram connector uses message.target['id'] instead of message.target.  This leads to problems when trying to use default_target per normal configuration and usage of the event flow logic.\r\n\r\n## Steps to Reproduce\r\nSetup telegram as the default connector... call the telegram connector.send with a target...  \r\n```\r\nawait self.opsdroid.send(Message(text='hello', target='<useridhere>') \r\n```\r\nThe default_target is also always None.\r\n```\r\nawait self.opsdroid.send(Message(text='hello')  \r\n```\r\nYou can hack around it with..\r\n```\r\nsillytarget = { 'id': <useridhere> }\r\nawait self.opsdroid.send(Message(text='hello', target=sillytarget) \r\n```\r\n## Expected Functionality\r\nmessage.target should work like the other core connectors\r\n\r\n## Experienced Functionality\r\nErrors out.\r\n```\r\nopsdroid    | ERROR opsdroid.connector.telegram.send_message(): Unable to respond.   \r\n```\r\n## Versions\r\n\r\n- opsdroid: latest/stable\r\n- python 3.7.6\r\n- docker image: opsdroid/opsdroid:latest\r\n\r\n## Configuration File\r\n```yaml\r\nconnectors:\r\n## Telegram (core)\r\n  telegram:\r\n    token: \"......\"\r\n   # optional\r\n    update-interval: 0.5  # Interval between checking for messages\r\n    whitelisted-users:  # List of users who can speak to the bot, if not set anyone can speak\r\n      - ......\r\n```\r\n## Additional Details\r\nNone\r\n\r\n<!-- Love opsdroid? Please consider supporting our collective:\r\n +\ud83d\udc49  https://opencollective.com/opsdroid/donate -->\r\n\n", "before_files": [{"content": "\"\"\"A connector for Telegram.\"\"\"\nimport asyncio\nimport logging\nimport aiohttp\nfrom voluptuous import Required\n\nfrom opsdroid.connector import Connector, register_event\nfrom opsdroid.events import Message, Image\n\n\n_LOGGER = logging.getLogger(__name__)\nCONFIG_SCHEMA = {\n    Required(\"token\"): str,\n    \"update-interval\": float,\n    \"default-user\": str,\n    \"whitelisted-users\": list,\n}\n\n\nclass ConnectorTelegram(Connector):\n    \"\"\"A connector the the char service Telegram.\"\"\"\n\n    def __init__(self, config, opsdroid=None):\n        \"\"\"Create the connector.\n\n        Args:\n            config (dict): configuration settings from the\n                file config.yaml.\n            opsdroid (OpsDroid): An instance of opsdroid.core.\n\n        \"\"\"\n        _LOGGER.debug(_(\"Loaded Telegram Connector\"))\n        super().__init__(config, opsdroid=opsdroid)\n        self.name = \"telegram\"\n        self.opsdroid = opsdroid\n        self.latest_update = None\n        self.default_target = None\n        self.listening = True\n        self.default_user = config.get(\"default-user\", None)\n        self.whitelisted_users = config.get(\"whitelisted-users\", None)\n        self.update_interval = config.get(\"update-interval\", 1)\n        self.session = None\n        self._closing = asyncio.Event()\n        self.loop = asyncio.get_event_loop()\n\n        try:\n            self.token = config[\"token\"]\n        except (KeyError, AttributeError):\n            _LOGGER.error(\n                _(\n                    \"Unable to login: Access token is missing. Telegram connector will be unavailable.\"\n                )\n            )\n\n    @staticmethod\n    def get_user(response):\n        \"\"\"Get user from response.\n\n        The API response is different depending on how\n        the bot is set up and where the message is coming\n        from. This method was created to keep if/else\n        statements to a minium on  _parse_message.\n\n        Args:\n            response (dict): Response returned by aiohttp.ClientSession.\n\n        \"\"\"\n        user = None\n        user_id = None\n\n        if \"username\" in response[\"message\"][\"from\"]:\n            user = response[\"message\"][\"from\"][\"username\"]\n\n        elif \"first_name\" in response[\"message\"][\"from\"]:\n            user = response[\"message\"][\"from\"][\"first_name\"]\n        user_id = response[\"message\"][\"from\"][\"id\"]\n\n        return user, user_id\n\n    def handle_user_permission(self, response, user):\n        \"\"\"Handle user permissions.\n\n        This will check if the user that tried to talk with\n        the bot is allowed to do so. It will also work with\n        userid to improve security.\n\n        \"\"\"\n        user_id = response[\"message\"][\"from\"][\"id\"]\n\n        if (\n            not self.whitelisted_users\n            or user in self.whitelisted_users\n            or user_id in self.whitelisted_users\n        ):\n            return True\n\n        return False\n\n    def build_url(self, method):\n        \"\"\"Build the url to connect to the API.\n\n        Args:\n            method (string): API call end point.\n\n        Return:\n            String that represents the full API url.\n\n        \"\"\"\n        return \"https://api.telegram.org/bot{}/{}\".format(self.token, method)\n\n    async def delete_webhook(self):\n        \"\"\"Delete Telegram webhook.\n\n        The Telegram api will thrown an 409 error when an webhook is\n        active and a call to getUpdates is made. This method will\n        try to request the deletion of the webhook to make the getUpdate\n        request possible.\n\n        \"\"\"\n        _LOGGER.debug(_(\"Sending deleteWebhook request to Telegram...\"))\n        resp = await self.session.get(self.build_url(\"deleteWebhook\"))\n\n        if resp.status == 200:\n            _LOGGER.debug(_(\"Telegram webhook deleted successfully.\"))\n        else:\n            _LOGGER.debug(_(\"Unable to delete webhook.\"))\n\n    async def connect(self):\n        \"\"\"Connect to Telegram.\n\n        This method is not an authorization call. It basically\n        checks if the API token was provided and makes an API\n        call to Telegram and evaluates the status of the call.\n\n        \"\"\"\n\n        _LOGGER.debug(_(\"Connecting to Telegram.\"))\n        self.session = aiohttp.ClientSession()\n\n        resp = await self.session.get(self.build_url(\"getMe\"))\n\n        if resp.status != 200:\n            _LOGGER.error(_(\"Unable to connect.\"))\n            _LOGGER.error(_(\"Telegram error %s, %s.\"), resp.status, resp.text)\n        else:\n            json = await resp.json()\n            _LOGGER.debug(json)\n            _LOGGER.debug(_(\"Connected to Telegram as %s.\"), json[\"result\"][\"username\"])\n\n    async def _parse_message(self, response):\n        \"\"\"Handle logic to parse a received message.\n\n        Since everyone can send a private message to any user/bot\n        in Telegram, this method allows to set a list of whitelisted\n        users that can interact with the bot. If any other user tries\n        to interact with the bot the command is not parsed and instead\n        the bot will inform that user that he is not allowed to talk\n        with the bot.\n\n        We also set self.latest_update to +1 in order to get the next\n        available message (or an empty {} if no message has been received\n        yet) with the method self._get_messages().\n\n        Args:\n            response (dict): Response returned by aiohttp.ClientSession.\n\n        \"\"\"\n        for result in response[\"result\"]:\n            _LOGGER.debug(result)\n            if result.get(\"edited_message\", None):\n                result[\"message\"] = result.pop(\"edited_message\")\n            if \"channel\" in result[\"message\"][\"chat\"][\"type\"]:\n                _LOGGER.debug(\n                    _(\"Channel message parsing not supported \" \"- Ignoring message.\")\n                )\n            elif \"message\" in result and \"text\" in result[\"message\"]:\n                user, user_id = self.get_user(result)\n                message = Message(\n                    text=result[\"message\"][\"text\"],\n                    user=user,\n                    user_id=user_id,\n                    target=result[\"message\"][\"chat\"],\n                    connector=self,\n                )\n\n                if self.handle_user_permission(result, user):\n                    await self.opsdroid.parse(message)\n                else:\n                    message.text = (\n                        \"Sorry, you're not allowed \" \"to speak with this bot.\"\n                    )\n                    await self.send(message)\n                self.latest_update = result[\"update_id\"] + 1\n            elif (\n                \"message\" in result\n                and \"sticker\" in result[\"message\"]\n                and \"emoji\" in result[\"message\"][\"sticker\"]\n            ):\n                self.latest_update = result[\"update_id\"] + 1\n                _LOGGER.debug(\n                    _(\"Emoji message parsing not supported - Ignoring message.\")\n                )\n            else:\n                _LOGGER.error(_(\"Unable to parse the message.\"))\n\n    async def _get_messages(self):\n        \"\"\"Connect to the Telegram API.\n\n        Uses an aiohttp ClientSession to connect to Telegram API\n        and get the latest messages from the chat service.\n\n        The data[\"offset\"] is used to consume every new message, the API\n        returns an  int - \"update_id\" value. In order to get the next\n        message this value needs to be increased by 1 the next time\n        the API is called. If no new messages exists the API will just\n        return an empty {}.\n\n        \"\"\"\n        data = {}\n        if self.latest_update is not None:\n            data[\"offset\"] = self.latest_update\n\n        await asyncio.sleep(self.update_interval)\n        resp = await self.session.get(self.build_url(\"getUpdates\"), params=data)\n\n        if resp.status == 409:\n            _LOGGER.info(\n                _(\n                    \"Can't get updates because previous webhook is still active. Will try to delete webhook.\"\n                )\n            )\n            await self.delete_webhook()\n\n        if resp.status != 200:\n            _LOGGER.error(_(\"Telegram error %s, %s.\"), resp.status, resp.text)\n            self.listening = False\n        else:\n            json = await resp.json()\n\n            await self._parse_message(json)\n\n    async def get_messages_loop(self):\n        \"\"\"Listen for and parse new messages.\n\n        The bot will always listen to all opened chat windows,\n        as long as opsdroid is running. Since anyone can start\n        a new chat with the bot is recommended that a list of\n        users to be whitelisted be provided in config.yaml.\n\n        The method will sleep asynchronously at the end of\n        every loop. The time can either be specified in the\n        config.yaml with the param update-interval - this\n        defaults to 1 second.\n\n        \"\"\"\n        while self.listening:\n            await self._get_messages()\n\n    async def listen(self):\n        \"\"\"Listen method of the connector.\n\n        Every connector has to implement the listen method. When an\n        infinite loop is running, it becomes hard to cancel this task.\n        So we are creating a task and set it on a variable so we can\n        cancel the task.\n\n        \"\"\"\n        message_getter = self.loop.create_task(await self.get_messages_loop())\n        await self._closing.wait()\n        message_getter.cancel()\n\n    @register_event(Message)\n    async def send_message(self, message):\n        \"\"\"Respond with a message.\n\n        Args:\n            message (object): An instance of Message.\n\n        \"\"\"\n        _LOGGER.debug(_(\"Responding with: %s.\"), message.text)\n\n        data = dict()\n        data[\"chat_id\"] = message.target[\"id\"]\n        data[\"text\"] = message.text\n        resp = await self.session.post(self.build_url(\"sendMessage\"), data=data)\n        if resp.status == 200:\n            _LOGGER.debug(_(\"Successfully responded.\"))\n        else:\n            _LOGGER.error(_(\"Unable to respond.\"))\n\n    @register_event(Image)\n    async def send_image(self, file_event):\n        \"\"\"Send Image to Telegram.\n\n        Gets the chat id from the channel and then\n        sends the bytes of the image as multipart/form-data.\n\n        \"\"\"\n        data = aiohttp.FormData()\n        data.add_field(\n            \"chat_id\", str(file_event.target[\"id\"]), content_type=\"multipart/form-data\"\n        )\n        data.add_field(\n            \"photo\",\n            await file_event.get_file_bytes(),\n            content_type=\"multipart/form-data\",\n        )\n\n        resp = await self.session.post(self.build_url(\"sendPhoto\"), data=data)\n        if resp.status == 200:\n            _LOGGER.debug(_(\"Sent %s image successfully.\"), file_event.name)\n        else:\n            _LOGGER.debug(_(\"Unable to send image - Status Code %s.\"), resp.status)\n\n    async def disconnect(self):\n        \"\"\"Disconnect from Telegram.\n\n        Stops the infinite loop found in self._listen(), closes\n        aiohttp session.\n\n        \"\"\"\n        self.listening = False\n        self._closing.set()\n        await self.session.close()\n", "path": "opsdroid/connector/telegram/__init__.py"}], "after_files": [{"content": "\"\"\"A connector for Telegram.\"\"\"\nimport asyncio\nimport logging\nimport aiohttp\nfrom voluptuous import Required\n\nfrom opsdroid.connector import Connector, register_event\nfrom opsdroid.events import Message, Image\n\n\n_LOGGER = logging.getLogger(__name__)\nCONFIG_SCHEMA = {\n    Required(\"token\"): str,\n    \"update-interval\": float,\n    \"default-user\": str,\n    \"whitelisted-users\": list,\n}\n\n\nclass ConnectorTelegram(Connector):\n    \"\"\"A connector the the char service Telegram.\"\"\"\n\n    def __init__(self, config, opsdroid=None):\n        \"\"\"Create the connector.\n\n        Args:\n            config (dict): configuration settings from the\n                file config.yaml.\n            opsdroid (OpsDroid): An instance of opsdroid.core.\n\n        \"\"\"\n        _LOGGER.debug(_(\"Loaded Telegram Connector\"))\n        super().__init__(config, opsdroid=opsdroid)\n        self.name = \"telegram\"\n        self.opsdroid = opsdroid\n        self.latest_update = None\n        self.listening = True\n        self.default_user = config.get(\"default-user\", None)\n        self.default_target = self.default_user\n        self.whitelisted_users = config.get(\"whitelisted-users\", None)\n        self.update_interval = config.get(\"update-interval\", 1)\n        self.session = None\n        self._closing = asyncio.Event()\n        self.loop = asyncio.get_event_loop()\n\n        try:\n            self.token = config[\"token\"]\n        except (KeyError, AttributeError):\n            _LOGGER.error(\n                _(\n                    \"Unable to login: Access token is missing. Telegram connector will be unavailable.\"\n                )\n            )\n\n    @staticmethod\n    def get_user(response):\n        \"\"\"Get user from response.\n\n        The API response is different depending on how\n        the bot is set up and where the message is coming\n        from. This method was created to keep if/else\n        statements to a minium on  _parse_message.\n\n        Args:\n            response (dict): Response returned by aiohttp.ClientSession.\n\n        \"\"\"\n        user = None\n        user_id = None\n\n        if \"username\" in response[\"message\"][\"from\"]:\n            user = response[\"message\"][\"from\"][\"username\"]\n\n        elif \"first_name\" in response[\"message\"][\"from\"]:\n            user = response[\"message\"][\"from\"][\"first_name\"]\n        user_id = response[\"message\"][\"from\"][\"id\"]\n\n        return user, user_id\n\n    def handle_user_permission(self, response, user):\n        \"\"\"Handle user permissions.\n\n        This will check if the user that tried to talk with\n        the bot is allowed to do so. It will also work with\n        userid to improve security.\n\n        \"\"\"\n        user_id = response[\"message\"][\"from\"][\"id\"]\n\n        if (\n            not self.whitelisted_users\n            or user in self.whitelisted_users\n            or user_id in self.whitelisted_users\n        ):\n            return True\n\n        return False\n\n    def build_url(self, method):\n        \"\"\"Build the url to connect to the API.\n\n        Args:\n            method (string): API call end point.\n\n        Return:\n            String that represents the full API url.\n\n        \"\"\"\n        return \"https://api.telegram.org/bot{}/{}\".format(self.token, method)\n\n    async def delete_webhook(self):\n        \"\"\"Delete Telegram webhook.\n\n        The Telegram api will thrown an 409 error when an webhook is\n        active and a call to getUpdates is made. This method will\n        try to request the deletion of the webhook to make the getUpdate\n        request possible.\n\n        \"\"\"\n        _LOGGER.debug(_(\"Sending deleteWebhook request to Telegram...\"))\n        resp = await self.session.get(self.build_url(\"deleteWebhook\"))\n\n        if resp.status == 200:\n            _LOGGER.debug(_(\"Telegram webhook deleted successfully.\"))\n        else:\n            _LOGGER.debug(_(\"Unable to delete webhook.\"))\n\n    async def connect(self):\n        \"\"\"Connect to Telegram.\n\n        This method is not an authorization call. It basically\n        checks if the API token was provided and makes an API\n        call to Telegram and evaluates the status of the call.\n\n        \"\"\"\n\n        _LOGGER.debug(_(\"Connecting to Telegram.\"))\n        self.session = aiohttp.ClientSession()\n\n        resp = await self.session.get(self.build_url(\"getMe\"))\n\n        if resp.status != 200:\n            _LOGGER.error(_(\"Unable to connect.\"))\n            _LOGGER.error(_(\"Telegram error %s, %s.\"), resp.status, resp.text)\n        else:\n            json = await resp.json()\n            _LOGGER.debug(json)\n            _LOGGER.debug(_(\"Connected to Telegram as %s.\"), json[\"result\"][\"username\"])\n\n    async def _parse_message(self, response):\n        \"\"\"Handle logic to parse a received message.\n\n        Since everyone can send a private message to any user/bot\n        in Telegram, this method allows to set a list of whitelisted\n        users that can interact with the bot. If any other user tries\n        to interact with the bot the command is not parsed and instead\n        the bot will inform that user that he is not allowed to talk\n        with the bot.\n\n        We also set self.latest_update to +1 in order to get the next\n        available message (or an empty {} if no message has been received\n        yet) with the method self._get_messages().\n\n        Args:\n            response (dict): Response returned by aiohttp.ClientSession.\n\n        \"\"\"\n        for result in response[\"result\"]:\n            _LOGGER.debug(result)\n\n            if result.get(\"edited_message\", None):\n                result[\"message\"] = result.pop(\"edited_message\")\n            if result.get(\"channel_post\", None) or result.get(\n                \"edited_channel_post\", None\n            ):\n                self.latest_update = result[\"update_id\"] + 1\n                _LOGGER.debug(\n                    _(\"Channel message parsing not supported \" \"- Ignoring message.\")\n                )\n            elif \"message\" in result and \"text\" in result[\"message\"]:\n                user, user_id = self.get_user(result)\n                message = Message(\n                    text=result[\"message\"][\"text\"],\n                    user=user,\n                    user_id=user_id,\n                    target=result[\"message\"][\"chat\"][\"id\"],\n                    connector=self,\n                )\n\n                if self.handle_user_permission(result, user):\n                    await self.opsdroid.parse(message)\n                else:\n                    message.text = (\n                        \"Sorry, you're not allowed \" \"to speak with this bot.\"\n                    )\n                    await self.send(message)\n                self.latest_update = result[\"update_id\"] + 1\n            elif (\n                \"message\" in result\n                and \"sticker\" in result[\"message\"]\n                and \"emoji\" in result[\"message\"][\"sticker\"]\n            ):\n                self.latest_update = result[\"update_id\"] + 1\n                _LOGGER.debug(\n                    _(\"Emoji message parsing not supported - Ignoring message.\")\n                )\n            else:\n                _LOGGER.error(_(\"Unable to parse the message.\"))\n\n    async def _get_messages(self):\n        \"\"\"Connect to the Telegram API.\n\n        Uses an aiohttp ClientSession to connect to Telegram API\n        and get the latest messages from the chat service.\n\n        The data[\"offset\"] is used to consume every new message, the API\n        returns an  int - \"update_id\" value. In order to get the next\n        message this value needs to be increased by 1 the next time\n        the API is called. If no new messages exists the API will just\n        return an empty {}.\n\n        \"\"\"\n        data = {}\n        if self.latest_update is not None:\n            data[\"offset\"] = self.latest_update\n\n        await asyncio.sleep(self.update_interval)\n        resp = await self.session.get(self.build_url(\"getUpdates\"), params=data)\n\n        if resp.status == 409:\n            _LOGGER.info(\n                _(\n                    \"Can't get updates because previous webhook is still active. Will try to delete webhook.\"\n                )\n            )\n            await self.delete_webhook()\n\n        if resp.status != 200:\n            _LOGGER.error(_(\"Telegram error %s, %s.\"), resp.status, resp.text)\n            self.listening = False\n        else:\n            json = await resp.json()\n\n            await self._parse_message(json)\n\n    async def get_messages_loop(self):\n        \"\"\"Listen for and parse new messages.\n\n        The bot will always listen to all opened chat windows,\n        as long as opsdroid is running. Since anyone can start\n        a new chat with the bot is recommended that a list of\n        users to be whitelisted be provided in config.yaml.\n\n        The method will sleep asynchronously at the end of\n        every loop. The time can either be specified in the\n        config.yaml with the param update-interval - this\n        defaults to 1 second.\n\n        \"\"\"\n        while self.listening:\n            await self._get_messages()\n\n    async def listen(self):\n        \"\"\"Listen method of the connector.\n\n        Every connector has to implement the listen method. When an\n        infinite loop is running, it becomes hard to cancel this task.\n        So we are creating a task and set it on a variable so we can\n        cancel the task.\n\n        \"\"\"\n        message_getter = self.loop.create_task(await self.get_messages_loop())\n        await self._closing.wait()\n        message_getter.cancel()\n\n    @register_event(Message)\n    async def send_message(self, message):\n        \"\"\"Respond with a message.\n\n        Args:\n            message (object): An instance of Message.\n\n        \"\"\"\n        _LOGGER.debug(\n            _(\"Responding with: '%s' at target: '%s'\"), message.text, message.target\n        )\n\n        data = dict()\n        data[\"chat_id\"] = message.target\n        data[\"text\"] = message.text\n        resp = await self.session.post(self.build_url(\"sendMessage\"), data=data)\n        if resp.status == 200:\n            _LOGGER.debug(_(\"Successfully responded.\"))\n        else:\n            _LOGGER.error(_(\"Unable to respond.\"))\n\n    @register_event(Image)\n    async def send_image(self, file_event):\n        \"\"\"Send Image to Telegram.\n\n        Gets the chat id from the channel and then\n        sends the bytes of the image as multipart/form-data.\n\n        \"\"\"\n        data = aiohttp.FormData()\n        data.add_field(\n            \"chat_id\", str(file_event.target[\"id\"]), content_type=\"multipart/form-data\"\n        )\n        data.add_field(\n            \"photo\",\n            await file_event.get_file_bytes(),\n            content_type=\"multipart/form-data\",\n        )\n\n        resp = await self.session.post(self.build_url(\"sendPhoto\"), data=data)\n        if resp.status == 200:\n            _LOGGER.debug(_(\"Sent %s image successfully.\"), file_event.name)\n        else:\n            _LOGGER.debug(_(\"Unable to send image - Status Code %s.\"), resp.status)\n\n    async def disconnect(self):\n        \"\"\"Disconnect from Telegram.\n\n        Stops the infinite loop found in self._listen(), closes\n        aiohttp session.\n\n        \"\"\"\n        self.listening = False\n        self._closing.set()\n        await self.session.close()\n", "path": "opsdroid/connector/telegram/__init__.py"}]}