youngtsai commited on
Commit
f455cf9
·
1 Parent(s): 405e31e

delete_file

Browse files
Files changed (4) hide show
  1. app.py +72 -15
  2. assignment_service.py +24 -2
  3. assignment_ui.py +105 -45
  4. storage_service.py +12 -1
app.py CHANGED
@@ -1042,6 +1042,32 @@ def get_assignment_content(assignment_id):
1042
  return None
1043
  return assignment_data
1044
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1045
  def get_chinese_paragraph_practice_log_session_content(file_name):
1046
  if file_name:
1047
  content = GCS_SERVICE.download_as_string("jutor_logs", file_name)
@@ -1055,21 +1081,32 @@ def get_chinese_paragraph_practice_log_session_content(file_name):
1055
  chinese_full_paragraph_refine_output_table_history = pd.DataFrame(content_json["chinese_full_paragraph_refine_output_table"]) if "chinese_full_paragraph_refine_output_table" in content_json else pd.DataFrame()
1056
  chinese_full_paragraph_save_output_history = content_json["chinese_full_paragraph_save_output"] if "chinese_full_paragraph_save_output" in content_json else ""
1057
 
 
1058
  assignment_id = content_json["assignment_id"] if "assignment_id" in content_json else ""
 
 
 
 
 
 
 
1059
  if assignment_id:
1060
- assignment = get_assignment_content(assignment_id)
1061
  chinese_assignment_content = gr.update(visible=True)
1062
- chinese_assignment_grade = assignment["metadata"]["grade"]
1063
- chinese_assignment_topic = assignment["metadata"]["topic"]
1064
- chinese_assignment_introduction = assignment["metadata"]["introduction"]
1065
- chinese_assignment_description = assignment["metadata"]["description"]
1066
- else:
1067
- chinese_assignment_content = gr.update(visible=False)
1068
- chinese_assignment_grade = ""
1069
- chinese_assignment_topic = ""
1070
- chinese_assignment_introduction = ""
1071
- chinese_assignment_description = ""
1072
-
 
 
 
 
1073
  else:
1074
  chinese_full_paragraph_input_history = ""
1075
  chinese_full_paragraph_evaluate_output_text_history = ""
@@ -1084,6 +1121,7 @@ def get_chinese_paragraph_practice_log_session_content(file_name):
1084
  chinese_assignment_topic = ""
1085
  chinese_assignment_introduction = ""
1086
  chinese_assignment_description = ""
 
1087
 
1088
  return chinese_full_paragraph_input_history, \
1089
  chinese_full_paragraph_evaluate_output_text_history, \
@@ -1096,7 +1134,8 @@ def get_chinese_paragraph_practice_log_session_content(file_name):
1096
  chinese_assignment_grade, \
1097
  chinese_assignment_topic, \
1098
  chinese_assignment_introduction, \
1099
- chinese_assignment_description
 
1100
 
1101
 
1102
  # === OpenAI Assistant ===
@@ -1591,12 +1630,19 @@ def init_params(request: gr.Request):
1591
  chinese_assignment_topic = gr.update(value=assignment_json_value.get("metadata", {}).get("topic", ""))
1592
  chinese_assignment_introduction = gr.update(value=assignment_json_value.get("metadata", {}).get("introduction", ""))
1593
  chinese_assignment_description = gr.update(value=assignment_json_value.get("metadata", {}).get("description", ""))
 
 
 
 
 
 
1594
  else:
1595
  chinese_assignment_row = gr.update(visible=False)
1596
  chinese_assignment_grade = gr.update(value="")
1597
  chinese_assignment_topic = gr.update(value="")
1598
  chinese_assignment_introduction = gr.update(value="")
1599
  chinese_assignment_description = gr.update(value="")
 
1600
 
1601
  assignment_id_input = gr.update(value=assignment_id_value)
1602
  assignment_json = gr.update(value=assignment_json_value)
@@ -1607,13 +1653,19 @@ def init_params(request: gr.Request):
1607
  chinese_assignment_topic = gr.update(value="")
