From 5c78fedced5e24f4c34ec5c588d4b728b55db441 Mon Sep 17 00:00:00 2001
From: David Trattnig <david.trattnig@o94.at>
Date: Thu, 25 Jun 2020 20:11:29 +0200
Subject: [PATCH] Extended API endpoints.

---
 src/rest/controllers/internal_controller.py |  33 ++-
 src/rest/controllers/public_controller.py   |   2 +-
 src/rest/models/clock_info.py               |  70 +++--
 src/rest/models/play_log_entry.py           | 296 ++------------------
 src/rest/models/schedule.py                 | 227 ---------------
 src/rest/models/timeslot.py                 | 253 +++++++++++++++++
 src/rest/swagger/swagger.yaml               | 187 +++++++------
 src/rest/test/test_internal_controller.py   |  28 +-
 src/rest/test/test_public_controller.py     |   3 +-
 9 files changed, 470 insertions(+), 629 deletions(-)
 delete mode 100644 src/rest/models/schedule.py
 create mode 100644 src/rest/models/timeslot.py

diff --git a/src/rest/controllers/internal_controller.py b/src/rest/controllers/internal_controller.py
index fc837a1..3701d38 100644
--- a/src/rest/controllers/internal_controller.py
+++ b/src/rest/controllers/internal_controller.py
@@ -2,6 +2,7 @@ import connexion
 import six
 
 from src.rest.models.clock_info import ClockInfo  # noqa: E501
+org.joda.time.*  # noqa: E501
 from src.rest.models.health_info import HealthInfo  # noqa: E501
 from src.rest.models.play_log_entry import PlayLogEntry  # noqa: E501
 from src.rest.models.status_entry import StatusEntry  # noqa: E501
