DeepLearning101 commited on
Commit
b634ffe
·
verified ·
1 Parent(s): 6539233

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -27
app.py CHANGED
@@ -5,7 +5,7 @@ import requests
5
  from supabase import create_client, Client
6
  from datetime import datetime, timedelta, timezone
7
 
8
- # ✅ 補回:設定台北時區
9
  TAIPEI_TZ = timezone(timedelta(hours=8))
10
 
11
  # --- 設定 ---
@@ -13,6 +13,7 @@ SUPABASE_URL = os.getenv("SUPABASE_URL")
13
  SUPABASE_KEY = os.getenv("SUPABASE_KEY")
14
  GAS_MAIL_URL = os.getenv("GAS_MAIL_URL")
15
  LINE_ACCESS_TOKEN = os.getenv("LINE_ACCESS_TOKEN")
 
16
  PUBLIC_SPACE_URL = "https://deeplearning101-ciecietaipei.hf.space"
17
 
18
  supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
@@ -36,39 +37,141 @@ def send_confirmation_hybrid(booking_id):
36
  email, user_id = booking.get('email'), booking.get('user_id')
37
  log_msg = ""
38
 
 
39
  confirm_link = f"{PUBLIC_SPACE_URL}/?id={booking_id}&action=confirm"
40
  cancel_link = f"{PUBLIC_SPACE_URL}/?id={booking_id}&action=cancel"
41
 
42
- # 1. Email 發送
 
 
43
  if email and "@" in email:
44
- html = f"""
45
- <div style="padding:20px; background:#111; color:#d4af37; border-radius:10px; max-width:600px; margin:0 auto; font-family:sans-serif;">
46
- <h2 style="border-bottom:1px solid #d4af37; padding-bottom:15px; text-align:center;">Cié Cié Taipei</h2>
47
- <p>{booking['name']} 您好,已為您保留座位:</p>
48
- <div style="background:#222; padding:15px; border-radius:8px;">
49
- <ul style="color:#eee; list-style:none; padding:0; margin:0; line-height:1.8;">
50
- <li>📅 {booking['date']} | {booking['time']}</li>
51
- <li>👥 {booking['pax']} 位</li>
52
- <li>📝 {booking.get('remarks') or '無'}</li>
53
- </ul>
54
- </div>
55
- <div style="text-align:center; margin-top:25px;">
56
- <a href="{confirm_link}" style="background:#d4af37; color:#000; padding:12px 25px; text-decoration:none; border-radius:5px; margin:0 10px; font-weight:bold;">✅ 確認出席</a>
57
- <a href="{cancel_link}" style="border:1px solid #ff5252; color:#ff5252; padding:11px 24px; text-decoration:none; border-radius:5px; margin:0 10px; font-weight:bold;">🚫 取消</a>
 
 
 
 
 
 
 
 
 
 
 
 
58
  </div>
59
- </div>
60
- """
61
- requests.post(GAS_MAIL_URL, json={"to": email, "subject": f"[{booking['date']}] 訂位確認", "htmlBody": html, "name": "Cié Cié Taipei"})
62
- log_msg += f"✅ Email ok "
 
63
 
64
- # 2. LINE 發送
65
- if user_id and len(str(user_id)) > 10 and LINE_ACCESS_TOKEN:
 
 
 
 
 
 
66
  try:
67
- line_msg = f"【訂位確認】{booking['name']} 您好\n已為您保留 {booking['date']} {booking['time']} ({booking['pax']}位)。\n\n如需取消請直接回覆,或點擊 Email 中的連結。期待您的光臨!"
68
- requests.post("https://api.line.me/v2/bot/message/push", headers={"Authorization": f"Bearer {LINE_ACCESS_TOKEN}", "Content-Type": "application/json"}, json={"to": user_id, "messages": [{"type": "text", "text": line_msg}]})
69
- log_msg += "| ✅ LINE ok"
70
- except: log_msg += "| ❌ LINE fail"
71
- else: log_msg += "| ℹ️ No LINE ID"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
  supabase.table("bookings").update({"status": "已發確認信"}).eq("id", booking_id).execute()
74
  return log_msg
 
5
  from supabase import create_client, Client
6
  from datetime import datetime, timedelta, timezone
7
 
