From b1f42c22ae8afc18ef5ad990d0d6d6f6377d79cd Mon Sep 17 00:00:00 2001
From: Fabio Manganiello <blacklight86@gmail.com>
Date: Thu, 11 Jan 2018 19:31:44 +0100
Subject: [PATCH] Added Booking.com endpoints automation

---
 platypush/backend/http/poll/__init__.py       |  1 +
 platypush/backend/http/request/__init__.py    | 10 +++-
 .../backend/http/request/ota/__init__.py      |  0
 .../http/request/ota/booking/__init__.py      | 47 +++++++++++++++++++
 platypush/message/event/http/ota/__init__.py  |  0
 .../event/http/ota/booking/__init__.py        |  9 ++++
 platypush/procedure/__init__.py               |  1 -
 requirements.txt                              | 10 ++--
 setup.py                                      |  1 +
 9 files changed, 74 insertions(+), 5 deletions(-)
 create mode 100644 platypush/backend/http/request/ota/__init__.py
 create mode 100644 platypush/backend/http/request/ota/booking/__init__.py
 create mode 100644 platypush/message/event/http/ota/__init__.py
 create mode 100644 platypush/message/event/http/ota/booking/__init__.py

diff --git a/platypush/backend/http/poll/__init__.py b/platypush/backend/http/poll/__init__.py
index 1b8acc79..934bc14f 100644
--- a/platypush/backend/http/poll/__init__.py
+++ b/platypush/backend/http/poll/__init__.py
@@ -6,6 +6,7 @@ from threading import Thread
 from platypush.bus import Bus
 from platypush.backend import Backend
 from platypush.backend.http.request import HttpRequest
+from platypush.message.request import Request
 
 
 class HttpPollBackend(Backend):
diff --git a/platypush/backend/http/request/__init__.py b/platypush/backend/http/request/__init__.py
index 01e67a54..2b203a22 100644
--- a/platypush/backend/http/request/__init__.py
+++ b/platypush/backend/http/request/__init__.py
@@ -39,6 +39,9 @@ class HttpRequest(object):
         else:
             raise RuntimeError('{} is neither a dictionary nor an HttpRequest')
 
+        if 'timeout' not in self.args.kwargs:
+            self.args.kwargs['timeout'] = self.timeout
+
         self.request_args = {
             'method': self.args.method, 'url': self.args.url, **self.args.kwargs
         }
@@ -53,8 +56,13 @@ class HttpRequest(object):
             response = method(self.args.url, *self.args.args, **self.args.kwargs)
             new_items = self.get_new_items(response)
 
-            if new_items and not is_first_call and self.bus:
+            if isinstance(new_items, HttpEvent):
+                event = new_items
+                new_items = event.args['response']
+            else:
                 event = HttpEvent(dict(self), new_items)
+
+            if new_items and not is_first_call and self.bus:
                 self.bus.post(event)
 
             response.raise_for_status()
diff --git a/platypush/backend/http/request/ota/__init__.py b/platypush/backend/http/request/ota/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/platypush/backend/http/request/ota/booking/__init__.py b/platypush/backend/http/request/ota/booking/__init__.py
new file mode 100644
index 00000000..2fb9c657
--- /dev/null
+++ b/platypush/backend/http/request/ota/booking/__init__.py
@@ -0,0 +1,47 @@
+import datetime
+import dateutil.parser
+import json
+
+from platypush.backend.http.request import JsonHttpRequest
+from platypush.message.event.http.ota.booking import NewReservationEvent
+
+
+class GetReservationUpdates(JsonHttpRequest):
+    def __init__(self, hotel_id, token, *args, **kwargs):
+        self.hotel_id = hotel_id
+        self.token = token
+        self.seen_entries = set()
+        self.last_update = None
+
+        args = {
+            'method': 'get',
+            'url': 'https://hub-api.booking.com/v1/hotels/{}/reservations'.format(self.hotel_id),
+            'headers': { 'X-Booking-Auth-Token': self.token },
+            'params': { 'updatedSince': datetime.date.today().isoformat() }
+        }
+
+        super().__init__(args=args, **kwargs)
+
+
+    def get_new_items(self, response):
+        response = response.json()
+        entries = []
+
+        for entry in response:
+            update_timestamp = dateutil.parser.parse(entry['updateDate'])
+            last_update_timestamp = dateutil.parser.parse(self.last_update['updateDate']) \
+                if self.last_update else None
+
+            if self.last_update is None \
+                    or (update_timestamp > last_update_timestamp
+                        and not (
+                            entry['booker']['email'] == self.last_update['booker']['email']
+                            and entry['status'] == self.last_update['status'])):
+                self.last_update = entry
+                entries.append(entry)
+
+        return NewReservationEvent(dict(self), entries)
+
+
+# vim:sw=4:ts=4:et:
+
diff --git a/platypush/message/event/http/ota/__init__.py b/platypush/message/event/http/ota/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/platypush/message/event/http/ota/booking/__init__.py b/platypush/message/event/http/ota/booking/__init__.py
new file mode 100644
index 00000000..8f9c9679
--- /dev/null
+++ b/platypush/message/event/http/ota/booking/__init__.py
@@ -0,0 +1,9 @@
+from platypush.message.event.http import HttpEvent
+
+class NewReservationEvent(HttpEvent):
+    def __init__(self, request, response, *args, **kwargs):
+        super().__init__(request=request, response=response, *args, **kwargs)
+
+
+# vim:sw=4:ts=4:et:
+
diff --git a/platypush/procedure/__init__.py b/platypush/procedure/__init__.py
index d843550a..0f5b4930 100644
--- a/platypush/procedure/__init__.py
+++ b/platypush/procedure/__init__.py
@@ -131,7 +131,6 @@ class LoopProcedure(Procedure):
 
         for item in iterable:
             context[self.iterator_name] = item
-            # print('**** context[{}]: {}, iterable type: {}'.format(self.iterator_name, item, type(iterable)))
             response = super().execute(n_tries, **context)
 
         return response
diff --git a/requirements.txt b/requirements.txt
index 1f1a4051..1deb4e71 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -31,9 +31,13 @@ google-assistant-sdk[samples]
 google-assistant-library
 
 # Flic buttons support
-git+https://github.com/50ButtonsEach/fliclib-linux-hci
+# It doesn't come with a pip package nor a setup.py,
+# follow the instructions on github to get the flicd daemon
+# running, set up the buttons you want to use, and then
+# enable backend.button.flic in your configuration.
+# git+https://github.com/50ButtonsEach/fliclib-linux-hci
 
-# text2speech plugin: mplayer package
+# text2speech plugin: mplayer system package
 
-# Video support on RaspberryPi: omxplayer package
+# Video support on RaspberryPi: omxplayer system package
 
diff --git a/setup.py b/setup.py
index 408bc6a9..de65dabb 100755
--- a/setup.py
+++ b/setup.py
@@ -73,6 +73,7 @@ setup(
         'Support for OMXPlayer plugin': ['omxplayer'],
         'Support for YouTube in the OMXPlayer plugin': ['youtube-dl'],
         'Support for Google Assistant': ['google-assistant-library'],
+        'Support for most of the HTTP poll backends': ['python-dateutil'],
         # 'Support for Flic buttons': ['git+ssh://git@github.com/50ButtonsEach/fliclib-linux-hci']
     },
 )