euler314 commited on
Commit
0718aa4
·
verified ·
1 Parent(s): 5720959

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -135
app.py CHANGED
@@ -29,149 +29,132 @@ SCOPES = [
29
  'https://www.googleapis.com/auth/drive.file'
30
  ]
31
 
32
- HTML_TEMPLATfrom flask import Flask, request, jsonify, render_template_string, redirect, session
33
- from google_auth_oauthlib.flow import Flow
34
- from google.oauth2.credentials import Credentials
35
- from googleapiclient.discovery import build
36
- from googleapiclient.http import MediaIoBaseUpload
37
- import os
38
- import io
39
- import datetime
40
-
41
- app = Flask(__name__)
42
- app.secret_key = os.environ.get('FLASK_SECRET_KEY')
43
-
44
- SPREADSHEET_ID = '1rcIJflbC1VIc70F6dnASLFvGQ90TXHhCx0iyxsXR7Ww'
45
- FOLDER_ID = '1brmLNqOMCvRS0TDY6ECHvIBmlRx8pcPz'
46
-
47
- # OAuth 2.0 configuration
48
- CLIENT_CONFIG = {
49
- "web": {
50
- "client_id": os.environ.get('GOOGLE_CLIENT_ID'),
51
- "client_secret": os.environ.get('GOOGLE_CLIENT_SECRET'),
52
- "auth_uri": "https://accounts.google.com/o/oauth2/auth",
53
- "token_uri": "https://oauth2.googleapis.com/token",
54
- "redirect_uris": ["https://euler314-purchase-record.hf.space/oauth2callback"]
55
- }
56
- }
57
-
58
- SCOPES = [
59
- 'https://www.googleapis.com/auth/spreadsheets',
60
- 'https://www.googleapis.com/auth/drive.file'
61
- ]
62
 
