185 lines
7.6 KiB
Python
185 lines
7.6 KiB
Python
import json
|
|
import os
|
|
import time
|
|
from datetime import datetime
|
|
|
|
from flask import Flask, request, jsonify, abort, make_response
|
|
from werkzeug.utils import secure_filename
|
|
from src.service.ModelStore import ModelStore
|
|
from src.model.entity.Slide import Slide
|
|
from src.model.enum.ContentType import ContentType
|
|
from src.interface.ObController import ObController
|
|
from src.util.utils import str_to_enum, get_optional_string, str_datetime_to_cron, str_weekdaytime_to_cron
|
|
from src.util.UtilFile import randomize_filename
|
|
|
|
|
|
class SlideApiController(ObController):
|
|
|
|
def register(self):
|
|
self._app.add_url_rule('/api/slide', 'api_slide_add', self.add_slide, methods=['POST'])
|
|
self._app.add_url_rule('/api/slide/notification', 'api_slide_notification_add', self.add_notification, methods=['POST'])
|
|
self._app.add_url_rule('/api/slide/<int:slide_id>', 'api_slide_get', self.get_slide, methods=['GET'])
|
|
self._app.add_url_rule('/api/slide/<int:slide_id>', 'api_slide_edit', self.edit_slide, methods=['PUT'])
|
|
self._app.add_url_rule('/api/slide/<int:slide_id>', 'api_slide_delete', self.delete_slide, methods=['DELETE'])
|
|
self._app.add_url_rule('/api/slide/positions', 'api_slide_positions', self.update_slide_positions, methods=['POST'])
|
|
|
|
def get_slide(self, slide_id: int):
|
|
slide = self._model_store.slide().get(slide_id)
|
|
if not slide:
|
|
abort(404, description="Slide not found")
|
|
return jsonify(slide.to_dict())
|
|
|
|
def add_slide(self):
|
|
return self.add_slide_or_notification(is_notification=False)
|
|
|
|
def add_notification(self):
|
|
return self.add_slide_or_notification(is_notification=True)
|
|
|
|
def add_slide_or_notification(self, is_notification=False):
|
|
data = request.get_json()
|
|
|
|
if not data or 'content_id' not in data:
|
|
abort(400, description="Valid Content ID is required")
|
|
|
|
if not self._model_store.content().get(data.get('content_id')):
|
|
abort(404, description="Content not found")
|
|
|
|
if not data or 'playlist_id' not in data:
|
|
abort(400, description="Valid Playlist ID is required")
|
|
|
|
if not self._model_store.playlist().get(data.get('playlist_id')):
|
|
abort(404, description="Playlist not found")
|
|
|
|
cron_schedule_start, cron_schedule_end = self._resolve_scheduling(data, is_notification=is_notification)
|
|
|
|
slide = Slide(
|
|
content_id=data.get('content_id'),
|
|
enabled=data.get('enabled', True),
|
|
delegate_duration=data.get('delegate_duration', False),
|
|
duration=data.get('duration', 3),
|
|
position=data.get('position', 999),
|
|
is_notification=is_notification,
|
|
playlist_id=data.get('playlist_id', None),
|
|
cron_schedule=cron_schedule_start,
|
|
cron_schedule_end=cron_schedule_end
|
|
)
|
|
|
|
slide = self._model_store.slide().add_form(slide)
|
|
self._post_update()
|
|
|
|
return jsonify(slide.to_dict()), 201
|
|
|
|
def edit_slide(self, slide_id: int):
|
|
data = request.get_json()
|
|
if not data or 'content_id' not in data:
|
|
abort(400, description="Content ID is required")
|
|
|
|
slide = self._model_store.slide().get(slide_id)
|
|
if not slide:
|
|
abort(404, description="Slide not found")
|
|
|
|
cron_schedule_start, cron_schedule_end = self._resolve_scheduling(data, is_notification=slide.is_notification)
|
|
|
|
self._model_store.slide().update_form(
|
|
id=slide_id,
|
|
content_id=data.get('content_id', slide.content_id),
|
|
enabled=data.get('enabled', slide.enabled),
|
|
position=data.get('position', slide.position),
|
|
delegate_duration=data.get('delegate_duration', slide.delegate_duration),
|
|
duration=data.get('duration', slide.duration),
|
|
cron_schedule=cron_schedule_start if 'scheduling' in data else slide.cron_schedule,
|
|
cron_schedule_end=cron_schedule_end if 'scheduling' in data else slide.cron_schedule_end,
|
|
)
|
|
self._post_update()
|
|
|
|
updated_slide = self._model_store.slide().get(slide_id)
|
|
return jsonify(updated_slide.to_dict())
|
|
|
|
def delete_slide(self, slide_id: int):
|
|
slide = self._model_store.slide().get(slide_id)
|
|
|
|
if not slide:
|
|
abort(404, description="Slide not found")
|
|
|
|
self._model_store.slide().delete(slide_id)
|
|
self._post_update()
|
|
|
|
return '', 204
|
|
|
|
def update_slide_positions(self):
|
|
data = request.get_json()
|
|
if not data:
|
|
abort(400, description="Positions data are required")
|
|
|
|
self._model_store.slide().update_positions(data)
|
|
self._post_update()
|
|
return jsonify({'status': 'ok'})
|
|
|
|
def _post_update(self):
|
|
self._model_store.variable().update_by_name("last_slide_update", time.time())
|
|
|
|
def _resolve_scheduling(self, data, is_notification=False):
|
|
try:
|
|
return self._resolve_scheduling_for_notification(data) if is_notification else self._resolve_scheduling_for_slide(data)
|
|
except ValueError as ve:
|
|
abort(400, description=str(ve))
|
|
|
|
def _resolve_scheduling_for_slide(self, data):
|
|
scheduling = data.get('scheduling', 'loop')
|
|
cron_schedule_start = None
|
|
cron_schedule_end = None
|
|
|
|
if scheduling == 'loop':
|
|
pass
|
|
elif scheduling == 'datetime':
|
|
datetime_start = data.get('datetime_start')
|
|
datetime_end = data.get('datetime_end')
|
|
|
|
if not datetime_start:
|
|
abort(400, description="Field datetime_start is required for scheduling='datetime'")
|
|
|
|
cron_schedule_start = str_datetime_to_cron(datetime_str=datetime_start)
|
|
|
|
if datetime_end:
|
|
cron_schedule_end = str_datetime_to_cron(datetime_str=datetime_end)
|
|
elif scheduling == 'inweek':
|
|
day_start = data.get('day_start')
|
|
time_start = data.get('time_start')
|
|
day_end = data.get('day_end')
|
|
time_end = data.get('time_end')
|
|
|
|
if not (day_start and time_start and day_end and time_end):
|
|
abort(400, description="day_start, time_start, day_end, and time_end are required for scheduling='inweek'")
|
|
cron_schedule_start = str_weekdaytime_to_cron(weekday=int(day_start), time_str=time_start)
|
|
cron_schedule_end = str_weekdaytime_to_cron(weekday=int(day_end), time_str=time_end)
|
|
else:
|
|
abort(400, description="Invalid value for slide scheduling. Expected 'loop', 'datetime', or 'inweek'.")
|
|
|
|
return cron_schedule_start, cron_schedule_end
|
|
|
|
def _resolve_scheduling_for_notification(self, data):
|
|
scheduling = data.get('scheduling', 'datetime')
|
|
cron_schedule_start = None
|
|
cron_schedule_end = None
|
|
|
|
if scheduling == 'datetime':
|
|
datetime_start = data.get('datetime_start')
|
|
datetime_end = data.get('datetime_end')
|
|
|
|
if not datetime_start:
|
|
abort(400, description="Field datetime_start is required for scheduling='datetime'")
|
|
|
|
cron_schedule_start = str_datetime_to_cron(datetime_str=datetime_start)
|
|
|
|
if datetime_end:
|
|
cron_schedule_end = str_datetime_to_cron(datetime_str=datetime_end)
|
|
elif scheduling == 'cron':
|
|
cron_schedule_start = data.get('cron_start')
|
|
|
|
if not cron_schedule_start:
|
|
abort(400, description="Field cron_start is required for scheduling='cron'")
|
|
else:
|
|
abort(400, description="Invalid value for notification scheduling. Expected 'datetime' or 'cron'.")
|
|
|
|
return cron_schedule_start, cron_schedule_end
|