1608
  chinese_assignment_introduction = gr.update(value="")
1609
  chinese_assignment_description = gr.update(value="")
 
1610
  assignment_id_input = gr.update(value=None)
1611
  assignment_json = gr.update(value=None)
1612
 
1613
  return user_data, \
1614
  admin_group, session_timestamp, request_origin, \
1615
  assignment_id_input, assignment_json, \
1616
- chinese_assignment_row, chinese_assignment_grade, chinese_assignment_topic, chinese_assignment_introduction, chinese_assignment_description, \
 
 
 
 
 
1617
  english_group, chinese_group, assignment_group
1618
 
1619
  CSS = """
@@ -3192,6 +3244,7 @@ with gr.Blocks(theme=THEME, css=CSS) as demo:
3192
  chinese_assignment_topic = gr.Textbox(label="主題", interactive=False)
3193
  chinese_assignment_introduction = gr.Textbox(label="寫作引文", interactive=False)
3194
  chinese_assignment_description = gr.Textbox(label="作業說明", interactive=False)
 
3195
 
3196
  # =====中文全文批改=====
3197
  with gr.Tab("中文全文批改") as chinese_full_paragraph_tab:
@@ -3462,6 +3515,8 @@ with gr.Blocks(theme=THEME, css=CSS) as demo:
3462
  chinese_assignment_introduction_history_log = gr.Markdown()
3463
  gr.Markdown("<span style='color:#4e80ee'>作業說明</span>")
3464
  chinese_assignment_description_history_log = gr.Markdown()
 
 
3465
 
3466
  gr.Markdown("---")
3467
  gr.Markdown("# 回傳作業內容")
@@ -3505,7 +3560,8 @@ with gr.Blocks(theme=THEME, css=CSS) as demo:
3505
  chinese_assignment_grade_history_log,
3506
  chinese_assignment_topic_history_log,
3507
  chinese_assignment_introduction_history_log,
3508
- chinese_assignment_description_history_log
 
3509
  ]
3510
  )
3511
 
@@ -3585,6 +3641,7 @@ with gr.Blocks(theme=THEME, css=CSS) as demo:
3585
  chinese_assignment_topic,
3586
  chinese_assignment_introduction,
3587
  chinese_assignment_description,
 
3588
  english_group,
3589
  chinese_group,
3590
  assignment_group
 
1042
  return None
1043
  return assignment_data
1044
 
1045
+ def get_assignment_formatted_deadline(submission_deadline_data):
1046
+ if submission_deadline_data is None:
1047
+ return "未設置截止日期"
1048
+
1049
+ try:
1050
+ # 嘗試解析 Unix 時間戳
1051
+ if isinstance(submission_deadline_data, (int, float)):
1052
+ submission_datetime = datetime.fromtimestamp(submission_deadline_data)
1053
+ # 嘗試解析 ISO 格式字串
1054
+ elif isinstance(submission_deadline_data, str):
1055
+ try:
1056
+ submission_datetime = datetime.fromisoformat(submission_deadline_data)
1057
+ except ValueError:
1058
+ # 如果不是 ISO 格式,嘗試其他常見格式
1059
+ submission_datetime = datetime.strptime(submission_deadline_data, "%Y-%m-%d %H:%M:%S")
1060
+ else:
1061
+ raise ValueError(f"無效的日期類型: {type(submission_deadline_data)}")
1062
+
1063
+ # 確保時間是 UTC+8
1064
+ taipei_tz = pytz.timezone('Asia/Taipei')
1065
+ submission_datetime = submission_datetime.astimezone(taipei_tz)
1066
+
1067
+ return submission_datetime.strftime("%Y-%m-%d %H:%M")
1068
+ except Exception as e:
1069
+ return f"無效的日期格式: {str(e)}"
1070
+
1071
  def get_chinese_paragraph_practice_log_session_content(file_name):
1072
  if file_name:
1073
  content = GCS_SERVICE.download_as_string("jutor_logs", file_name)
 
1081
  chinese_full_paragraph_refine_output_table_history = pd.DataFrame(content_json["chinese_full_paragraph_refine_output_table"]) if "chinese_full_paragraph_refine_output_table" in content_json else pd.DataFrame()
1082
  chinese_full_paragraph_save_output_history = content_json["chinese_full_paragraph_save_output"] if "chinese_full_paragraph_save_output" in content_json else ""
1083
 
1084
+ # 作業模式
1085
  assignment_id = content_json["assignment_id"] if "assignment_id" in content_json else ""
1086
+ chinese_assignment_content = gr.update(visible=False)
1087
+ chinese_assignment_grade = ""
1088
+ chinese_assignment_topic = ""
1089
+ chinese_assignment_introduction = ""
1090
+ chinese_assignment_description = ""
1091
+ chinese_assignment_submission_deadline = ""
1092
+
1093
  if assignment_id:
 
1094
  chinese_assignment_content = gr.update(visible=True)
1095
+ try:
1096
+ assignment = get_assignment_content(assignment_id)
1097
+ chinese_assignment_grade = assignment["metadata"]["grade"]
1098
+ chinese_assignment_topic = assignment["metadata"]["topic"]
1099
+ chinese_assignment_introduction = assignment["metadata"]["introduction"]
1100
+ chinese_assignment_description = assignment["metadata"]["description"]
1101
+ submission_deadline = assignment["metadata"]["submission_deadline"]
1102
+ chinese_assignment_submission_deadline = get_assignment_formatted_deadline(submission_deadline)
1103
+ except Exception as e:
1104
+ print(f"Error: {e}")
1105
+ chinese_assignment_grade = "作業已刪除"
1106
+ chinese_assignment_topic = "作業已刪除"
1107
+ chinese_assignment_introduction = "作業已刪除"
1108
+ chinese_assignment_description = "作業已刪除"
1109
+ chinese_assignment_submission_deadline = "作業已刪除"
1110
  else:
1111
  chinese_full_paragraph_input_history = ""
1112
  chinese_full_paragraph_evaluate_output_text_history = ""
 
1121
  chinese_assignment_topic = ""
1122
  chinese_assignment_introduction = ""
1123
  chinese_assignment_description = ""
1124
+ chinese_assignment_submission_deadline = ""
1125
 
1126
  return chinese_full_paragraph_input_history, \
1127
  chinese_full_paragraph_evaluate_output_text_history, \
 
1134
  chinese_assignment_grade, \
1135
  chinese_assignment_topic, \
1136
  chinese_assignment_introduction, \
1137
+ chinese_assignment_description, \
1138
+ chinese_assignment_submission_deadline
1139
 
1140
 
1141
  # === OpenAI Assistant ===
 
1630
  chinese_assignment_topic = gr.update(value=assignment_json_value.get("metadata", {}).get("topic", ""))
1631
  chinese_assignment_introduction = gr.update(value=assignment_json_value.get("metadata", {}).get("introduction", ""))
1632
  chinese_assignment_description = gr.update(value=assignment_json_value.get("metadata", {}).get("description", ""))
1633
+ submission_deadline = assignment_json_value.get("metadata", {}).get("submission_deadline", "")
1634
+ # submission_deadline 轉成 y-m-d H:M
1635
+ submission_deadline_value = submission_deadline_value = get_assignment_formatted_deadline(submission_deadline)
1636
+ chinese_assignment_submission_deadline = gr.update(value=submission_deadline_value)
1637
+
1638
+ print(f"chinese_assignment_submission_deadline: {chinese_assignment_submission_deadline}")
1639
  else:
1640
  chinese_assignment_row = gr.update(visible=False)
1641
  chinese_assignment_grade = gr.update(value="")
1642
  chinese_assignment_topic = gr.update(value="")
1643
  chinese_assignment_introduction = gr.update(value="")
1644
  chinese_assignment_description = gr.update(value="")
1645
+ chinese_assignment_submission_deadline = gr.update(value="")
1646
 
1647
  assignment_id_input = gr.update(value=assignment_id_value)
1648
  assignment_json = gr.update(value=assignment_json_value)
 
1653
  chinese_assignment_topic = gr.update(value="")
1654
  chinese_assignment_introduction = gr.update(value="")
1655
  chinese_assignment_description = gr.update(value="")
1656
+ chinese_assignment_submission_deadline = gr.update(value="")
1657
  assignment_id_input = gr.update(value=None)
1658
  assignment_json = gr.update(value=None)
1659
 
1660
  return user_data, \
1661
  admin_group, session_timestamp, request_origin, \
1662
  assignment_id_input, assignment_json, \
1663
+ chinese_assignment_row, \
1664
+ chinese_assignment_grade, \
1665
+ chinese_assignment_topic, \
1666
+ chinese_assignment_introduction, \
1667
+ chinese_assignment_description, \
1668
+ chinese_assignment_submission_deadline, \
1669
  english_group, chinese_group, assignment_group
1670
 
1671
  CSS = """
 