63
  HTML_TEMPLATE = '''
64
- [Previous HTML template remains the same]
65
- '''
66
-
67
- @app.route('/')
68
- def index():
69
- if 'credentials' not in session:
70
- return redirect('/login')
71
- return render_template_string(HTML_TEMPLATE)
72
-
73
- @app.route('/login')
74
- def login():
75
- flow = Flow.from_client_config(
76
- CLIENT_CONFIG,
77
- scopes=SCOPES,
78
- redirect_uri=CLIENT_CONFIG['web']['redirect_uris'][0]
79
- )
80
- authorization_url, state = flow.authorization_url(
81
- access_type='offline',
82
- include_granted_scopes='true'
83
- )
84
- session['state'] = state
85
- return redirect(authorization_url)
86
-
87
- @app.route('/oauth2callback')
88
- def oauth2callback():
89
- flow = Flow.from_client_config(
90
- CLIENT_CONFIG,
91
- scopes=SCOPES,
92
- state=session['state'],
93
- redirect_uri=CLIENT_CONFIG['web']['redirect_uris'][0]
94
- )
95
-
96
- authorization_response = request.url
97
- flow.fetch_token(authorization_response=authorization_response)
98
-
99
- credentials = flow.credentials
100
- session['credentials'] = {
101
- 'token': credentials.token,
102
- 'refresh_token': credentials.refresh_token,
103
- 'token_uri': credentials.token_uri,
104
- 'client_id': credentials.client_id,
105
- 'client_secret': credentials.client_secret,
106
- 'scopes': credentials.scopes
107
- }
108
-
109
- return redirect('/')
110
-
111
- def get_credentials():
112
- if 'credentials' not in session:
113
- return None
114
- return Credentials(**session['credentials'])
115
-
116
- @app.route('/submit', methods=['POST'])
117
- def submit():
118
- credentials = get_credentials()
119
- if not credentials:
120
- return jsonify({'success': False, 'message': 'Authentication required'})
121
-
122
- try:
123
- name = request.form['name']
124
- student_id = request.form['studentId']
125
- product = request.form['product']
126
- cost = request.form['cost']
127
- file = request.files['receipt']
128
-
129
- # Upload file to Drive
130
- drive_service = build('drive', 'v3', credentials=credentials)
131
-
132
- file_metadata = {
133
- 'name': f"{student_id}_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}_{file.filename}",
134
- 'parents': [FOLDER_ID]
135
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
- media = MediaIoBaseUpload(
138
- io.BytesIO(file.read()),
139
- mimetype=file.content_type,
140
- resumable=True
141
- )
142
 
143
- uploaded_file = drive_service.files().create(
144
- body=file_metadata,
145
- media_body=media,
146
- fields='id,webViewLink'
147
- ).execute()
148
 
149
- file_url = uploaded_file.get('webViewLink', '')
150
-
151
- # Update Google Sheet
152
- sheets_service = build('sheets', 'v4', credentials=credentials)
153
 
154
- timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
155
- ip_address = request.remote_addr
156
-
157
- values = [[name, student_id, product, cost, file_url, timestamp, ip_address]]
158
- body = {'values': values}
159
 
160
- sheets_service.spreadsheets().values().append(
161
- spreadsheetId=SPREADSHEET_ID,
162
- range='Sheet1!A:G',
163
- valueInputOption='USER_ENTERED',
164
- body=body
165
- ).execute()
166
-
167
- return jsonify({'success': True, 'message': 'Data submitted successfully!'})
168
-
169
- except Exception as e:
170
- return jsonify({'success': False, 'message': f'Error: {str(e)}'})
171
-
172
- if __name__ == '__main__':
173
- os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
174
- app.run(host='0.0.0.0', port=7860)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
 
176
  @app.route('/')
177
  def index():
 
29
  'https://www.googleapis.com/auth/drive.file'
30
  ]
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
  HTML_TEMPLATE = '''
34
+ <!DOCTYPE html>
35
+ <html>
36
+ <head>
37
+ <title>Purchase Record Form</title>
38
+ <meta charset="UTF-8">
39
+ <style>
40
+ body {
41
+ font-family: Arial, sans-serif;
42
+ max-width: 600px;
43
+ margin: 20px auto;
44
+ padding: 20px;
45
+ }
46
+ .form-group {
47
+ margin-bottom: 20px;
48
+ }
49
+ label {
50
+ display: block;
51
+ margin-bottom: 8px;
52
+ font-weight: bold;
53
+ }
54
+ input {
55
+ width: 100%;
56
+ padding: 10px;
57
+ border: 1px solid #ddd;
58
+ border-radius: 4px;
59
+ font-size: 16px;
60
+ }
61
+ button {
62
+ background-color: #4CAF50;
63
+ color: white;
64
+ padding: 12px 24px;
65
+ border: none;
66
+ border-radius: 4px;
67
+ cursor: pointer;
68
+ font-size: 16px;
69
+ width: 100%;
70
+ }
71
+ button:hover {
72
+ background-color: #45a049;
73
+ }
74
+ #status {
75
+ margin-top: 20px;
76
+ padding: 15px;
77
+ border-radius: 4px;
78
+ display: none;
79
+ }
80
+ .success {
81
+ background-color: #dff0d8;
82
+ color: #3c763d;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  }
84
+ .error {
85
+ background-color: #f2dede;
86
+ color: #a94442;
87
+ }
88
+ </style>
89
+ </head>
90
+ <body>
91
+ <h2>購買記錄表單 Purchase Record Form</h2>
92
+ <form id="purchaseForm">
93
+ <div class="form-group">
94
+ <label for="name">姓名 Name:</label>
95
+ <input type="text" id="name" name="name" required>
96
+ </div>
97
 
98
+ <div class="form-group">
99
+ <label for="studentId">學號 Student ID:</label>
100
+ <input type="text" id="studentId" name="studentId" required>
101
+ </div>
 
102
 
103
+ <div class="form-group">
104
+ <label for="product">購買商品 Product:</label>
105
+ <input type="text" id="product" name="product" required>
106
+ </div>
 
107
 
108
+ <div class="form-group">
109
+ <label for="cost">金額 Cost:</label>
110
+ <input type="number" id="cost" name="cost" required>
111
+ </div>
112
 
113
+ <div class="form-group">
114
+ <label for="receipt">發票 Receipt:</label>
115
+ <input type="file" id="receipt" name="receipt" accept="image/*,.pdf" required>
116
+ </div>
 
117
 
118
+ <button type="submit">提交 Submit</button>
119
+ </form>
120
+ <div id="status"></div>
121
+
122
+ <script>
123
+ document.getElementById('purchaseForm').addEventListener('submit', async (e) => {
124
+ e.preventDefault();
125
+
126
+ const status = document.getElementById('status');
127
+ status.style.display = 'block';
128
+ status.textContent = '提交中... Submitting...';
129
+ status.className = '';
130
+
131
+ const formData = new FormData(e.target);
132
+
133
+ try {
134
+ const response = await fetch('/submit', {
135
+ method: 'POST',
136
+ body: formData
137
+ });
138
+
139
+ const result = await response.json();
140
+
141
+ if (result.success) {
142
+ status.className = 'success';
143
+ status.textContent = '提交成功! ' + result.message;
144
+ e.target.reset();
145
+ } else {
146
+ status.className = 'error';
147
+ status.textContent = '錯誤:' + result.message;
148
+ }
149
+ } catch (error) {
150
+ status.className = 'error';
151
+ status.textContent = '提交錯誤 Error submitting form';
152
+ }
153
+ });
154
+ </script>
155
+ </body>
156
+ </html>
157
+ '''
158
 
159
  @app.route('/')
160
  def index():