@@ -21,7 +22,17 @@ def activate_engine(engine_number):  # noqa: E501
     :rtype: None
     """
     service = current_app.config['SERVICE']
-    return 'do some magic!'
+
+
+def add_playlog():  # noqa: E501
+    """Adds an entry to the playlog
+
+    Stores the passed playlog entry  # noqa: E501
+
+
+    :rtype: PlayLogEntry
+    """
+    service = current_app.config['SERVICE']
 
 
 def clock_info():  # noqa: E501
@@ -76,6 +87,26 @@ def get_report(year_month):  # noqa: E501
     return 'do some magic!'
 
 
+def list_playlog(date_time, page=None, limit=None):  # noqa: E501
+    """List tracks in the play-log since the given timestamp
+
+    Get paginated playlog entries for since the given timestamp.  # noqa: E501
+
+    :param date_time: Get entries after this timestamp (e.g. &#x27;2020-08-29T09:12:33.001Z&#x27;)
+    :type date_time: dict | bytes
+    :param page: The number of items to skip before starting to collect the result set
+    :type page: int
+    :param limit: The numbers of items to return per page
+    :type limit: int
+
+    :rtype: List[PlayLogEntry]
+    """
+    if connexion.request.is_json:
+        date_time = .from_dict(connexion.request.get_json())  # noqa: E501
+    service = current_app.config['SERVICE']
+    return 'do some magic!'
+
+
 def log_engine_health(engine_number):  # noqa: E501
     """Log health info
 
diff --git a/src/rest/controllers/public_controller.py b/src/rest/controllers/public_controller.py
index f9fc50d..27a8b02 100644
--- a/src/rest/controllers/public_controller.py
+++ b/src/rest/controllers/public_controller.py
@@ -6,6 +6,7 @@ from src.rest.models.play_log_entry import PlayLogEntry  # noqa: E501
 from src.rest import util
 
 from flask import current_app
+
 def current_track():  # noqa: E501
     """Get current track
 
@@ -32,4 +33,3 @@ def list_tracks(page=None, limit=None):  # noqa: E501
     """
     service = current_app.config['SERVICE']
     return service.list_tracks(offset, limit)
-    
\ No newline at end of file
diff --git a/src/rest/models/clock_info.py b/src/rest/models/clock_info.py
index 0b2ab8a..88d3c83 100644
--- a/src/rest/models/clock_info.py
+++ b/src/rest/models/clock_info.py
@@ -7,7 +7,7 @@ from typing import List, Dict  # noqa: F401
 
 from src.rest.models.base_model_ import Model
 from src.rest.models.play_log_entry import PlayLogEntry  # noqa: F401,E501
-from src.rest.models.schedule import Schedule  # noqa: F401,E501
+from src.rest.models.timeslot import Timeslot  # noqa: F401,E501
 from src.rest import util
 
 
@@ -16,30 +16,30 @@ class ClockInfo(Model):
 
     Do not edit the class manually.
     """
-    def __init__(self, current_track=None, current_schedule=None, next_schedule=None):  # noqa: E501
+    def __init__(self, current_track=None, current_timeslot=None, next_timeslot=None):  # noqa: E501
         """ClockInfo - a model defined in Swagger
 
         :param current_track: The current_track of this ClockInfo.  # noqa: E501
         :type current_track: PlayLogEntry
-        :param current_schedule: The current_schedule of this ClockInfo.  # noqa: E501
-        :type current_schedule: Schedule
-        :param next_schedule: The next_schedule of this ClockInfo.  # noqa: E501
-        :type next_schedule: Schedule
+        :param current_timeslot: The current_timeslot of this ClockInfo.  # noqa: E501
+        :type current_timeslot: Timeslot
+        :param next_timeslot: The next_timeslot of this ClockInfo.  # noqa: E501
+        :type next_timeslot: Timeslot
         """
         self.swagger_types = {
             'current_track': PlayLogEntry,
-            'current_schedule': Schedule,
-            'next_schedule': Schedule
+            'current_timeslot': Timeslot,
+            'next_timeslot': Timeslot
         }
 
         self.attribute_map = {
             'current_track': 'current_track',
-            'current_schedule': 'current_schedule',
-            'next_schedule': 'next_schedule'
+            'current_timeslot': 'current_timeslot',
+            'next_timeslot': 'next_timeslot'
         }
         self._current_track = current_track
-        self._current_schedule = current_schedule
-        self._next_schedule = next_schedule
+        self._current_timeslot = current_timeslot
+        self._next_timeslot = next_timeslot
 
     @classmethod
     def from_dict(cls, dikt):
@@ -74,45 +74,43 @@ class ClockInfo(Model):
         self._current_track = current_track
 
     @property
-    def current_schedule(self):
-        """Gets the current_schedule of this ClockInfo.
+    def current_timeslot(self):
+        """Gets the current_timeslot of this ClockInfo.
 
 
-        :return: The current_schedule of this ClockInfo.
-        :rtype: Schedule
+        :return: The current_timeslot of this ClockInfo.
+        :rtype: Timeslot
         """
-        return self._current_schedule
+        return self._current_timeslot
 
-    @current_schedule.setter
-    def current_schedule(self, current_schedule):
-        """Sets the current_schedule of this ClockInfo.
+    @current_timeslot.setter
+    def current_timeslot(self, current_timeslot):
+        """Sets the current_timeslot of this ClockInfo.
 
 
-        :param current_schedule: The current_schedule of this ClockInfo.
-        :type current_schedule: Schedule
+        :param current_timeslot: The current_timeslot of this ClockInfo.
+        :type current_timeslot: Timeslot
         """
-        if current_schedule is None:
-            raise ValueError("Invalid value for `current_schedule`, must not be `None`")  # noqa: E501
 
-        self._current_schedule = current_schedule
+        self._current_timeslot = current_timeslot
 
     @property
-    def next_schedule(self):
-        """Gets the next_schedule of this ClockInfo.
+    def next_timeslot(self):
+        """Gets the next_timeslot of this ClockInfo.
 
 
-        :return: The next_schedule of this ClockInfo.
-        :rtype: Schedule
+        :return: The next_timeslot of this ClockInfo.
+        :rtype: Timeslot
         """
-        return self._next_schedule
+        return self._next_timeslot
 
-    @next_schedule.setter
-    def next_schedule(self, next_schedule):
-        """Sets the next_schedule of this ClockInfo.
+    @next_timeslot.setter
+    def next_timeslot(self, next_timeslot):
+        """Sets the next_timeslot of this ClockInfo.
 
 
-        :param next_schedule: The next_schedule of this ClockInfo.
-        :type next_schedule: Schedule
+        :param next_timeslot: The next_timeslot of this ClockInfo.
+        :type next_timeslot: Timeslot
         """
 
-        self._next_schedule = next_schedule
+        self._next_timeslot = next_timeslot
diff --git a/src/rest/models/play_log_entry.py b/src/rest/models/play_log_entry.py
index ef1986b..79d0e7e 100644
--- a/src/rest/models/play_log_entry.py
+++ b/src/rest/models/play_log_entry.py
@@ -14,7 +14,7 @@ class PlayLogEntry(Model):
 
     Do not edit the class manually.
     """
-    def __init__(self, track_start=None, track_artist=None, track_album=None, track_title=None, track_duration=None, track_type=None, schedule_id=None, schedule_start=None, schedule_end=None, schedule_repetition=None, schedule_playlist_id=None, schedule_fallback_type=None, show_id=None, show_name=None, show_funding_category=None, show_type=None, show_category=None, show_topic=None):  # noqa: E501
+    def __init__(self, track_start=None, track_artist=None, track_album=None, track_title=None, track_duration=None, track_type=None, timeslot_id=None, show_name=None):  # noqa: E501
         """PlayLogEntry - a model defined in Swagger
 
         :param track_start: The track_start of this PlayLogEntry.  # noqa: E501
@@ -29,30 +29,10 @@ class PlayLogEntry(Model):
         :type track_duration: int
         :param track_type: The track_type of this PlayLogEntry.  # noqa: E501
         :type track_type: int
-        :param schedule_id: The schedule_id of this PlayLogEntry.  # noqa: E501
-        :type schedule_id: int
-        :param schedule_start: The schedule_start of this PlayLogEntry.  # noqa: E501
-        :type schedule_start: datetime
-        :param schedule_end: The schedule_end of this PlayLogEntry.  # noqa: E501
-        :type schedule_end: datetime
-        :param schedule_repetition: The schedule_repetition of this PlayLogEntry.  # noqa: E501
-        :type schedule_repetition: bool
-        :param schedule_playlist_id: The schedule_playlist_id of this PlayLogEntry.  # noqa: E501
-        :type schedule_playlist_id: int
-        :param schedule_fallback_type: The schedule_fallback_type of this PlayLogEntry.  # noqa: E501
-        :type schedule_fallback_type: int
-        :param show_id: The show_id of this PlayLogEntry.  # noqa: E501
-        :type show_id: int
+        :param timeslot_id: The timeslot_id of this PlayLogEntry.  # noqa: E501
+        :type timeslot_id: int
         :param show_name: The show_name of this PlayLogEntry.  # noqa: E501
         :type show_name: str
-        :param show_funding_category: The show_funding_category of this PlayLogEntry.  # noqa: E501
-        :type show_funding_category: str
-        :param show_type: The show_type of this PlayLogEntry.  # noqa: E501
-        :type show_type: str
-        :param show_category: The show_category of this PlayLogEntry.  # noqa: E501
-        :type show_category: str
-        :param show_topic: The show_topic of this PlayLogEntry.  # noqa: E501
-        :type show_topic: str
         """
         self.swagger_types = {
             'track_start': datetime,
@@ -61,18 +41,8 @@ class PlayLogEntry(Model):
             'track_title': str,
             'track_duration': int,
             'track_type': int,
-            'schedule_id': int,
-            'schedule_start': datetime,
-            'schedule_end': datetime,
-            'schedule_repetition': bool,
-            'schedule_playlist_id': int,
-            'schedule_fallback_type': int,
-            'show_id': int,
-            'show_name': str,
-            'show_funding_category': str,
-            'show_type': str,
-            'show_category': str,
-            'show_topic': str
+            'timeslot_id': int,
+            'show_name': str
         }
 
         self.attribute_map = {
@@ -82,18 +52,8 @@ class PlayLogEntry(Model):
             'track_title': 'track_title',
             'track_duration': 'track_duration',
             'track_type': 'track_type',
-            'schedule_id': 'schedule_id',
-            'schedule_start': 'schedule_start',
-            'schedule_end': 'schedule_end',
-            'schedule_repetition': 'schedule_repetition',
-            'schedule_playlist_id': 'schedule_playlist_id',
-            'schedule_fallback_type': 'schedule_fallback_type',
-            'show_id': 'show_id',
-            'show_name': 'show_name',
-            'show_funding_category': 'show_funding_category',
-            'show_type': 'show_type',
-            'show_category': 'show_category',
-            'show_topic': 'show_topic'
+            'timeslot_id': 'timeslot_id',
+            'show_name': 'show_name'
         }
         self._track_start = track_start
         self._track_artist = track_artist
@@ -101,18 +61,8 @@ class PlayLogEntry(Model):
         self._track_title = track_title
         self._track_duration = track_duration
         self._track_type = track_type
-        self._schedule_id = schedule_id
-        self._schedule_start = schedule_start
-        self._schedule_end = schedule_end
-        self._schedule_repetition = schedule_repetition
-        self._schedule_playlist_id = schedule_playlist_id
-        self._schedule_fallback_type = schedule_fallback_type
-        self._show_id = show_id
+        self._timeslot_id = timeslot_id
         self._show_name = show_name
-        self._show_funding_category = show_funding_category
-        self._show_type = show_type
-        self._show_category = show_category
-        self._show_topic = show_topic
 
     @classmethod
     def from_dict(cls, dikt):
@@ -254,151 +204,25 @@ class PlayLogEntry(Model):
         self._track_type = track_type
 
     @property
-    def schedule_id(self):
-        """Gets the schedule_id of this PlayLogEntry.
+    def timeslot_id(self):
+        """Gets the timeslot_id of this PlayLogEntry.
 
 
-        :return: The schedule_id of this PlayLogEntry.
+        :return: The timeslot_id of this PlayLogEntry.
         :rtype: int
         """
-        return self._schedule_id
+        return self._timeslot_id
 
-    @schedule_id.setter
-    def schedule_id(self, schedule_id):
-        """Sets the schedule_id of this PlayLogEntry.
+    @timeslot_id.setter
+    def timeslot_id(self, timeslot_id):
+        """Sets the timeslot_id of this PlayLogEntry.
 
 
-        :param schedule_id: The schedule_id of this PlayLogEntry.
-        :type schedule_id: int
+        :param timeslot_id: The timeslot_id of this PlayLogEntry.
+        :type timeslot_id: int
         """
 
-        self._schedule_id = schedule_id
-
-    @property
-    def schedule_start(self):
-        """Gets the schedule_start of this PlayLogEntry.
-
-
-        :return: The schedule_start of this PlayLogEntry.
-        :rtype: datetime
-        """
-        return self._schedule_start
-
-    @schedule_start.setter
-    def schedule_start(self, schedule_start):
-        """Sets the schedule_start of this PlayLogEntry.
-
-
-        :param schedule_start: The schedule_start of this PlayLogEntry.
-        :type schedule_start: datetime
-        """
-
-        self._schedule_start = schedule_start
-
-    @property
-    def schedule_end(self):
-        """Gets the schedule_end of this PlayLogEntry.
-
-
-        :return: The schedule_end of this PlayLogEntry.
-        :rtype: datetime
-        """
-        return self._schedule_end
-
-    @schedule_end.setter
-    def schedule_end(self, schedule_end):
-        """Sets the schedule_end of this PlayLogEntry.
-
-
-        :param schedule_end: The schedule_end of this PlayLogEntry.
-        :type schedule_end: datetime
-        """
-
-        self._schedule_end = schedule_end
-
-    @property
-    def schedule_repetition(self):
-        """Gets the schedule_repetition of this PlayLogEntry.
-
-
-        :return: The schedule_repetition of this PlayLogEntry.
-        :rtype: bool
-        """
-        return self._schedule_repetition
-
-    @schedule_repetition.setter
-    def schedule_repetition(self, schedule_repetition):
-        """Sets the schedule_repetition of this PlayLogEntry.
-
-
-        :param schedule_repetition: The schedule_repetition of this PlayLogEntry.
-        :type schedule_repetition: bool
-        """
-
-        self._schedule_repetition = schedule_repetition
-
-    @property
-    def schedule_playlist_id(self):
-        """Gets the schedule_playlist_id of this PlayLogEntry.
-
-
-        :return: The schedule_playlist_id of this PlayLogEntry.
-        :rtype: int
-        """
-        return self._schedule_playlist_id
-
-    @schedule_playlist_id.setter
-    def schedule_playlist_id(self, schedule_playlist_id):
-        """Sets the schedule_playlist_id of this PlayLogEntry.
-
-
-        :param schedule_playlist_id: The schedule_playlist_id of this PlayLogEntry.
-        :type schedule_playlist_id: int
-        """
-
-        self._schedule_playlist_id = schedule_playlist_id
-
-    @property
-    def schedule_fallback_type(self):
-        """Gets the schedule_fallback_type of this PlayLogEntry.
-
-
-        :return: The schedule_fallback_type of this PlayLogEntry.
-        :rtype: int
-        """
-        return self._schedule_fallback_type
-
-    @schedule_fallback_type.setter
-    def schedule_fallback_type(self, schedule_fallback_type):
-        """Sets the schedule_fallback_type of this PlayLogEntry.
-
-
-        :param schedule_fallback_type: The schedule_fallback_type of this PlayLogEntry.
-        :type schedule_fallback_type: int
-        """
-
-        self._schedule_fallback_type = schedule_fallback_type
-
-    @property
-    def show_id(self):
-        """Gets the show_id of this PlayLogEntry.
-
-
-        :return: The show_id of this PlayLogEntry.
-        :rtype: int
-        """
-        return self._show_id
-
-    @show_id.setter
-    def show_id(self, show_id):
-        """Sets the show_id of this PlayLogEntry.
-
-
-        :param show_id: The show_id of this PlayLogEntry.
-        :type show_id: int
-        """
-
-        self._show_id = show_id
+        self._timeslot_id = timeslot_id
 
     @property
     def show_name(self):
@@ -420,87 +244,3 @@ class PlayLogEntry(Model):
         """
 
         self._show_name = show_name
-
-    @property
-    def show_funding_category(self):
-        """Gets the show_funding_category of this PlayLogEntry.
-
-
-        :return: The show_funding_category of this PlayLogEntry.
-        :rtype: str
-        """
-        return self._show_funding_category
-
-    @show_funding_category.setter
-    def show_funding_category(self, show_funding_category):
-        """Sets the show_funding_category of this PlayLogEntry.
-
-
-        :param show_funding_category: The show_funding_category of this PlayLogEntry.
-        :type show_funding_category: str
-        """
-
-        self._show_funding_category = show_funding_category
-
-    @property
-    def show_type(self):
-        """Gets the show_type of this PlayLogEntry.
-
-
-        :return: The show_type of this PlayLogEntry.
-        :rtype: str
-        """
-        return self._show_type
-
-    @show_type.setter
-    def show_type(self, show_type):
-        """Sets the show_type of this PlayLogEntry.
-
-
-        :param show_type: The show_type of this PlayLogEntry.
-        :type show_type: str
-        """
-
-        self._show_type = show_type
-
-    @property
-    def show_category(self):
-        """Gets the show_category of this PlayLogEntry.
-
-
-        :return: The show_category of this PlayLogEntry.
-        :rtype: str
-        """
-        return self._show_category
-
-    @show_category.setter
-    def show_category(self, show_category):
-        """Sets the show_category of this PlayLogEntry.
-
-
-        :param show_category: The show_category of this PlayLogEntry.
-        :type show_category: str
-        """
-
-        self._show_category = show_category
-
-    @property
-    def show_topic(self):
-        """Gets the show_topic of this PlayLogEntry.
-
-
-        :return: The show_topic of this PlayLogEntry.
-        :rtype: str
-        """
-        return self._show_topic
-
-    @show_topic.setter
-    def show_topic(self, show_topic):
-        """Sets the show_topic of this PlayLogEntry.
-
-
-        :param show_topic: The show_topic of this PlayLogEntry.
-        :type show_topic: str
-        """
-
-        self._show_topic = show_topic
diff --git a/src/rest/models/schedule.py b/src/rest/models/schedule.py
deleted file mode 100644
index c5eaab3..0000000
--- a/src/rest/models/schedule.py
+++ /dev/null
@@ -1,227 +0,0 @@
-# coding: utf-8
-
-from __future__ import absolute_import
-from datetime import date, datetime  # noqa: F401
-
-from typing import List, Dict  # noqa: F401
-
-from src.rest.models.base_model_ import Model
-from src.rest.models.playlist_entry import PlaylistEntry  # noqa: F401,E501
-from src.rest import util
-
-
-class Schedule(Model):
-    """NOTE: This class is auto generated by the swagger code generator program.
-
-    Do not edit the class manually.
-    """
-    def __init__(self, show_name=None, schedule_id=None, schedule_start=None, schedule_end=None, playlist_id=None, fallback_type=None, playlist_entries=None):  # noqa: E501
-        """Schedule - a model defined in Swagger
-
-        :param show_name: The show_name of this Schedule.  # noqa: E501
-        :type show_name: str
-        :param schedule_id: The schedule_id of this Schedule.  # noqa: E501
-        :type schedule_id: int
-        :param schedule_start: The schedule_start of this Schedule.  # noqa: E501
-        :type schedule_start: datetime
-        :param schedule_end: The schedule_end of this Schedule.  # noqa: E501
-        :type schedule_end: datetime
-        :param playlist_id: The playlist_id of this Schedule.  # noqa: E501
-        :type playlist_id: int
-        :param fallback_type: The fallback_type of this Schedule.  # noqa: E501
-        :type fallback_type: int
-        :param playlist_entries: The playlist_entries of this Schedule.  # noqa: E501
-        :type playlist_entries: List[PlaylistEntry]
-        """
-        self.swagger_types = {
-            'show_name': str,
-            'schedule_id': int,
-            'schedule_start': datetime,
-            'schedule_end': datetime,
-            'playlist_id': int,
-            'fallback_type': int,
-            'playlist_entries': List[PlaylistEntry]
-        }
-
-        self.attribute_map = {
-            'show_name': 'show_name',
-            'schedule_id': 'schedule_id',
-            'schedule_start': 'schedule_start',
-            'schedule_end': 'schedule_end',
-            'playlist_id': 'playlist_id',
-            'fallback_type': 'fallback_type',
-            'playlist_entries': 'playlist_entries'
-        }
-        self._show_name = show_name
-        self._schedule_id = schedule_id
-        self._schedule_start = schedule_start
-        self._schedule_end = schedule_end
-        self._playlist_id = playlist_id
-        self._fallback_type = fallback_type
-        self._playlist_entries = playlist_entries
-
-    @classmethod
-    def from_dict(cls, dikt):
-        """Returns the dict as a model
-
-        :param dikt: A dict.
-        :type: dict
-        :return: The Schedule of this Schedule.  # noqa: E501
-        :rtype: Schedule
-        """
-        return util.deserialize_model(dikt, cls)
-
-    @property
-    def show_name(self):
-        """Gets the show_name of this Schedule.
-
-
-        :return: The show_name of this Schedule.
-        :rtype: str
-        """
-        return self._show_name
-
-    @show_name.setter
-    def show_name(self, show_name):
-        """Sets the show_name of this Schedule.
-
-
-        :param show_name: The show_name of this Schedule.
-        :type show_name: str
-        """
-        if show_name is None:
-            raise ValueError("Invalid value for `show_name`, must not be `None`")  # noqa: E501
-
-        self._show_name = show_name
-
-    @property
-    def schedule_id(self):
-        """Gets the schedule_id of this Schedule.
-
-
-        :return: The schedule_id of this Schedule.
-        :rtype: int
-        """
-        return self._schedule_id
-
-    @schedule_id.setter
-    def schedule_id(self, schedule_id):
-        """Sets the schedule_id of this Schedule.
-
-
-        :param schedule_id: The schedule_id of this Schedule.
-        :type schedule_id: int
-        """
-
-        self._schedule_id = schedule_id
-
-    @property
-    def schedule_start(self):
-        """Gets the schedule_start of this Schedule.
-
-
-        :return: The schedule_start of this Schedule.
-        :rtype: datetime
-        """
-        return self._schedule_start
-
-    @schedule_start.setter
-    def schedule_start(self, schedule_start):
-        """Sets the schedule_start of this Schedule.
-
-
-        :param schedule_start: The schedule_start of this Schedule.
-        :type schedule_start: datetime
-        """
-        if schedule_start is None:
-            raise ValueError("Invalid value for `schedule_start`, must not be `None`")  # noqa: E501
-
-        self._schedule_start = schedule_start
-
-    @property
-    def schedule_end(self):
-        """Gets the schedule_end of this Schedule.
-
-
-        :return: The schedule_end of this Schedule.
-        :rtype: datetime
-        """
-        return self._schedule_end
-
-    @schedule_end.setter
-    def schedule_end(self, schedule_end):
-        """Sets the schedule_end of this Schedule.
-
-
-        :param schedule_end: The schedule_end of this Schedule.
-        :type schedule_end: datetime
-        """
-        if schedule_end is None:
-            raise ValueError("Invalid value for `schedule_end`, must not be `None`")  # noqa: E501
-
-        self._schedule_end = schedule_end
-
-    @property
-    def playlist_id(self):
-        """Gets the playlist_id of this Schedule.
-
-
-        :return: The playlist_id of this Schedule.
-        :rtype: int
-        """
-        return self._playlist_id
-
-    @playlist_id.setter
-    def playlist_id(self, playlist_id):
-        """Sets the playlist_id of this Schedule.
-
-
-        :param playlist_id: The playlist_id of this Schedule.
-        :type playlist_id: int
-        """
-
-        self._playlist_id = playlist_id
-
-    @property
-    def fallback_type(self):
-        """Gets the fallback_type of this Schedule.
-
-
-        :return: The fallback_type of this Schedule.
-        :rtype: int
-        """
-        return self._fallback_type
-
-    @fallback_type.setter
-    def fallback_type(self, fallback_type):
-        """Sets the fallback_type of this Schedule.
-
-
-        :param fallback_type: The fallback_type of this Schedule.
-        :type fallback_type: int
-        """
-
-        self._fallback_type = fallback_type
-
-    @property
-    def playlist_entries(self):
-        """Gets the playlist_entries of this Schedule.
-
-
-        :return: The playlist_entries of this Schedule.
-        :rtype: List[PlaylistEntry]
-        """
-        return self._playlist_entries
-
-    @playlist_entries.setter
-    def playlist_entries(self, playlist_entries):
-        """Sets the playlist_entries of this Schedule.
-
-
-        :param playlist_entries: The playlist_entries of this Schedule.
-        :type playlist_entries: List[PlaylistEntry]
-        """
-        if playlist_entries is None:
-            raise ValueError("Invalid value for `playlist_entries`, must not be `None`")  # noqa: E501
-
-        self._playlist_entries = playlist_entries
diff --git a/src/rest/models/timeslot.py b/src/rest/models/timeslot.py
new file mode 100644
index 0000000..4de2596
--- /dev/null
+++ b/src/rest/models/timeslot.py
@@ -0,0 +1,253 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+from datetime import date, datetime  # noqa: F401
+
+from typing import List, Dict  # noqa: F401
+
+from src.rest.models.base_model_ import Model
+from src.rest.models.playlist_entry import PlaylistEntry  # noqa: F401,E501
+from src.rest import util
+
+
+class Timeslot(Model):
+    """NOTE: This class is auto generated by the swagger code generator program.
+
+    Do not edit the class manually.
+    """
+    def __init__(self, show_name=None, schedule_id=None, timeslot_id=None, timeslot_start=None, timeslot_end=None, playlist_id=None, fallback_type=None, playlist_entries=None):  # noqa: E501
+        """Timeslot - a model defined in Swagger
+
+        :param show_name: The show_name of this Timeslot.  # noqa: E501
+        :type show_name: str
+        :param schedule_id: The schedule_id of this Timeslot.  # noqa: E501
+        :type schedule_id: int
+        :param timeslot_id: The timeslot_id of this Timeslot.  # noqa: E501
+        :type timeslot_id: int
+        :param timeslot_start: The timeslot_start of this Timeslot.  # noqa: E501
+        :type timeslot_start: datetime
+        :param timeslot_end: The timeslot_end of this Timeslot.  # noqa: E501
+        :type timeslot_end: datetime
+        :param playlist_id: The playlist_id of this Timeslot.  # noqa: E501
+        :type playlist_id: int
+        :param fallback_type: The fallback_type of this Timeslot.  # noqa: E501
+        :type fallback_type: int
+        :param playlist_entries: The playlist_entries of this Timeslot.  # noqa: E501
+        :type playlist_entries: List[PlaylistEntry]
+        """
+        self.swagger_types = {
+            'show_name': str,
+            'schedule_id': int,
+            'timeslot_id': int,
+            'timeslot_start': datetime,
+            'timeslot_end': datetime,
+            'playlist_id': int,
+            'fallback_type': int,
+            'playlist_entries': List[PlaylistEntry]
+        }
+
+        self.attribute_map = {
+            'show_name': 'show_name',
+            'schedule_id': 'schedule_id',
+            'timeslot_id': 'timeslot_id',
+            'timeslot_start': 'timeslot_start',
+            'timeslot_end': 'timeslot_end',
+            'playlist_id': 'playlist_id',
+            'fallback_type': 'fallback_type',
+            'playlist_entries': 'playlist_entries'
+        }
+        self._show_name = show_name
+        self._schedule_id = schedule_id
+        self._timeslot_id = timeslot_id
+        self._timeslot_start = timeslot_start
+        self._timeslot_end = timeslot_end
+        self._playlist_id = playlist_id
+        self._fallback_type = fallback_type
+        self._playlist_entries = playlist_entries
+
+    @classmethod
+    def from_dict(cls, dikt):
+        """Returns the dict as a model
+
+        :param dikt: A dict.
+        :type: dict
+        :return: The Timeslot of this Timeslot.  # noqa: E501
+        :rtype: Timeslot
+        """
+        return util.deserialize_model(dikt, cls)
+
+    @property
+    def show_name(self):
+        """Gets the show_name of this Timeslot.
+
+
+        :return: The show_name of this Timeslot.
+        :rtype: str
+        """
+        return self._show_name
+
+    @show_name.setter
+    def show_name(self, show_name):
+        """Sets the show_name of this Timeslot.
+
+
+        :param show_name: The show_name of this Timeslot.
+        :type show_name: str
+        """
+        if show_name is None:
+            raise ValueError("Invalid value for `show_name`, must not be `None`")  # noqa: E501
+
+        self._show_name = show_name
+
+    @property
+    def schedule_id(self):
+        """Gets the schedule_id of this Timeslot.
+
+
+        :return: The schedule_id of this Timeslot.
+        :rtype: int
+        """
+        return self._schedule_id
+
+    @schedule_id.setter
+    def schedule_id(self, schedule_id):
+        """Sets the schedule_id of this Timeslot.
+
+
+        :param schedule_id: The schedule_id of this Timeslot.
+        :type schedule_id: int
+        """
+
+        self._schedule_id = schedule_id
+
+    @property
+    def timeslot_id(self):
+        """Gets the timeslot_id of this Timeslot.
+
+
+        :return: The timeslot_id of this Timeslot.
+        :rtype: int
+        """
+        return self._timeslot_id
+
+    @timeslot_id.setter
+    def timeslot_id(self, timeslot_id):
+        """Sets the timeslot_id of this Timeslot.
+
+
+        :param timeslot_id: The timeslot_id of this Timeslot.
+        :type timeslot_id: int
+        """
+
+        self._timeslot_id = timeslot_id
+
+    @property
+    def timeslot_start(self):
+        """Gets the timeslot_start of this Timeslot.
+
+
+        :return: The timeslot_start of this Timeslot.
+        :rtype: datetime
+        """
+        return self._timeslot_start
+
+    @timeslot_start.setter
+    def timeslot_start(self, timeslot_start):
+        """Sets the timeslot_start of this Timeslot.
+
+
+        :param timeslot_start: The timeslot_start of this Timeslot.
+        :type timeslot_start: datetime
+        """
+        if timeslot_start is None:
+            raise ValueError("Invalid value for `timeslot_start`, must not be `None`")  # noqa: E501
+
+        self._timeslot_start = timeslot_start
+
+    @property
+    def timeslot_end(self):
+        """Gets the timeslot_end of this Timeslot.
+
+
+        :return: The timeslot_end of this Timeslot.
+        :rtype: datetime
+        """
+        return self._timeslot_end
+
+    @timeslot_end.setter
+    def timeslot_end(self, timeslot_end):
+        """Sets the timeslot_end of this Timeslot.
+
+
+        :param timeslot_end: The timeslot_end of this Timeslot.
+        :type timeslot_end: datetime
+        """
+        if timeslot_end is None:
+            raise ValueError("Invalid value for `timeslot_end`, must not be `None`")  # noqa: E501
+
+        self._timeslot_end = timeslot_end
+
+    @property
+    def playlist_id(self):
+        """Gets the playlist_id of this Timeslot.
+
+
+        :return: The playlist_id of this Timeslot.
+        :rtype: int
+        """
+        return self._playlist_id
+
+    @playlist_id.setter
+    def playlist_id(self, playlist_id):
+        """Sets the playlist_id of this Timeslot.
+
+
+        :param playlist_id: The playlist_id of this Timeslot.
+        :type playlist_id: int
+        """
+
+        self._playlist_id = playlist_id
+
+    @property
+    def fallback_type(self):
+        """Gets the fallback_type of this Timeslot.
+
+
+        :return: The fallback_type of this Timeslot.
+        :rtype: int
+        """
+        return self._fallback_type
+
+    @fallback_type.setter
+    def fallback_type(self, fallback_type):
+        """Sets the fallback_type of this Timeslot.
+
+
+        :param fallback_type: The fallback_type of this Timeslot.
+        :type fallback_type: int
+        """
+
+        self._fallback_type = fallback_type
+
+    @property
+    def playlist_entries(self):
+        """Gets the playlist_entries of this Timeslot.
+
+
+        :return: The playlist_entries of this Timeslot.
+        :rtype: List[PlaylistEntry]
+        """
+        return self._playlist_entries
+
+    @playlist_entries.setter
+    def playlist_entries(self, playlist_entries):
+        """Sets the playlist_entries of this Timeslot.
+
+
+        :param playlist_entries: The playlist_entries of this Timeslot.
+        :type playlist_entries: List[PlaylistEntry]
+        """
+        if playlist_entries is None:
+            raise ValueError("Invalid value for `playlist_entries`, must not be `None`")  # noqa: E501
+
+        self._playlist_entries = playlist_entries
diff --git a/src/rest/swagger/swagger.yaml b/src/rest/swagger/swagger.yaml
index 467ce79..3095fce 100644
--- a/src/rest/swagger/swagger.yaml
+++ b/src/rest/swagger/swagger.yaml
@@ -113,7 +113,75 @@ paths:
         "400":
           description: bad input parameter
       x-openapi-router-controller: src.rest.controllers.internal_controller
-  /report/{year_month}:
+  /playlog/add:
+    post:
+      tags:
+      - internal
+      summary: Adds an entry to the playlog
+      description: |
+        Stores the passed playlog entry
+      operationId: add_playlog
+      responses:
+        "200":
+          description: Stored playlog
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/PlayLogEntry'
+        "400":
+          description: bad input parameter
+      x-openapi-router-controller: src.rest.controllers.internal_controller
+  /playlog/since/{date_time}:
+    get:
+      tags:
+      - internal
+      summary: List tracks in the play-log since the given timestamp
+      description: |
+        Get paginated playlog entries for since the given timestamp.
+      operationId: list_playlog
+      parameters:
+      - name: date_time
+        in: path
+        description: Get entries after this timestamp (e.g. '2020-08-29T09:12:33.001Z')
+        required: true
+        style: simple
+        explode: false
+        schema:
+          type: date-time
+      - name: page
+        in: query
+        description: The number of items to skip before starting to collect the result
+          set
+        required: false
+        style: form
+        explode: true
+        schema:
+          type: integer
+      - name: limit
+        in: query
+        description: The numbers of items to return per page
+        required: false
+        style: form
+        explode: true
+        schema:
+          maximum: 200
+          minimum: 1
+          type: integer
+          default: 50
+      responses:
+        "200":
+          description: search results matching criteria
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/PlayLogEntry'
+                x-content-type: application/json
+        "400":
+          description: bad input parameter
+      x-openapi-router-controller: src.rest.controllers.internal_controller
+  /playlog/report/{year_month}:
     get:
       tags:
       - internal
@@ -261,67 +329,25 @@ components:
           example: Chomp Samba
         track_duration:
           type: integer
-          example: 234
+          example: 303
         track_type:
           type: integer
           example: 2
-        schedule_id:
-          type: integer
-          example: 1
-        schedule_start:
-          type: string
-          format: date-time
-          example: 2020-08-29T09:12:33.001Z
-        schedule_end:
-          type: string
-          format: date-time
-          example: 2020-08-29T09:12:33.001Z
-        schedule_repetition:
-          type: boolean
-          example: false
-        schedule_playlist_id:
-          type: integer
-          example: 1
-        schedule_fallback_type:
-          type: integer
-          example: 0
-        show_id:
+        timeslot_id:
           type: integer
           example: 1
         show_name:
           type: string
-          example: Special Music Show
-        show_funding_category:
-          type: string
-          example: Standard
-        show_type:
-          type: string
-          example: Feature
-        show_category:
-          type: string
-          example: Progressive
-        show_topic:
-          type: string
-          example: Music
+          example: Electronic Music from Brazil
       example:
         track_album: Bricolage
-        show_funding_category: Standard
-        show_id: 1
-        schedule_fallback_type: 0
+        track_start: 2020-08-29T09:12:33.001Z
         track_title: Chomp Samba
-        show_name: Special Music Show
+        show_name: Electronic Music from Brazil
         track_artist: Amon Tobin
-        show_topic: Music
+        timeslot_id: 1
+        track_duration: 303
         track_type: 2
-        schedule_playlist_id: 1
-        show_type: Feature
-        track_start: 2020-08-29T09:12:33.001Z
-        schedule_repetition: false
-        schedule_end: 2020-08-29T09:12:33.001Z
-        track_duration: 234
-        show_category: Progressive
-        schedule_id: 1
-        schedule_start: 2020-08-29T09:12:33.001Z
     StatusEntry:
       required:
       - engine_host
@@ -377,35 +403,16 @@ components:
       properties:
         current_track:
           $ref: '#/components/schemas/PlayLogEntry'
-        current_schedule:
-          $ref: '#/components/schemas/Schedule'
-        next_schedule:
-          $ref: '#/components/schemas/Schedule'
+        current_timeslot:
+          $ref: '#/components/schemas/Timeslot'
+        next_timeslot:
+          $ref: '#/components/schemas/Timeslot'
       example:
-        current_track:
-          track_album: Bricolage
-          show_funding_category: Standard
-          show_id: 1
-          schedule_fallback_type: 0
-          track_title: Chomp Samba
-          show_name: Special Music Show
-          track_artist: Amon Tobin
-          show_topic: Music
-          track_type: 2
-          schedule_playlist_id: 1
-          show_type: Feature
-          track_start: 2020-08-29T09:12:33.001Z
-          schedule_repetition: false
-          schedule_end: 2020-08-29T09:12:33.001Z
-          track_duration: 234
-          show_category: Progressive
-          schedule_id: 1
-          schedule_start: 2020-08-29T09:12:33.001Z
-        current_schedule:
+        current_timeslot:
+          timeslot_end: 2020-08-29T09:12:33.001Z
           playlist_id: 38
           show_name: Future Pop
           fallback_type: 0
-          schedule_end: 2020-08-29T09:12:33.001Z
           playlist_entries:
           - duration: 363
             artist: xxyyxx
@@ -417,14 +424,24 @@ components:
             album: XXYYXX
             title: Alone
             type: 1
+          timeslot_start: 2020-08-29T09:12:33.001Z
+          timeslot_id: 42
           schedule_id: 23
-          schedule_start: 2020-08-29T09:12:33.001Z
-    Schedule:
+        current_track:
+          track_album: Bricolage
+          track_start: 2020-08-29T09:12:33.001Z
+          track_title: Chomp Samba
+          show_name: Electronic Music from Brazil
+          track_artist: Amon Tobin
+          timeslot_id: 1
+          track_duration: 303
+          track_type: 2
+    Timeslot:
       required:
       - playlist_entries
-      - schedule_end
-      - schedule_start
       - show_name
+      - timeslot_end
+      - timeslot_start
       type: object
       properties:
         show_name:
@@ -433,11 +450,14 @@ components:
         schedule_id:
           type: integer
           example: 23
-        schedule_start:
+        timeslot_id:
+          type: integer
+          example: 42
+        timeslot_start:
           type: string
           format: date-time
           example: 2020-08-29T09:12:33.001Z
-        schedule_end:
+        timeslot_end:
           type: string
           format: date-time
           example: 2020-08-29T09:12:33.001Z
@@ -452,10 +472,10 @@ components:
           items:
             $ref: '#/components/schemas/PlaylistEntry'
       example:
+        timeslot_end: 2020-08-29T09:12:33.001Z
         playlist_id: 38
         show_name: Future Pop
         fallback_type: 0
-        schedule_end: 2020-08-29T09:12:33.001Z
         playlist_entries:
         - duration: 363
           artist: xxyyxx
@@ -467,8 +487,9 @@ components:
           album: XXYYXX
           title: Alone
           type: 1
+        timeslot_start: 2020-08-29T09:12:33.001Z
+        timeslot_id: 42
         schedule_id: 23
-        schedule_start: 2020-08-29T09:12:33.001Z
     PlaylistEntry:
       required:
       - title
diff --git a/src/rest/test/test_internal_controller.py b/src/rest/test/test_internal_controller.py
index 2d7c2e5..b90612d 100644
--- a/src/rest/test/test_internal_controller.py
+++ b/src/rest/test/test_internal_controller.py
@@ -23,6 +23,7 @@ from flask import json
 from six import BytesIO
 
 from src.rest.models.clock_info import ClockInfo  # noqa: E501
+org.joda.time.*  # noqa: E501
 from src.rest.models.health_info import HealthInfo  # noqa: E501
 from src.rest.models.play_log_entry import PlayLogEntry  # noqa: E501
 from src.rest.models.status_entry import StatusEntry  # noqa: E501
@@ -43,6 +44,17 @@ class TestInternalController(BaseTestCase):
         self.assert200(response,
                        'Response body is : ' + response.data.decode('utf-8'))
 
+    def test_add_playlog(self):
+        """Test case for add_playlog
+
+        Adds an entry to the playlog
+        """
+        response = self.client.open(
+            '/api/v1/playlog/add',
+            method='POST')
+        self.assert200(response,
+                       'Response body is : ' + response.data.decode('utf-8'))
+
     def test_clock_info(self):
         """Test case for clock_info
 
@@ -82,11 +94,25 @@ class TestInternalController(BaseTestCase):
         Report for one month
         """
         response = self.client.open(
-            '/api/v1/report/{year_month}'.format(year_month='year_month_example'),
+            '/api/v1/playlog/report/{year_month}'.format(year_month='year_month_example'),
             method='GET')
         self.assert200(response,
                        'Response body is : ' + response.data.decode('utf-8'))
 
+    def test_list_playlog(self):
+        """Test case for list_playlog
+
+        List tracks in the play-log since the given timestamp
+        """
+        query_string = [('page', 56),
+                        ('limit', 200)]
+        response = self.client.open(
+            '/api/v1/playlog/since/{date_time}'.format(date_time='2013-10-20T19:20:30+01:00'),
+            method='GET',
+            query_string=query_string)
+        self.assert200(response,
+                       'Response body is : ' + response.data.decode('utf-8'))
+
     def test_log_engine_health(self):
         """Test case for log_engine_health
 
diff --git a/src/rest/test/test_public_controller.py b/src/rest/test/test_public_controller.py
index 8a38b22..9fc7780 100644
--- a/src/rest/test/test_public_controller.py
+++ b/src/rest/test/test_public_controller.py
@@ -40,13 +40,12 @@ class TestPublicController(BaseTestCase):
         self.assert200(response,
                        'Response body is : ' + response.data.decode('utf-8'))
 
-
     def test_list_tracks(self):
         """Test case for list_tracks
 
         List recent tracks in the play-log
         """
-        query_string = [('offset', 56),
+        query_string = [('page', 56),
                         ('limit', 50)]
         response = self.client.open(
             '/api/v1/trackservice',
-- 
GitLab