3244
  chinese_assignment_topic = gr.Textbox(label="主題", interactive=False)
3245
  chinese_assignment_introduction = gr.Textbox(label="寫作引文", interactive=False)
3246
  chinese_assignment_description = gr.Textbox(label="作業說明", interactive=False)
3247
+ chinese_assignment_submission_deadline = gr.Textbox(label="截止日期", interactive=False)
3248
 
3249
  # =====中文全文批改=====
3250
  with gr.Tab("中文全文批改") as chinese_full_paragraph_tab:
 
3515
  chinese_assignment_introduction_history_log = gr.Markdown()
3516
  gr.Markdown("<span style='color:#4e80ee'>作業說明</span>")
3517
  chinese_assignment_description_history_log = gr.Markdown()
3518
+ gr.Markdown("<span style='color:#4e80ee'>作業繳交截止時間</span>")
3519
+ chinese_assignment_submission_deadline_history_log = gr.Markdown()
3520
 
3521
  gr.Markdown("---")
3522
  gr.Markdown("# 回傳作業內容")
 
3560
  chinese_assignment_grade_history_log,
3561
  chinese_assignment_topic_history_log,
3562
  chinese_assignment_introduction_history_log,
3563
+ chinese_assignment_description_history_log,
3564
+ chinese_assignment_submission_deadline_history_log
3565
  ]