8
+ # 設定台北時區
9
  TAIPEI_TZ = timezone(timedelta(hours=8))
10
 
11
  # --- 設定 ---
 
13
  SUPABASE_KEY = os.getenv("SUPABASE_KEY")
14
  GAS_MAIL_URL = os.getenv("GAS_MAIL_URL")
15
  LINE_ACCESS_TOKEN = os.getenv("LINE_ACCESS_TOKEN")
16
+ # ⚠️ 請確認這是您 Space A 的正確網址 (結尾不要有斜線)
17
  PUBLIC_SPACE_URL = "https://deeplearning101-ciecietaipei.hf.space"
18
 
19
  supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
 
37
  email, user_id = booking.get('email'), booking.get('user_id')
38
  log_msg = ""
39
 
40
+ # 產生確認連結
41
  confirm_link = f"{PUBLIC_SPACE_URL}/?id={booking_id}&action=confirm"
42
  cancel_link = f"{PUBLIC_SPACE_URL}/?id={booking_id}&action=cancel"
43
 
44
+ # ---------------------------------------------------------
45
+ # 1. Email 發送 (改良版:使用 Table 排版,解決跑版問題)
46
+ # ---------------------------------------------------------
47
  if email and "@" in email:
48
+ try:
49
+ html = f"""
50
+ <div style="padding: 20px; background: #111; color: #d4af37; border-radius: 10px; max-width: 600px; margin: 0 auto; font-family: sans-serif;">
51
+ <h2 style="border-bottom: 1px solid #d4af37; padding-bottom: 15px; text-align: center; letter-spacing: 2px;">Cié Cié Taipei</h2>
52
+ <p style="font-size: 16px; margin-top: 20px; color: #eee;">{booking['name']} 您好,已為您保留座位:</p>
53
+
54
+ <div style="background: #222; padding: 15px; border-radius: 8px; margin: 20px 0; border-left: 4px solid #d4af37;">
55
+ <ul style="color: #eee; list-style: none; padding: 0; margin: 0; line-height: 2;">
56
+ <li>📅 日期:<strong style="color:#fff;">{booking['date']}</strong></li>
57
+ <li>⏰ 時間:<strong style="color:#fff;">{booking['time']}</strong></li>
58
+ <li>👥 人數:<strong style="color:#fff;">{booking['pax']} 位</strong></li>
59
+ <li>📝 備註:{booking.get('remarks') or '無'}</li>
60
+ </ul>
61
+ </div>
62
+
63
+ <table width="100%" border="0" cellspacing="0" cellpadding="0">
64
+ <tr>
65
+ <td align="center">
66
+ <a href="{confirm_link}" style="display: inline-block; background: #d4af37; color: #000; padding: 12px 30px; text-decoration: none; border-radius: 5px; font-weight: bold; margin-right: 10px;">✅ 確認出席</a>
67
+ <a href="{cancel_link}" style="display: inline-block; border: 1px solid #ff5252; color: #ff5252; padding: 11px 29px; text-decoration: none; border-radius: 5px; font-weight: bold; margin-left: 10px;">🚫 取消</a>
68
+ </td>
69
+ </tr>
70
+ </table>
71
+
72
+ <hr style="border: 0; border-top: 1px solid #333; margin-top: 30px;">
73
+ <p style="color: #666; font-size: 12px; text-align: center;">如需更改,請直接回覆此信件。</p>
74
  </div>
75
+ """
76
+ requests.post(GAS_MAIL_URL, json={"to": email, "subject": f"[{booking['date']}] 訂位確認 - Cié Cié Taipei", "htmlBody": html, "name": "Cié Cié Taipei"})
77
+ log_msg += f" Email ok "
78
+ except Exception as e:
79
+ log_msg += f"⚠️ Email 失敗: {e} "
80
 
81
+ # ---------------------------------------------------------
82
+ # 2. LINE 發送 (升級版:Flex Message 卡片按鈕)
83
+ # ---------------------------------------------------------
84
+ if not LINE_ACCESS_TOKEN:
85
+ log_msg += "| ⚠️ 未設定 LINE_ACCESS_TOKEN"
86
+ elif not user_id or len(str(user_id)) < 10:
87
+ log_msg += "| ℹ️ 無 LINE ID"
88
+ else:
89
  try:
