1+ import atexit
2+ import signal
3+ import sys
14from flask import Flask , request , jsonify
25from flask_cors import CORS
36
69
710from werkzeug .middleware .proxy_fix import ProxyFix
811
9- from controller .queue_item import QueueItem
1012from controller .admin_action import AdminAction
1113from controller .upload_history import UploadHistory
1214from controller .user import User
1315from controller .design import Design
14-
16+ from controller . rotation_system import RotationSystem
1517from controller .setting import authorize_mail , authorize_callback
18+ from services .scheduler_service import scheduler_service
19+
20+ def create_app ():
21+ app = Flask (__name__ )
22+ app .wsgi_app = ProxyFix (app .wsgi_app , x_proto = 1 )
23+ app .secret_key = "super-secret" # Change this in production
24+ CORS (app )
25+ app .config ["JWT_SECRET_KEY" ] = "super-secret" # Change this in production
26+ jwt = JWTManager (app )
27+
28+ # Register signal handlers for clean shutdown
29+ def signal_handler (sig , frame ):
30+ print (f"Received shutdown signal { sig } " )
31+ # Since scheduler_service has its own shutdown logic in atexit handler,
32+ # we don't need to manually shut it down here
33+ sys .exit (0 )
34+
35+ # Register the signal handler for SIGINT (Ctrl+C) and SIGTERM
36+ signal .signal (signal .SIGINT , signal_handler )
37+ signal .signal (signal .SIGTERM , signal_handler )
38+
39+ # Initialize the scheduler service
40+ try :
41+ print ("Initializing scheduler service" )
42+ scheduler_service .init_app (app )
43+ # No need to register a separate atexit handler here
44+ # The scheduler_service already registers its own in init_app
45+ except Exception as e :
46+ print (f"Failed to initialize scheduler: { e } " )
47+
48+ return app
1649
17- app = Flask (__name__ )
18- app .wsgi_app = ProxyFix (app .wsgi_app , x_proto = 1 )
19- app .secret_key = "super-secret" # Change this
20- CORS (app )
21-
22- app .config ["JWT_SECRET_KEY" ] = "super-secret" # Change this
23- jwt = JWTManager (app )
24-
50+ app = create_app ()
2551
2652@app .route ('/' )
2753def hello_world (): # put application's code here
@@ -146,9 +172,9 @@ def update_design_image(design_id):
146172@jwt_required ()
147173def get_design (design_id ):
148174 handler = Design (email = get_jwt_identity ())
149- # Use the URL param, not request.form
150175 return handler .get_design (design_id = design_id )
151176
177+
152178@app .route ("/designs" , methods = ['GET' ])
153179@jwt_required ()
154180def get_designs ():
@@ -161,9 +187,9 @@ def get_designs():
161187
162188@app .route ("/design/<int:design_id>/title" , methods = ['PUT' ])
163189@jwt_required ()
164- def update_design_title ():
190+ def update_design_title (design_id ):
165191 handler = Design (email = get_jwt_identity ())
166- return handler .update_design_title (design_id = request . form . get ( ' design_id' ) , title = request .form .get ('title' ))
192+ return handler .update_design_title (design_id = design_id , title = request .form .get ('title' ))
167193
168194
169195@app .route ("/design/<int:design_id>/approval" , methods = ['PUT' ])
@@ -273,103 +299,87 @@ def handleAdminActionById(action_id):
273299 return jsonify ("Cannot delete record because it is referenced by other records" ), 400
274300
275301
276- # QueueItem-----------------------------------------------------------------------------------------------------------
277-
278- @app .route ("/queue_item/pagination" , methods = ['GET' ])
302+ # Rotation System-----------------------------------------------------------------------------------------------------------
303+ @app .route ("/rotation/current" , methods = ['GET' ])
279304@jwt_required ()
280- def get_queue_paginated ():
281- try :
282- page = int (request .args .get ('page' , 1 ))
283- page_size = int (request .args .get ('size' , 6 ))
284- handler = QueueItem (email = get_jwt_identity ())
285-
286- result = handler .get_all_items_paginated (page , page_size )
287- return jsonify (result ), 200
288-
289- except Exception as e :
290- return jsonify ({'error' : str (e )}), 500
305+ def get_current_image ():
306+ handler = RotationSystem (email = get_jwt_identity ())
307+ return handler .get_current_image ()
291308
309+ @app .route ("/rotation/add" , methods = ['POST' ])
310+ @jwt_required ()
311+ def add_unscheduled_image ():
312+ handler = RotationSystem (email = get_jwt_identity (), json_data = request .json )
313+ return handler .add_unscheduled_image ()
292314
293- @app .route ("/queue_item/<int:queue_id>/order " , methods = ['PUT ' ])
315+ @app .route ("/rotation/schedule " , methods = ['POST ' ])
294316@jwt_required ()
295- def update_item_order (queue_id ):
296- data = request .get_json ()
297- new_order = data .get ('new_order' )
298- handler = QueueItem (email = get_jwt_identity ())
299- return handler .update_item_order (queue_id = queue_id , new_order = new_order )
317+ def schedule_image ():
318+ handler = RotationSystem (email = get_jwt_identity (), json_data = request .json )
319+ return handler .schedule_image ()
300320
321+ @app .route ("/rotation/reorder" , methods = ['POST' ])
322+ @jwt_required ()
323+ def reorder_images ():
324+ handler = RotationSystem (email = get_jwt_identity (), json_data = request .json )
325+ return handler .reorder_images ()
301326
327+ @app .route ("/rotation/rotate" , methods = ['POST' ])
328+ @jwt_required ()
329+ def rotate_to_next ():
330+ handler = RotationSystem (email = get_jwt_identity ())
331+ return handler .rotate_to_next ()
302332
303- # ————— GET all queue items (public) —————
304- @app .route ("/queue_item" , methods = ['GET' ])
305- def handleGetQueueItems ():
306- handler = QueueItem ()
307- items = handler .getAllQueueItem ()
308- return jsonify (items ), 200
333+ @app .route ("/rotation/items" , methods = ['GET' ])
334+ @jwt_required ()
335+ def get_all_rotation_items ():
336+ handler = RotationSystem (email = get_jwt_identity ())
337+ return handler .get_all_items ()
309338
310- # ————— Create a new queue item (auth required) —————
311- @app .route ("/queue_item" , methods = ['POST' ])
339+ @app .route ("/rotation/items/pagination" , methods = ['GET' ])
312340@jwt_required ()
313- def handleCreateQueueItem ():
314- data = request .get_json () or {}
315- required_keys = {
316- 'design_id' ,
317- 'start_time' ,
318- 'end_time' ,
319- 'display_duration' ,
320- 'scheduled' ,
321- 'scheduled_at'
322- }
323-
324- if not required_keys .issubset (data ):
325- return jsonify ("Missing one of required keys" ), 400
326-
327- handler = QueueItem ()
341+ def get_rotation_items_paginated ():
328342 try :
329- new_item = handler .addNewQueueItem (data )
330- return jsonify (new_item ), 201
331- except Exception as e :
332- print ("Error processing request:" , e )
333- return jsonify ("Invalid JSON data provided" ), 400
334-
335- @app .route ("/queue_item/<int:queue_id>" , methods = ['GET' , 'PUT' , 'DELETE' ])
336- def handleQueueItemById (queue_id ):
337- if request .method == 'GET' :
338- handler = QueueItem ()
339- return handler .getQueueItemById (queue_id )
340- elif request .method == 'PUT' :
341- try :
342- data = request .json
343- if not data :
344- return jsonify ("No data provided" ), 400
345343
346- valid_keys = { 'design_id ' , 'start_time' , 'end_time' , 'display_duration' , 'display_order' ,
347- 'scheduled ' , 'scheduled_at' }
348- if not any ( key in data for key in valid_keys ):
349- return jsonify ( "Missing a key" ), 400
344+ page = int ( request . args . get ( 'page ' , 1 ))
345+ page_size = int ( request . args . get ( 'size ' , 6 ))
346+ handler = RotationSystem ( email = get_jwt_identity ())
347+ return handler . get_items_paginated ( page , page_size )
350348
351- handler = QueueItem ()
352- return handler .updateQueueItemById (queue_id , data )
353- except Exception as e :
354- print ("Error processing request:" , e )
355- return jsonify ("Invalid data provided" ), 400
356- else :
357- try :
358- handler = QueueItem ()
359- return handler .deleteQueueItemById (queue_id )
360- except Exception as e :
361- print ("Error processing request:" , e )
362- return jsonify ("Can not delete record because it is referenced by other records" ), 400
349+ except Exception as e :
350+ return jsonify ({'error' : str (e )}), 500
363351
352+ @app .route ("/rotation/item/<int:item_id>" , methods = ['DELETE' ])
353+ @jwt_required ()
354+ def remove_rotation_item (item_id ):
355+ handler = RotationSystem (email = get_jwt_identity ())
356+ return handler .remove_item (item_id )
364357
365- @app .route ("/queue_item /scheduled" , methods = ['GET' ])
358+ @app .route ("/rotation /scheduled" , methods = ['GET' ])
366359@jwt_required ()
367- def get_scheduled_designs ():
360+ def get_scheduled_items ():
361+ handler = RotationSystem (email = get_jwt_identity ())
362+ return handler .get_scheduled_items ()
368363
369- handler = QueueItem ()
370- scheduled_items = handler .getScheduledDesigns ()
371- return jsonify (scheduled_items ), 200
364+ @app .route ("/rotation/scheduled/pagination" , methods = ['GET' ])
365+ @jwt_required ()
366+ def get_scheduled_items_paginated ():
367+ try :
368+ page = int (request .args .get ('page' , 1 ))
369+ page_size = int (request .args .get ('size' , 6 ))
370+ handler = RotationSystem (email = get_jwt_identity ())
371+ return handler .get_scheduled_items_paginated (page , page_size )
372+ except Exception as e :
373+ return jsonify ({'error' : str (e )}), 500
372374
375+ @app .route ("/rotation/scheduled/<int:schedule_id>" , methods = ['DELETE' ])
376+ @jwt_required ()
377+ def remove_scheduled_item (schedule_id ):
378+ try :
379+ handler = RotationSystem (email = get_jwt_identity ())
380+ return handler .remove_scheduled_item (schedule_id )
381+ except Exception as e :
382+ return jsonify ({'error' : str (e )}), 500
373383
374384# UploadHistory-----------------------------------------------------------------------------------------------------------
375385
0 commit comments