3566
  )
3567
 
 
3641
  chinese_assignment_topic,
3642
  chinese_assignment_introduction,
3643
  chinese_assignment_description,
3644
+ chinese_assignment_submission_deadline,
3645
  english_group,
3646
  chinese_group,
3647
  assignment_group
assignment_service.py CHANGED
@@ -19,7 +19,11 @@ class AssignmentService:
19
  return assignment_id
20
 
21
  def create_assignment_metadata(self, assignment_type, grade, topic, introduction, description, attach_materials, submission_deadline):
22
- # if assignment_type == ["中文寫作 AI 批改", "英文寫作 AI 批改"]:
 
 
 
 
23
  metadata = {
24
  "assignment_type": assignment_type,
25
  "grade": grade,
@@ -135,5 +139,23 @@ class AssignmentService:
135
  return gr.update(choices=choices)
136
 
137
 
138
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
 
19
  return assignment_id
20
 
21
  def create_assignment_metadata(self, assignment_type, grade, topic, introduction, description, attach_materials, submission_deadline):
22
+ # submission_deadline is Unix timestamp (seconds)
23
+ # convert to ISO format with timezone, example: 2024-06-01T00:00:00+08:00
24
+ taipei_tz = pytz.timezone('Asia/Taipei')
25
+ submission_deadline = datetime.fromtimestamp(submission_deadline, tz=taipei_tz).isoformat()
26
+
27
  metadata = {
28
  "assignment_type": assignment_type,
29
  "grade": grade,
 
139
  return gr.update(choices=choices)
140
 
141
 
142
+ def delete_assignment(self, assignment_id, user_data):
143
+ try:
144
+ # 刪除作業文件
145
+ file_name = f"assignments/{assignment_id}.json"
146
+ if not self.gcs_service.delete_file(self.bucket_name, file_name):
147
+ raise Exception("Failed to delete assignment file")
148
+
149
+ # 從用戶的作業列表中刪除
150
+ user_assignments = self.get_user_assignments(user_data)
151
+ if assignment_id in user_assignments:
152
+ del user_assignments[assignment_id]
153
+ encoded_user_id_url = urllib.parse.quote(user_data, safe='')
154
+ self.gcs_service.upload_json_string(self.bucket_name, f"users/{encoded_user_id_url}/assignments.json", json.dumps(user_assignments))
155
+
156
+ return True
157
+ except Exception as e:
158
+ print(f"Error deleting assignment: {e}")
159
+ return False
160
+
161
 
assignment_ui.py CHANGED
@@ -1,4 +1,5 @@
1
  import gradio as gr
 
2
 
3
  def create_assignment_ui(user_data, assignment_service, submission_service):
4
  with gr.Blocks() as assignment_interface:
@@ -13,7 +14,7 @@ def create_assignment_ui(user_data, assignment_service, submission_service):
13
  "中文寫作 AI 批改",
14
  "英文寫作 AI 批改"
15
  ]
16
- assignment_type = gr.Radio(choices=assignment_type_list, label="選擇類型")
17
  assignment_grade = gr.Radio(["一年級", "二年級", "三年級", "四年級", "五年級", "六年級"], label="選擇年級", visible=False)
18
  with gr.Row():
19
  gr.Markdown("### 內容規範")
@@ -24,7 +25,7 @@ def create_assignment_ui(user_data, assignment_service, submission_service):
24
  gr.Markdown("### 繳交規範")
25
  with gr.Row():
26
  assignment_submission_deadline = gr.DateTime(label="提交截止日期")
27
- assignment_attach_materials = gr.Textbox(label="附件參考", placeholder='[{"type": "video", "url": "link1", "description": "描述"}]')
28
  with gr.Row():
29
  assignment_create_button = gr.Button("建立作業")
30
  assignment_metadata = gr.JSON(label="作業元數據", visible=False)
@@ -73,6 +74,37 @@ def create_assignment_ui(user_data, assignment_service, submission_service):
73
  with gr.Column(scale=2):
74
  assignment_data = gr.JSON(label="作業內容", visible=False)
75
  assignment_data_html = gr.HTML()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  with gr.Row():
77
  with gr.Column(scale=1):
78
  submissions_list_json = gr.JSON(visible=False)
@@ -92,6 +124,25 @@ def create_assignment_ui(user_data, assignment_service, submission_service):
92
  return assignment_list, assignment_data, assignment_data_html, submissions_list_json, submissions_list_radio, submission_data_json, submission_data_html
93
 
94
  def update_assignment_data_html(assignment_data):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  html = f"""
96
  <div style="background-color: #f8f9fa; padding: 30px; border-radius: 15px; font-family: 'Helvetica', sans-serif;">
97
  <h2 style="color: #007bff; font-size: 28px; margin-bottom: 20px;">✨ 作業詳情</h2>
@@ -123,6 +174,11 @@ def create_assignment_ui(user_data, assignment_service, submission_service):
123
  <div style="font-weight: bold; color: #17a2b8; margin-bottom: 5px;">🔗 作業連結</div>
124
  <a href="{assignment_data['assignment_url']}" target="_blank" style="display: inline-block; padding: 10px 15px; background-color: #007bff; color: white; text-decoration: none; border-radius: 5px; transition: background-color 0.3s;" onmouseover="this.style.backgroundColor='#0056b3'" onmouseout="this.style.backgroundColor='#007bff'">點擊前往作業</a>
125
  </div>
 
 
 
 
 
126
 
127
  <div>
128
  <div style="font-weight: bold; color: #dc3545; margin-bottom: 5px;">📎 附加材料</div>
@@ -133,6 +189,12 @@ def create_assignment_ui(user_data, assignment_service, submission_service):
133
  """
134
  return gr.update(value=html)
135
 
 
 
 
 
 
 
136
  def update_submissions_list_radio(submission_ids):
137
  choices = []
138
  for submission_id in submission_ids:
@@ -373,6 +435,10 @@ def create_assignment_ui(user_data, assignment_service, submission_service):
373
  fn=init_assignment_list_data,
374
  inputs=[],
375
  outputs=[assignment_list, assignment_data, assignment_data_html, submissions_list_json, submissions_list_radio, submission_data_json, submission_data_html]
 
 
 
 
376
  )
