272 lines
10 KiB
Python
272 lines
10 KiB
Python
|
import flet as ft
|
||
|
import requests
|
||
|
import threading
|
||
|
import asyncio
|
||
|
import websockets
|
||
|
from websockets import connect # Ensure this is imported
|
||
|
import json
|
||
|
from datetime import datetime
|
||
|
from pages.student_main_page import student_main_page
|
||
|
|
||
|
def main_page(page: ft.Page):
|
||
|
page.clean()
|
||
|
page.theme_mode = ft.ThemeMode.LIGHT
|
||
|
|
||
|
session = page.session.get("access_token")
|
||
|
if not session:
|
||
|
page.go("/login") # Redirect to login if no session
|
||
|
|
||
|
def is_student():
|
||
|
url = 'http://awesom-o.org:8000/check_role'
|
||
|
headers = {
|
||
|
'accept': 'application/json',
|
||
|
'Content-Type': 'application/json'
|
||
|
}
|
||
|
session_id = page.session.get("access_token")
|
||
|
if not session_id:
|
||
|
return None
|
||
|
|
||
|
data = {'session_id': session_id}
|
||
|
try:
|
||
|
response = requests.post(url, json=data, headers=headers)
|
||
|
response.raise_for_status()
|
||
|
role = response.json()
|
||
|
|
||
|
if role and 'role' in role and 'role' in role['role']:
|
||
|
if role['role']['role'] == "student":
|
||
|
role = "s"
|
||
|
return role
|
||
|
elif role['role']['role'] == "teacher":
|
||
|
role = "t"
|
||
|
return role
|
||
|
print("Unexpected response structure:", role)
|
||
|
return None
|
||
|
except requests.exceptions.RequestExceptin as error:
|
||
|
print("Error during role check:", error)
|
||
|
return None
|
||
|
|
||
|
|
||
|
|
||
|
page.title = "Room Information"
|
||
|
page.vertical_alignment = ft.MainAxisAlignment.START # Align all content to the top
|
||
|
|
||
|
|
||
|
if is_student() == "s":
|
||
|
student_main_page(page)
|
||
|
elif is_student() == "t":
|
||
|
async def fetch_room_data(session_id: str, update_room_list):
|
||
|
uri = "ws://localhost:8000/ws/teacher/open_rooms"
|
||
|
headers = {"session-id": session_id} # Add session ID to headers
|
||
|
|
||
|
async with websockets.connect(uri, extra_headers=headers) as websocket:
|
||
|
print("WebSocket connected")
|
||
|
try:
|
||
|
while True:
|
||
|
# Receive data from the WebSocket
|
||
|
data = await websocket.recv()
|
||
|
room_data = json.loads(data)
|
||
|
open_rooms = room_data.get("open_rooms", [])
|
||
|
|
||
|
# Update the room list
|
||
|
update_room_list(open_rooms)
|
||
|
|
||
|
except websockets.ConnectionClosed:
|
||
|
print("WebSocket connection closed")
|
||
|
except Exception as e:
|
||
|
print(f"WebSocket error: {e}")
|
||
|
|
||
|
# Function to fetch students in a room
|
||
|
def fetch_students_in_room(unique_id: str, session_id: str):
|
||
|
url = f"http://awesom-o.org:8000/teacher/room_students/?unique_id={unique_id}"
|
||
|
headers = {"accept": "application/json", "Content-Type": "application/json"}
|
||
|
data = {"session_id": session_id}
|
||
|
try:
|
||
|
response = requests.post(url, json=data, headers=headers)
|
||
|
response.raise_for_status()
|
||
|
return response.json()
|
||
|
except requests.RequestException as e:
|
||
|
print(f"Error fetching students: {e}")
|
||
|
return None
|
||
|
|
||
|
# Function to delete a room
|
||
|
def delete_room(unique_id: str, session_id: str):
|
||
|
url = f"http://awesom-o.org:8000/teacher/delete_room/?unique_id={unique_id}"
|
||
|
headers = {"accept": "application/json", "Content-Type": "application/json"}
|
||
|
data = {"session_id": session_id}
|
||
|
try:
|
||
|
response = requests.delete(url, json=data, headers=headers)
|
||
|
response.raise_for_status()
|
||
|
return True
|
||
|
except requests.RequestException as e:
|
||
|
print(f"Error deleting room: {e}")
|
||
|
return False
|
||
|
|
||
|
# Main Flet app
|
||
|
page.title = "Room Management"
|
||
|
page.vertical_alignment = ft.MainAxisAlignment.START # Align content to the top
|
||
|
page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
|
||
|
page.padding = 20
|
||
|
page.scroll = "adaptive"
|
||
|
|
||
|
# Check if the user is logged in
|
||
|
session_id = page.session.get("access_token")
|
||
|
if not session_id:
|
||
|
page.go("/login") # Redirect to login if no session
|
||
|
|
||
|
# Search field
|
||
|
search_field = ft.TextField(label="Search", expand=True)
|
||
|
|
||
|
# Icon button to navigate to "/create" page
|
||
|
create_button = ft.IconButton(
|
||
|
icon=ft.icons.ADD,
|
||
|
on_click=lambda _: page.go("/create"),
|
||
|
)
|
||
|
|
||
|
# Container for the room list
|
||
|
room_container = ft.Column(scroll=ft.ScrollMode.AUTO, expand=True)
|
||
|
|
||
|
# Function to update the room list
|
||
|
def update_room_list(rooms):
|
||
|
room_container.controls.clear()
|
||
|
|
||
|
for room in rooms:
|
||
|
room_name = room.get("room_name", "Unknown Room")
|
||
|
room_info = room.get("info", "")
|
||
|
location = room.get("location", "")
|
||
|
teacher_name = room.get("teacher_name", "")
|
||
|
max_students = room.get("max_students", 0)
|
||
|
current_students = room.get("current_students", 0)
|
||
|
unique_id = room.get("unique_id", "")
|
||
|
|
||
|
# Create a clickable room card
|
||
|
room_card = ft.GestureDetector(
|
||
|
content=ft.Card(
|
||
|
content=ft.Container(
|
||
|
content=ft.Column(
|
||
|
[
|
||
|
# Top line: room_name, room_info, location
|
||
|
ft.Row(
|
||
|
[
|
||
|
ft.Text(f"{room_name}", size=20),
|
||
|
ft.Text(f"{room_info}", size=16),
|
||
|
ft.Text(f"| {location}", size=16),
|
||
|
],
|
||
|
spacing=5,
|
||
|
),
|
||
|
# Teacher line
|
||
|
ft.Text(f"Teacher: {teacher_name}", size=16),
|
||
|
# Capacity line
|
||
|
ft.Text(f"Capacity: {current_students}/{max_students}", size=16),
|
||
|
],
|
||
|
spacing=10,
|
||
|
),
|
||
|
padding=20,
|
||
|
),
|
||
|
margin=10,
|
||
|
elevation=5,
|
||
|
),
|
||
|
on_tap=lambda e, unique_id=unique_id: open_room_dialog(unique_id),
|
||
|
)
|
||
|
|
||
|
room_container.controls.append(room_card)
|
||
|
|
||
|
if not rooms:
|
||
|
room_container.controls.append(ft.Text("No open rooms available.", size=18))
|
||
|
|
||
|
page.update()
|
||
|
|
||
|
# Function to open the room dialog
|
||
|
def open_room_dialog(unique_id: str):
|
||
|
# Fetch students in the room
|
||
|
students_data = fetch_students_in_room(unique_id, session_id)
|
||
|
if not students_data:
|
||
|
page.snack_bar = ft.SnackBar(ft.Text("Failed to fetch students."))
|
||
|
page.snack_bar.open = True
|
||
|
page.update()
|
||
|
return
|
||
|
|
||
|
students = students_data.get("students", [])
|
||
|
|
||
|
if students != None:
|
||
|
|
||
|
students_list = ft.Column(
|
||
|
[ft.Text(f"Student: {student}") for student in students],
|
||
|
scroll=ft.ScrollMode.AUTO,
|
||
|
expand=True,
|
||
|
)
|
||
|
else:
|
||
|
|
||
|
students_list = ft.Column(ft.Text(f"There are no students who joined your Room"),
|
||
|
scroll=ft.ScrollMode.AUTO,
|
||
|
expand=True,
|
||
|
)
|
||
|
# Confirmation dialog for deleting the room
|
||
|
def open_delete_confirmation_dialog():
|
||
|
page.close(dialog)
|
||
|
def confirm_delete(e):
|
||
|
if delete_room(unique_id, session_id):
|
||
|
page.snack_bar = ft.SnackBar(ft.Text("Room deleted successfully."))
|
||
|
page.snack_bar.open = True
|
||
|
page.update()
|
||
|
page.close(confirm_dialog)
|
||
|
page.update()
|
||
|
else:
|
||
|
page.snack_bar = ft.SnackBar(ft.Text("Failed to delete room."))
|
||
|
page.snack_bar.open = True
|
||
|
page.update()
|
||
|
|
||
|
confirm_dialog = ft.AlertDialog(
|
||
|
title=ft.Text("Are you sure you want to delete this room?"),
|
||
|
actions=[
|
||
|
ft.TextButton("No", on_click=lambda e: page.close(confirm_dialog)),
|
||
|
ft.TextButton("Yes", on_click=confirm_delete),
|
||
|
],
|
||
|
)
|
||
|
|
||
|
page.dialog = confirm_dialog
|
||
|
confirm_dialog.open = True
|
||
|
page.update()
|
||
|
|
||
|
# Room dialog
|
||
|
dialog = ft.AlertDialog(
|
||
|
title=ft.Text("Room Details"),
|
||
|
content=students_list,
|
||
|
actions=[
|
||
|
ft.TextButton("Close", on_click=lambda e: page.close(dialog)),
|
||
|
ft.TextButton("Delete Room", on_click=lambda e: open_delete_confirmation_dialog()),
|
||
|
],
|
||
|
)
|
||
|
|
||
|
page.dialog = dialog
|
||
|
dialog.open = True
|
||
|
page.update()
|
||
|
|
||
|
# WebSocket listener for real-time updates
|
||
|
async def listen_for_updates():
|
||
|
while True:
|
||
|
try:
|
||
|
await fetch_room_data(session_id, update_room_list)
|
||
|
except Exception as e:
|
||
|
print(f"WebSocket connection error: {e}. Reconnecting in 5 seconds...")
|
||
|
await asyncio.sleep(5) # Wait before reconnecting
|
||
|
|
||
|
# Top bar layout
|
||
|
top_bar = ft.Row(
|
||
|
[
|
||
|
search_field,
|
||
|
create_button,
|
||
|
],
|
||
|
alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
|
||
|
vertical_alignment=ft.CrossAxisAlignment.CENTER,
|
||
|
)
|
||
|
|
||
|
# Add components to the page
|
||
|
page.add(
|
||
|
top_bar,
|
||
|
room_container,
|
||
|
)
|
||
|
|
||
|
# Start the WebSocket listener
|
||
|
page.run_task(listen_for_updates)
|
||
|
else:
|
||
|
page.go("/login")
|