Spaces:
Running
Running
from flask import Flask, request, jsonify, render_template_string | |
from google.oauth2.credentials import Credentials | |
from googleapiclient.discovery import build | |
from googleapiclient.http import MediaIoBaseUpload | |
import os | |
import io | |
import datetime | |
app = Flask(__name__) | |
SPREADSHEET_ID = '1rcIJflbC1VIc70F6dnASLFvGQ90TXHhCx0iyxsXR7Ww' | |
FOLDER_ID = '1brmLNqOMCvRS0TDY6ECHvIBmlRx8pcPz' | |
# OAuth 2.0 credentials | |
CREDENTIALS = { | |
'token': None, | |
'refresh_token': None, | |
'token_uri': 'https://oauth2.googleapis.com/token', | |
'client_id': os.environ.get('GOOGLE_CLIENT_ID'), | |
'client_secret': os.environ.get('GOOGLE_CLIENT_SECRET'), | |
'scopes': ['https://www.googleapis.com/auth/spreadsheets', | |
'https://www.googleapis.com/auth/drive.file'] | |
} | |
HTML_TEMPLATE = ''' | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Purchase Record Form</title> | |
<meta charset="UTF-8"> | |
<style> | |
body { | |
font-family: Arial, sans-serif; | |
max-width: 600px; | |
margin: 20px auto; | |
padding: 20px; | |
} | |
.form-group { | |
margin-bottom: 20px; | |
} | |
label { | |
display: block; | |
margin-bottom: 8px; | |
font-weight: bold; | |
} | |
input { | |
width: 100%; | |
padding: 10px; | |
border: 1px solid #ddd; | |
border-radius: 4px; | |
font-size: 16px; | |
} | |
button { | |
background-color: #4CAF50; | |
color: white; | |
padding: 12px 24px; | |
border: none; | |
border-radius: 4px; | |
cursor: pointer; | |
font-size: 16px; | |
width: 100%; | |
} | |
button:hover { | |
background-color: #45a049; | |
} | |
#status { | |
margin-top: 20px; | |
padding: 15px; | |
border-radius: 4px; | |
display: none; | |
} | |
.success { | |
background-color: #dff0d8; | |
color: #3c763d; | |
} | |
.error { | |
background-color: #f2dede; | |
color: #a94442; | |
} | |
</style> | |
</head> | |
<body> | |
<h2>購買記錄表單 Purchase Record Form</h2> | |
<form id="purchaseForm"> | |
<div class="form-group"> | |
<label for="name">姓名 Name:</label> | |
<input type="text" id="name" name="name" required> | |
</div> | |
<div class="form-group"> | |
<label for="studentId">學號 Student ID:</label> | |
<input type="text" id="studentId" name="studentId" required> | |
</div> | |
<div class="form-group"> | |
<label for="product">購買商品 Product:</label> | |
<input type="text" id="product" name="product" required> | |
</div> | |
<div class="form-group"> | |
<label for="cost">金額 Cost:</label> | |
<input type="number" id="cost" name="cost" required> | |
</div> | |
<div class="form-group"> | |
<label for="receipt">發票 Receipt:</label> | |
<input type="file" id="receipt" name="receipt" accept="image/*,.pdf" required> | |
</div> | |
<button type="submit">提交 Submit</button> | |
</form> | |
<div id="status"></div> | |
<script> | |
document.getElementById('purchaseForm').addEventListener('submit', async (e) => { | |
e.preventDefault(); | |
const status = document.getElementById('status'); | |
status.style.display = 'block'; | |
status.textContent = '提交中... Submitting...'; | |
status.className = ''; | |
const formData = new FormData(e.target); | |
try { | |
const response = await fetch('/submit', { | |
method: 'POST', | |
body: formData | |
}); | |
const result = await response.json(); | |
if (result.success) { | |
status.className = 'success'; | |
status.textContent = '提交成功! ' + result.message; | |
e.target.reset(); | |
} else { | |
status.className = 'error'; | |
status.textContent = '錯誤:' + result.message; | |
} | |
} catch (error) { | |
status.className = 'error'; | |
status.textContent = '提交錯誤 Error submitting form'; | |
} | |
}); | |
</script> | |
</body> | |
</html> | |
''' | |
def index(): | |
return render_template_string(HTML_TEMPLATE) | |
def submit(): | |
try: | |
name = request.form['name'] | |
student_id = request.form['studentId'] | |
product = request.form['product'] | |
cost = request.form['cost'] | |
file = request.files['receipt'] | |
credentials = Credentials.from_authorized_user_info(CREDENTIALS) | |
# Upload file to Drive | |
drive_service = build('drive', 'v3', credentials=credentials) | |
file_metadata = { | |
'name': f"{student_id}_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}_{file.filename}", | |
'parents': [FOLDER_ID] | |
} | |
media = MediaIoBaseUpload( | |
io.BytesIO(file.read()), | |
mimetype=file.content_type, | |
resumable=True | |
) | |
uploaded_file = drive_service.files().create( | |
body=file_metadata, | |
media_body=media, | |
fields='id,webViewLink' | |
).execute() | |
file_url = uploaded_file.get('webViewLink', '') | |
# Update Google Sheet | |
sheets_service = build('sheets', 'v4', credentials=credentials) | |
timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') | |
ip_address = request.remote_addr | |
values = [[name, student_id, product, cost, file_url, timestamp, ip_address]] | |
body = {'values': values} | |
sheets_service.spreadsheets().values().append( | |
spreadsheetId=SPREADSHEET_ID, | |
range='Sheet1!A:G', | |
valueInputOption='USER_ENTERED', | |
body=body | |
).execute() | |
return jsonify({'success': True, 'message': 'Data submitted successfully!'}) | |
except Exception as e: | |
return jsonify({'success': False, 'message': f'Error: {str(e)}'}) | |
if __name__ == '__main__': | |
app.run(host='0.0.0.0', port=7860) |