377
 
378
  assignment_list.select(
@@ -395,6 +461,10 @@ def create_assignment_ui(user_data, assignment_service, submission_service):
395
  fn=update_submissions_list_radio,
396
  inputs=[submissions_list_json],
397
  outputs=[submissions_list_radio]
 
 
 
 
398
  )
399
 
400
  submissions_list_radio.select(
@@ -407,48 +477,38 @@ def create_assignment_ui(user_data, assignment_service, submission_service):
407
  outputs=[submission_data_html]
408
  )
409
 
410
- # with gr.Tab("生|模擬繳交"):
411
- # with gr.Row():
412
- # with gr.Column():
413
- # assignment_id_input_student = gr.Textbox(label="作業 ID")
414
- # get_assignment_button = gr.Button("獲取作業")
415
- # assignment_display = gr.JSON(label="作業內容")
416
-
417
- # get_assignment_button.click(
418
- # assignment_service.get_assignment,
419
- # inputs=[assignment_id_input_student],
420
- # outputs=assignment_display
421
- # )
422
-
423
- # with gr.Row():
424
- # with gr.Column():
425
- # student_name_input = gr.Textbox(label="學生姓名")
426
- # submission_input = gr.Textbox(label="文字輸入")
427
- # submit_button = gr.Button("繳交作業")
428
- # submission_status = gr.Textbox(label="繳交狀態", interactive=False)
429
-
430
- # submit_button.click(
431
- # submission_service.submit_assignment,
432
- # inputs=[assignment_id_input_student, user_data, student_name_input, submission_input],
433
- # outputs=submission_status
434
- # )
435
-
436
- # with gr.Row():
437
- # with gr.Column():
438
- # load_submissions_button = gr.Button("獲取提交的作業")
439
- # submissions_radio = gr.Radio([], label="提交的作業", interactive=True)
440
- # submission_display = gr.JSON(label="作業內容")
441
-
442
- # load_submissions_button.click(
443
- # submission_service.update_submission_list,
444
- # inputs=[user_data],
445
- # outputs=submissions_radio
446
- # )
447
-
448
- # submissions_radio.select(
449
- # submission_service.get_submission_from_gcs,
450
- # inputs=[submissions_radio],
451
- # outputs=submission_display
452
- # )
453
 
