diff --git a/requirements.txt b/requirements.txt index 0cc3a9710e30b7fff977fb1bd577c51e447c7726..7b5d96d51e3c5c147f26fd0d1be514bc06729f8c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,8 @@ connexion[swagger-ui] == 2.7.0 python_dateutil == 2.6.0 typing == 3.5.2.2 setuptools >= 21.0.0 -gunicorn==20.0.4 \ No newline at end of file +gunicorn==20.0.4 +sqlalchemy==1.3.17 +Flask_SQLAlchemy==2.4.3 +flask-marshmallow==0.13.0 +marshmallow-sqlalchemy==0.23.1 \ No newline at end of file diff --git a/src/base/config.py b/src/base/config.py index 2d90e5cb0a61a46009d02d29a78e8375d4bca72b..aa567085ae021c5256a52b0f9ae15242bf253b88 100644 --- a/src/base/config.py +++ b/src/base/config.py @@ -142,9 +142,9 @@ class AuraConfig: """ Retrieves the database connection string. """ - db_name = self.get("db_name") - db_user = self.get("db_user") - db_pass = self.get("db_pass") - db_host = self.get("db_host") + db_name = str(self.get("db_name")) + db_user = str(self.get("db_user")) + db_pass = str(self.get("db_pass")) + db_host = str(self.get("db_host")) db_charset = self.get("db_charset", "utf8") return "mysql://" + db_user + ":" + db_pass + "@" + db_host + "/" + db_name + "?charset=" + db_charset \ No newline at end of file diff --git a/src/base/logger.py b/src/base/logger.py index e0cf95784a0778668ecf3edff41dc202c0273412..da2f62900a436fbfdac56272b0991b8f5f6fc96f 100644 --- a/src/base/logger.py +++ b/src/base/logger.py @@ -19,7 +19,7 @@ import logging -from src.base.config import AuraConfig +from .config import AuraConfig class AuraLogger(): diff --git a/src/models.py b/src/models.py new file mode 100644 index 0000000000000000000000000000000000000000..6bb95883cac287420795baea65c68bb5a16117a4 --- /dev/null +++ b/src/models.py @@ -0,0 +1,150 @@ + +# +# Aura Engine API (https://gitlab.servus.at/aura/engine-api) +# +# Copyright (C) 2020 - The Aura Engine Team. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import datetime + +from sqlalchemy import create_engine, Column, DateTime, String, Integer, Boolean + +from src.server import db, ma + + + + +class PlayLog(db.Model): + """ + Table holding play-log entries. + """ + __tablename__ = 'playlog' + + # Primary Key + track_start = Column(DateTime, primary_key=True) + + # Columns + track_artist = Column(String(256)) + track_album = Column(String(256)) + track_title = Column(String(256)) + track_duration = Column(String(256)) + track_type = Column(Integer) + schedule_id = Column(Integer) + schedule_start = Column(DateTime) + schedule_end = Column(DateTime) + schedule_repetition = Column(Boolean) + schedule_playlist_id = Column(Integer) + schedule_fallback_type = Column(Integer) + show_id = Column(Integer) + schedule_repetition = Column(Boolean) + schedule_playlist_id = Column(Integer) + schedule_fallback_type = Column(Integer) + show_id = Column(Integer) + show_name = Column(String(256)) + show_funding_category = Column(String(256)) + show_name = Column(String(256)) + show_type = Column(String(256)) + show_category = Column(String(256)) + show_topic = Column(String(256)) + + + + def __init__(self): + """ + Initializes a trackservice entry + """ + pass + + + @staticmethod + def select_current(): + """ + Selects the currently playing track. + """ + db.session.commit() + now = datetime.datetime.now() + track = db.session.query(PlayLog).\ + filter(PlayLog.track_start <= str(now)).\ + order_by(PlayLog.track_start.desc()).first() + return track + + + @staticmethod + def select_last_hours(n): + """ + Selects the tracks playing in the past (`n`) hours. + """ + db.session.commit() + last_hours = datetime.datetime.today() - datetime.timedelta(hours=n) + tracks = db.session.query(PlayLog).filter(PlayLog.track_start >= str(last_hours)).all() + return tracks + + + @staticmethod + def select_by_day(day): + """ + Select the track-service items for a day. + """ + db.session.commit() + day_plus_one = day + datetime.timedelta(days=1) + tracks = db.session.query(PlayLog).\ + filter(PlayLog.track_start >= str(day), PlayLog.track_start < str(day_plus_one)).\ + order_by(PlayLog.track_start.desc()).all() + return tracks + + + @staticmethod + def select_by_range(from_day, to_day): + """ + Selects the track-service items for a day range. + """ + db.session.commit() + tracks = db.session.query(PlayLog).filter(PlayLog.track_start >= str(from_day),\ + PlayLog.track_start < str(to_day)).all() + return tracks + + + def __str__(self): + return "Track [track_start: %s, track_title: %s]" % (str(self.track_start), str(self.track_title)) + + +class PlayLogSchema(ma.SQLAlchemyAutoSchema): + """ + Schema for playlog entries. + """ + class Meta: + model = PlayLog + sqla_session = db.session + + +class TrackServiceSchema(ma.SQLAlchemySchema): + """ + Schema for trackservice entries. + """ + class Meta: + model = PlayLog + sqla_session = db.session + fields = ( + "track_start", + "track_artist", + "track_album", + "track_title" + ) + + + +# Create Tables +db.create_all() diff --git a/src/server.py b/src/server.py index 79355420659d5621a96046d88c85b11e0aa90cd8..46aee0ead3a0462ca289d34470988109119d3ff2 100644 --- a/src/server.py +++ b/src/server.py @@ -19,19 +19,55 @@ import sys import os -import connexion sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -from src.rest import encoder +import connexion +from flask_sqlalchemy import SQLAlchemy +from flask_marshmallow import Marshmallow + +from base.config import AuraConfig +from base.logger import AuraLogger +from rest import encoder +from service import ApiService + + +# App Initialization +config = AuraConfig() +logger = AuraLogger(config, "engine-api").logger + +def configure_flask(app): + api.app.json_encoder = encoder.JSONEncoder + app.config["SQLALCHEMY_DATABASE_URI"] = config.get_database_uri() + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + app.config['ENV'] = "development" + app.config['FLASK_ENV'] = "development" + return app + + +api = connexion.App("engine-api", specification_dir='src/rest/swagger') +api.add_api('swagger.yaml', arguments={'title': 'AURA Engine API'}, pythonic_params=True) +app = configure_flask(api.app) +db = SQLAlchemy(app) +db.init_app(app) +ma = Marshmallow(app) + + +def startup(): + """ + Startup Server. + """ + port = config.get("api_port") + api.run(port=port) -app = connexion.App(__name__, specification_dir='rest/swagger') -app.app.json_encoder = encoder.JSONEncoder -app.add_api('swagger.yaml', arguments={'title': 'AURA Engine API'}, pythonic_params=True) +with app.app_context(): + """ + Initialize Server. + """ + service = ApiService(config, logger) + logger.info("API Service initialized.") -def main(): - app.run(port=8008) if __name__ == '__main__': - main() + startup() diff --git a/src/service/engine_service.py b/src/service.py similarity index 61% rename from src/service/engine_service.py rename to src/service.py index 3a578107427f2d583a14f77526c31818177cd2dc..bd4b96a80871133abb56df8ae5a0fdd9dfd2f9d8 100644 --- a/src/service/engine_service.py +++ b/src/service.py @@ -17,11 +17,56 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. -class EngineService(): +import datetime - def __init__(self): - pass + +class ApiService(): + """ + Service handling API actions. + """ + + config = None + logger = None + + + def __init__(self, config, logger): + self.config = config + self.logger = logger + + + def current_track(self): + """ + Retrieves the currently playing track. + + Returns: + (PlayLogEntry) + """ + from models import PlayLog, TrackServiceSchema + track = PlayLog.select_current() + track_schema = TrackServiceSchema() + return track_schema.dump(track) + + + def list_tracks(self, offset=None, limit=None): + """ + Lists the most recent track-service entries. + + Args: + offset (Integer): The number of items to skip before starting to collect the result set + limit (Integer): The numbers of items to return + + Returns: + (List[PlayLogEntry]) + """ + return "some list of tracks" + + + def clock_info(self): + """ + Retrieves the currently playing playlist. + """ + return "current playlist" def activate_engine(self, engine_number): @@ -67,7 +112,3 @@ class EngineService(): """ return 'do some magic!' - - - -engineService = EngineService() \ No newline at end of file diff --git a/src/service/__init__.py b/src/service/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/service/playlist_service.py b/src/service/playlist_service.py deleted file mode 100644 index 48a11236de6c95a4d29886b70411512cf55b98d3..0000000000000000000000000000000000000000 --- a/src/service/playlist_service.py +++ /dev/null @@ -1,43 +0,0 @@ -# -# Aura Engine API (https://gitlab.servus.at/aura/engine-api) -# -# Copyright (C) 2020 - The Aura Engine Team. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -class PlaylistService(): - - - def __init__(self): - pass - - def current_playlist(self): - """ - Retrieves the currently playing playlist. - """ - return "current playlist" - - - def next_playlist(self): - """ - Retrieves the playlist playing next. - - Returns Playlist - """ - return "next playlist" - - - -playlistService = PlaylistService() \ No newline at end of file diff --git a/src/service/track_service.py b/src/service/track_service.py deleted file mode 100644 index 861f5bc6cd819137508953f30e108e9b50f13528..0000000000000000000000000000000000000000 --- a/src/service/track_service.py +++ /dev/null @@ -1,67 +0,0 @@ -# -# Aura Engine API (https://gitlab.servus.at/aura/engine-api) -# -# Copyright (C) 2020 - The Aura Engine Team. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -class TrackService(): - - - def __init__(self): - pass - - - def current_track(self): - """ - Retrieves the currently playing track. - - Returns: - (PlayLogEntry) - """ - return "current track" - - - def get_track(self, track_id): - """ - Retrieves a single track by its ID. - - Args: - track_id (Integer): ID of the track-service entry - - Returns: - (PlayLogEntry) - """ - return "a single track by id" - - - def list_tracks(self, offset=None, limit=None): - """ - Lists the most recent track-service entries. - - Args: - offset (Integer): The number of items to skip before starting to collect the result set - limit (Integer): The numbers of items to return - - Returns: - (List[PlayLogEntry]) - """ - return "some list of tracks" - - - - - -trackService = TrackService() \ No newline at end of file