90
+ # 定義 Flex Message 內容
91
+ flex_payload = {
92
+ "type": "flex",
93
+ "altText": "您有一筆訂位確認通知",
94
+ "contents": {
95
+ "type": "bubble",
96
+ "styles": { "header": {"backgroundColor": "#222222"}, "body": {"backgroundColor": "#2c2c2c"}, "footer": {"backgroundColor": "#2c2c2c"} },
97
+ "header": {
98
+ "type": "box",
99
+ "layout": "vertical",
100
+ "contents": [
101
+ {"type": "text", "text": "Cié Cié Taipei", "color": "#d4af37", "weight": "bold", "size": "xl", "align": "center"}
102
+ ]
103
+ },
104
+ "body": {
105
+ "type": "box",
106
+ "layout": "vertical",
107
+ "contents": [
108
+ {"type": "text", "text": "訂位確認", "weight": "bold", "size": "lg", "color": "#ffffff", "align": "center", "margin": "md"},
109
+ {"type": "separator", "margin": "lg", "color": "#444444"},
110
+ {"type": "box", "layout": "vertical", "margin": "lg", "spacing": "sm", "contents": [
111
+ {"type": "box", "layout": "baseline", "spacing": "sm", "contents": [
112
+ {"type": "text", "text": "姓名", "color": "#aaaaaa", "size": "sm", "flex": 2},
113
+ {"type": "text", "text": f"{booking['name']}", "wrap": True, "color": "#ffffff", "size": "sm", "flex": 4}
114
+ ]},
115
+ {"type": "box", "layout": "baseline", "spacing": "sm", "contents": [
116
+ {"type": "text", "text": "日期", "color": "#aaaaaa", "size": "sm", "flex": 2},
117
+ {"type": "text", "text": f"{booking['date']}", "wrap": True, "color": "#ffffff", "size": "sm", "flex": 4}
118
+ ]},
119
+ {"type": "box", "layout": "baseline", "spacing": "sm", "contents": [
120
+ {"type": "text", "text": "時間", "color": "#aaaaaa", "size": "sm", "flex": 2},
121
+ {"type": "text", "text": f"{booking['time']}", "wrap": True, "color": "#ffffff", "size": "sm", "flex": 4}
122
+ ]},
123
+ {"type": "box", "layout": "baseline", "spacing": "sm", "contents": [
124
+ {"type": "text", "text": "人數", "color": "#aaaaaa", "size": "sm", "flex": 2},
125
+ {"type": "text", "text": f"{booking['pax']} 位", "wrap": True, "color": "#ffffff", "size": "sm", "flex": 4}
126
+ ]}
127
+ ]}
128
+ ]
129
+ },
130
+ "footer": {
131
+ "type": "box",
132
+ "layout": "vertical",
133
+ "spacing": "sm",
134
+ "contents": [
135
+ {
136
+ "type": "button",
137
+ "style": "primary",
138
+ "color": "#d4af37",
139
+ "height": "sm",
140
+ "action": {
141
+ "type": "uri",
142
+ "label": "✅ 確認出席",
143
+ "uri": confirm_link
144
+ }
145
+ },
146
+ {
147
+ "type": "button",
148
+ "style": "secondary",
149
+ "height": "sm",
150
+ "color": "#aaaaaa",
151
+ "action": {
152
+ "type": "uri",
153
+ "label": "🚫 取消訂位",
154
+ "uri": cancel_link
155
+ }
156
+ }
157
+ ]
158
+ }
159
+ }
160
+ }
161
+
162
+ # 發送請求
163
+ r = requests.post(
164
+ "https://api.line.me/v2/bot/message/push",
165
+ headers={"Authorization": f"Bearer {LINE_ACCESS_TOKEN}", "Content-Type": "application/json"},
166
+ json={"to": user_id, "messages": [flex_payload]}
167
+ )
168
+
169
+ if r.status_code == 200:
170
+ log_msg += "| ✅ LINE Flex ok"
171
+ else:
172
+ log_msg += f"| ❌ LINE 錯誤: {r.text}"
173
+ except Exception as e:
174
+ log_msg += f"| ❌ LINE 例外: {e}"
175
 
176
  supabase.table("bookings").update({"status": "已發確認信"}).eq("id", booking_id).execute()
177
  return log_msg