454
  return assignment_interface
 
1
  import gradio as gr
2
+ from datetime import datetime
3
 
4
  def create_assignment_ui(user_data, assignment_service, submission_service):
5
  with gr.Blocks() as assignment_interface:
 
14
  "中文寫作 AI 批改",
15
  "英文寫作 AI 批改"
16
  ]
17
+ assignment_type = gr.Radio(choices=assignment_type_list, label="選擇類型", value="中文寫作 AI 批改")
18
  assignment_grade = gr.Radio(["一年級", "二年級", "三年級", "四年級", "五年級", "六年級"], label="選擇年級", visible=False)
19
  with gr.Row():
20
  gr.Markdown("### 內容規範")
 
25
  gr.Markdown("### 繳交規範")
26
  with gr.Row():
27
  assignment_submission_deadline = gr.DateTime(label="提交截止日期")
28
+ assignment_attach_materials = gr.Textbox(label="附件參考", placeholder='[{"type": "video", "url": "link1", "description": "描述"}]', visible=False)
29
  with gr.Row():
30
  assignment_create_button = gr.Button("建立作業")
31
  assignment_metadata = gr.JSON(label="作業元數據", visible=False)
 
74
  with gr.Column(scale=2):
75
  assignment_data = gr.JSON(label="作業內容", visible=False)
