Skip to content

Commit e8d74da

Browse files
authored
Merge pull request #70 from RGBOARD/restructuring-queue
Restructuring queue
2 parents 8b70926 + 7c362d4 commit e8d74da

29 files changed

Lines changed: 3540 additions & 2031 deletions

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,20 @@ To run app.py:
8383
#### After Sign Up and Log in
8484
1. **Without credentials file:** Open your database application and check the `VerificationCode` table to find the code associated with the newly created account.
8585

86-
2. **With credentials file:** You should receive an email containing the verification code.
86+
2. **With credentials file:** You should receive an email containing the verification code.
87+
88+
#### Fetching PRs
89+
1. Fetch the PR and create a local branch on your device. For example, PR #15:
90+
```sh
91+
git fetch origin pull/15/head:pr-15
92+
```
93+
94+
2. Switch to the PR branch.
95+
```sh
96+
git checkout pr-63
97+
```
98+
99+
3. To refresh a PR branch with the latest changes:
100+
```sh
101+
git pull origin pull/66/head
102+
```

app.py

Lines changed: 103 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import atexit
2+
import signal
3+
import sys
14
from flask import Flask, request, jsonify
25
from flask_cors import CORS
36

@@ -6,22 +9,45 @@
69

710
from werkzeug.middleware.proxy_fix import ProxyFix
811

9-
from controller.queue_item import QueueItem
1012
from controller.admin_action import AdminAction
1113
from controller.upload_history import UploadHistory
1214
from controller.user import User
1315
from controller.design import Design
14-
16+
from controller.rotation_system import RotationSystem
1517
from 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('/')
2753
def hello_world(): # put application's code here
@@ -146,9 +172,9 @@ def update_design_image(design_id):
146172
@jwt_required()
147173
def 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()
154180
def 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

controller/queue_item.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ def get_all_items_paginated(self, page, page_size):
169169

170170
return jsonify(error="Unauthorized. No token."), 401
171171

172+
## MOVE TO OTHER FILE
172173
@jwt_required()
173174
def getUserHistory(self):
174175
user_email = get_jwt_identity()

0 commit comments

Comments
 (0)