76
  assignment_data_html = gr.HTML()
77
+ delete_assignment_button = gr.Button("刪除此作業", visible=False, variant="stop")
78
+ with gr.Row(visible=False) as check_delete_confirmation_row:
79
+ delete_assignment_execute_button = gr.Button(visible=True, value="⚠️ 警告:刪除作業將永久移除此作業相關數據。請將確認框打勾即可點擊刪除。", interactive=False)
80
+ delete_confirm = gr.Checkbox(label="我確認要刪除這個作業", visible=True)
81
+ delete_warning = gr.Markdown(visible=True)
82
+
83
+ def show_delete_confirmation():
84
+ check_delete_confirmation_row = gr.update(visible=True)
85
+ return check_delete_confirmation_row
86
+
87
+ def init_check_delete_confirmation_row():
88
+ check_delete_confirmation_row = gr.update(visible=False)
89
+ delete_confirm = gr.update(value=False)
90
+ delete_warning = gr.update(value="")
91
+ return check_delete_confirmation_row, delete_confirm, delete_warning
92
+
93
+ def check_delete_confirmation(confirmed):
94
+ if confirmed:
95
+ delete_assignment_execute_button = gr.update(interactive=True)
96
+ else:
97
+ delete_assignment_execute_button = gr.update(interactive=False)
98
+
99
+ return delete_assignment_execute_button
100
+
101
+ def delete_assignment(assignment_id, user_data):
102
+ success = assignment_service.delete_assignment(assignment_id, user_data)
103
+ if success:
104
+ return gr.update(value="作業已成功刪除"), gr.update(value=None), gr.update(value=None), gr.update(choices=[]), gr.update(value=None), gr.update(value=None)
105
+ else:
106
+ return gr.update(value="刪除作業失敗,請稍後再試"), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
107
+
108
  with gr.Row():
109
  with gr.Column(scale=1):
110
  submissions_list_json = gr.JSON(visible=False)
 
124
  return assignment_list, assignment_data, assignment_data_html, submissions_list_json, submissions_list_radio, submission_data_json, submission_data_html
125
 
126
  def update_assignment_data_html(assignment_data):
127
+ # 處理 submission_deadline
128
+ submission_deadline = assignment_data['metadata'].get('submission_deadline')
129
+ formatted_deadline = "未設置截止日期"
130
+
131
+ if submission_deadline is not None:
132
+ try:
133
+ if isinstance(submission_deadline, (int, float)):
134
+ # 假設這是一個 Unix 時間戳(秒)
135
+ submission_datetime = datetime.fromtimestamp(submission_deadline)
136
+ elif isinstance(submission_deadline, str):
137
+ # 嘗試解析 ISO 格式的字串
138
+ submission_datetime = datetime.fromisoformat(submission_deadline)
139
+ else:
140
+ raise ValueError(f"無效的日期類型: {type(submission_deadline)}")
141
+
142
+ formatted_deadline = submission_datetime.strftime("%Y-%m-%d %H:%M")
143
+ except ValueError as e:
144
+ formatted_deadline = f"無效的日期格式: {str(e)}"
145
+
146
  html = f"""
147
  <div style="background-color: #f8f9fa; padding: 30px; border-radius: 15px; font-family: 'Helvetica', sans-serif;">
148
  <h2 style="color: #007bff; font-size: 28px; margin-bottom: 20px;">✨ 作業詳情</h2>
 
174
  <div style="font-weight: bold; color: #17a2b8; margin-bottom: 5px;">🔗 作業連結</div>
175
  <a href="{assignment_data['assignment_url']}" target="_blank" style="display: inline-block; padding: 10px 15px; background-color: #007bff; color: white; text-decoration: none; border-radius: 5px; transition: background-color 0.3s;" onmouseover="this.style.backgroundColor='#0056b3'" onmouseout="this.style.backgroundColor='#007bff'">點擊前往作業</a>
176
  </div>
177
+
178
+ <div style="margin-bottom: 20px;">
179
+ <div style="font-weight: bold; color: #17a2b8; margin-bottom: 5px;">🔗 作業截止日期</div>
180
+ <div style="background-color: #f8f9fa; padding: 10px 15px; border-radius: 5px;">{formatted_deadline}</div>
181
+ </div>
182
 
183
  <div>
184
  <div style="font-weight: bold; color: #dc3545; margin-bottom: 5px;">📎 附加材料</div>
 
189
  """
190
  return gr.update(value=html)
191
 
192
+ def show_button():
193
+ return gr.update(visible=True)
194
+
195
+ def hide_button():
196
+ return gr.update(visible=False)
197
+
198
  def update_submissions_list_radio(submission_ids):
199
  choices = []
200
  for submission_id in submission_ids:
 
435
  fn=init_assignment_list_data,
436
  inputs=[],
437
  outputs=[assignment_list, assignment_data, assignment_data_html, submissions_list_json, submissions_list_radio, submission_data_json, submission_data_html]
438
+ ).then(
439
+ fn=hide_button,
440
+ inputs=[],
441
+ outputs=[delete_assignment_button]
442
  )
443
 
444
  assignment_list.select(
 
461
  fn=update_submissions_list_radio,
462
  inputs=[submissions_list_json],
463
  outputs=[submissions_list_radio]
464
+ ).then(
465
+ fn=show_button,
466
+ inputs=[],
467
+ outputs=[delete_assignment_button]
468
  )
469
 
470
  submissions_list_radio.select(
 
477
  outputs=[submission_data_html]
478
  )
479
 
480
+ delete_assignment_button.click(
481
+ fn=hide_button,
482
+ inputs=[],
483
+ outputs=[delete_assignment_button]
484
+ ).then(
485
+ fn=show_delete_confirmation,
486
+ inputs=[],
487
+ outputs=[check_delete_confirmation_row]
488
+ )
489
+
490
+ delete_confirm.change(
491
+ fn=check_delete_confirmation,
492
+ inputs=[delete_confirm],
493
+ outputs=[delete_assignment_execute_button]
494
+ )
495
+
496
+ delete_assignment_execute_button.click(
497
+ fn=delete_assignment,
498
+ inputs=[assignment_list, user_data],
499
+ outputs=[assignment_data_html, assignment_data, submissions_list_json, submissions_list_radio, submission_data_json, submission_data_html]
500
+ ).then(
501
+ fn=init_check_delete_confirmation_row,
502
+ inputs=[],
503
+ outputs=[check_delete_confirmation_row, delete_confirm, delete_warning]
504
+ ).then(
505
+ fn=hide_button,
506
+ inputs=[],
507
+ outputs=[delete_assignment_button]
508
+ ).then(
509
+ assignment_service.update_assignment_list,
510
+ inputs=[user_data],
511
+ outputs=assignment_list
512
+ )
 
 
 
 
 
 
 
 
 
 
513
 
514
  return assignment_interface
storage_service.py CHANGED
@@ -56,4 +56,15 @@ class GoogleCloudStorage:
56
 
57
  def list_files(self, bucket_name, prefix=None):
58
  blobs = self.client.bucket(bucket_name).list_blobs(prefix=prefix)
59
- return [blob.name for blob in blobs]
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
  def list_files(self, bucket_name, prefix=None):
58
  blobs = self.client.bucket(bucket_name).list_blobs(prefix=prefix)
59
+ return [blob.name for blob in blobs]
60
+
61
+ def delete_file(self, bucket_name, file_name):
62
+ try:
63
+ bucket = self.client.bucket(bucket_name)
64
+ blob = bucket.blob(file_name)
65
+ blob.delete()
66
+ print(f"File {file_name} deleted from {bucket_name}")
67
+ return True
68
+ except Exception as e:
69
+ print(f"Error deleting file {file_name} from {bucket_name}: {e}")
70
+ return False