mistpe commited on
Commit
8cd139e
·
verified ·
1 Parent(s): 12b72e1

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +293 -0
app.py ADDED
@@ -0,0 +1,293 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify
2
+ from flask_cors import CORS
3
+ from pymongo import MongoClient
4
+ from bson import ObjectId
5
+ import os
6
+ import oss2
7
+ import bcrypt
8
+ from datetime import datetime, timedelta
9
+ import jwt
10
+ from functools import wraps
11
+ import random
12
+ from dotenv import load_dotenv
13
+
14
+ # 加载 .env 文件中的环境变量
15
+ load_dotenv()
16
+
17
+ app = Flask(__name__)
18
+ CORS(app)
19
+
20
+ # MongoDB configuration
21
+ # 从环境变量中获取 MongoDB 配置信息
22
+ mongo_uri = os.getenv("MONGO_URI")
23
+ client = MongoClient(mongo_uri)
24
+ db = client['stylespace']
25
+
26
+ if 'carts' not in db.list_collection_names():
27
+ db.create_collection('carts')
28
+
29
+ # 从环境变量中获取阿里云 OSS 配置信息
30
+ access_key_id = os.getenv("OSS_ACCESS_KEY_ID")
31
+ access_key_secret = os.getenv("OSS_ACCESS_KEY_SECRET")
32
+ bucket_name = os.getenv("OSS_BUCKET_NAME")
33
+ endpoint = os.getenv("OSS_ENDPOINT")
34
+
35
+
36
+ # Create Aliyun OSS bucket object
37
+ bucket = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket_name)
38
+
39
+ # JWT configuration
40
+ app.config['SECRET_KEY'] = '1234' # Change this to a secure secret key
41
+
42
+ def token_required(f):
43
+ @wraps(f)
44
+ def decorated(*args, **kwargs):
45
+ token = request.headers.get('Authorization')
46
+ if not token:
47
+ print("No token provided")
48
+ return jsonify({'message': 'Token is missing!'}), 401
49
+ try:
50
+ token = token.split(" ")[1] if token.startswith("Bearer ") else token
51
+ data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"])
52
+ current_user = db.users.find_one({'_id': ObjectId(data['user_id'])})
53
+ if not current_user:
54
+ print(f"User not found for id: {data['user_id']}")
55
+ raise jwt.InvalidTokenError
56
+ except jwt.ExpiredSignatureError:
57
+ print("Token has expired")
58
+ return jsonify({'message': 'Token has expired!'}), 401
59
+ except jwt.InvalidTokenError:
60
+ print("Invalid token")
61
+ return jsonify({'message': 'Invalid token!'}), 401
62
+ except Exception as e:
63
+ print(f"Unexpected error: {str(e)}")
64
+ return jsonify({'message': 'Token verification failed!'}), 401
65
+ return f(current_user, *args, **kwargs)
66
+ return decorated
67
+
68
+ @app.route('/api/auth/register', methods=['POST'])
69
+ def register():
70
+ data = request.json
71
+ if db.users.find_one({'username': data['username']}):
72
+ return jsonify({'message': 'Username already exists'}), 400
73
+ if db.users.find_one({'email': data['email']}):
74
+ return jsonify({'message': 'Email already exists'}), 400
75
+ hashed_password = bcrypt.hashpw(data['password'].encode('utf-8'), bcrypt.gensalt())
76
+ user = {
77
+ 'username': data['username'],
78
+ 'email': data['email'],
79
+ 'password': hashed_password,
80
+ 'created_at': datetime.utcnow()
81
+ }
82
+ result = db.users.insert_one(user)
83
+ return jsonify({'message': 'User created successfully', 'id': str(result.inserted_id)}), 201
84
+
85
+ @app.route('/api/auth/login', methods=['POST'])
86
+ def login():
87
+ data = request.json
88
+ user = db.users.find_one({'username': data['username']})
89
+ if user and bcrypt.checkpw(data['password'].encode('utf-8'), user['password']):
90
+ token = jwt.encode(
91
+ {'user_id': str(user['_id']), 'exp': datetime.utcnow() + timedelta(hours=24)},
92
+ app.config['SECRET_KEY'],
93
+ algorithm="HS256"
94
+ )
95
+ return jsonify({'token': token, 'user': {'id': str(user['_id']), 'username': user['username'], 'email': user['email']}}), 200
96
+ return jsonify({'message': 'Invalid username or password'}), 401
97
+
98
+ @app.route('/api/auth/verify-token', methods=['POST'])
99
+ @token_required
100
+ def verify_token(current_user):
101
+ return jsonify({'user': {'id': str(current_user['_id']), 'username': current_user['username'], 'email': current_user['email']}}), 200
102
+
103
+ @app.route('/api/products', methods=['GET'])
104
+ def get_products():
105
+ product_type = request.args.get('type', 'all')
106
+ limit = int(request.args.get('limit', 20))
107
+
108
+ all_products = list(db.products.find())
109
+
110
+ if product_type == 'hot':
111
+ selected_products = random.sample(all_products, min(4, len(all_products)))
112
+ elif product_type == 'new':
113
+ selected_products = random.sample(all_products, min(4, len(all_products)))
114
+ else:
115
+ selected_products = all_products[:limit]
116
+
117
+ result = []
118
+ for product in selected_products:
119
+ result.append({
120
+ '_id': str(product['_id']),
121
+ 'name': product.get('name', 'Unknown Product'),
122
+ 'price': float(product.get('price', 0)),
123
+ 'originalPrice': float(product.get('originalPrice', 0)),
124
+ 'brief': product.get('brief', 'No description available'),
125
+ 'image': product.get('images', [None])[0],
126
+ 'description': product.get('description', ''),
127
+ 'images': product.get('images', []),
128
+ 'sizes': product.get('sizes', [])
129
+ })
130
+
131
+ return jsonify({'data': result}), 200
132
+
133
+ @app.route('/api/products/<product_id>', methods=['GET'])
134
+ def get_product_details(product_id):
135
+ product = db.products.find_one({'_id': ObjectId(product_id)})
136
+ if product:
137
+ product['_id'] = str(product['_id'])
138
+ return jsonify({'data': product}), 200
139
+ return jsonify({'message': 'Product not found'}), 404
140
+
141
+ @app.route('/api/cart', methods=['GET'])
142
+ @token_required
143
+ def get_cart(current_user):
144
+ cart = db.carts.find_one({'user_id': str(current_user['_id'])})
145
+ if cart:
146
+ cart_items = []
147
+ for item in cart['items']:
148
+ product = db.products.find_one({'_id': item['product_id']})
149
+ if product:
150
+ cart_items.append({
151
+ '_id': str(item['_id']),
152
+ 'product_id': str(product['_id']),
153
+ 'name': product['name'],
154
+ 'price': product['price'],
155
+ 'image': product['images'][0] if product['images'] else None,
156
+ 'quantity': item['quantity'],
157
+ 'size': item['size']
158
+ })
159
+ return jsonify({'data': cart_items}), 200
160
+ else:
161
+ return jsonify({'data': []}), 200
162
+
163
+ @app.route('/api/cart', methods=['POST'])
164
+ @token_required
165
+ def add_to_cart(current_user):
166
+ data = request.json
167
+ cart = db.carts.find_one({'user_id': str(current_user['_id'])})
168
+ if not cart:
169
+ cart = {
170
+ 'user_id': str(current_user['_id']),
171
+ 'items': []
172
+ }
173
+ result = db.carts.insert_one(cart)
174
+ cart['_id'] = result.inserted_id
175
+
176
+ item = next((item for item in cart['items'] if str(item['product_id']) == data['productId'] and item['size'] == data['size']), None)
177
+ if item:
178
+ item['quantity'] += data['quantity']
179
+ else:
180
+ cart['items'].append({
181
+ '_id': ObjectId(),
182
+ 'product_id': ObjectId(data['productId']),
183
+ 'quantity': data['quantity'],
184
+ 'size': data['size']
185
+ })
186
+
187
+ db.carts.update_one({'_id': cart['_id']}, {'$set': cart})
188
+
189
+ return jsonify({'message': 'Item added to cart successfully'}), 200
190
+
191
+ @app.route('/api/cart/<item_id>', methods=['PUT'])
192
+ @token_required
193
+ def update_cart_item(current_user, item_id):
194
+ data = request.json
195
+ cart = db.carts.find_one({'user_id': str(current_user['_id'])})
196
+ if cart:
197
+ for item in cart['items']:
198
+ if str(item['_id']) == item_id:
199
+ item['quantity'] = data['quantity']
200
+ break
201
+ db.carts.update_one({'_id': cart['_id']}, {'$set': cart})
202
+
203
+ updated_item = next((item for item in cart['items'] if str(item['_id']) == item_id), None)
204
+ if updated_item:
205
+ product = db.products.find_one({'_id': updated_item['product_id']})
206
+ if product:
207
+ return jsonify({
208
+ 'data': {
209
+ '_id': str(updated_item['_id']),
210
+ 'product_id': str(product['_id']),
211
+ 'name': product['name'],
212
+ 'price': product['price'],
213
+ 'image': product['images'][0] if product['images'] else None,
214
+ 'quantity': updated_item['quantity'],
215
+ 'size': updated_item['size']
216
+ }
217
+ }), 200
218
+
219
+ return jsonify({'message': 'Cart item updated successfully'}), 200
220
+ return jsonify({'message': 'Cart not found'}), 404
221
+
222
+ @app.route('/api/cart/<item_id>', methods=['DELETE'])
223
+ @token_required
224
+ def remove_from_cart(current_user, item_id):
225
+ cart = db.carts.find_one({'user_id': str(current_user['_id'])})
226
+ if cart:
227
+ cart['items'] = [item for item in cart['items'] if str(item['_id']) != item_id]
228
+ db.carts.update_one({'_id': cart['_id']}, {'$set': cart})
229
+ return jsonify({'message': 'Item removed from cart successfully'}), 200
230
+ return jsonify({'message': 'Cart not found'}), 404
231
+
232
+ @app.route('/api/orders', methods=['POST'])
233
+ @token_required
234
+ def create_order(current_user):
235
+ data = request.json
236
+ order = {
237
+ 'user_id': current_user['_id'],
238
+ 'items': data['items'],
239
+ 'total': data['total'],
240
+ 'status': 'pending',
241
+ 'created_at': datetime.utcnow(),
242
+ 'updated_at': datetime.utcnow()
243
+ }
244
+ result = db.orders.insert_one(order)
245
+ return jsonify({'message': 'Order created successfully', 'order_id': str(result.inserted_id)}), 201
246
+
247
+ @app.route('/api/orders', methods=['GET'])
248
+ @token_required
249
+ def get_orders(current_user):
250
+ orders = list(db.orders.find({'user_id': current_user['_id']}))
251
+ for order in orders:
252
+ order['_id'] = str(order['_id'])
253
+ order['user_id'] = str(order['user_id'])
254
+ for item in order['items']:
255
+ item['product_id'] = str(item['product_id'])
256
+ return jsonify({'data': orders}), 200
257
+
258
+ @app.route('/api/orders/<order_id>', methods=['GET'])
259
+ @token_required
260
+ def get_order_details(current_user, order_id):
261
+ order = db.orders.find_one({'_id': ObjectId(order_id), 'user_id': current_user['_id']})
262
+ if order:
263
+ order['_id'] = str(order['_id'])
264
+ order['user_id'] = str(order['user_id'])
265
+ for item in order['items']:
266
+ item['product_id'] = str(item['product_id'])
267
+ return jsonify({'data': order}), 200
268
+ return jsonify({'message': 'Order not found'}), 404
269
+
270
+ @app.route('/api/upload', methods=['POST'])
271
+ @token_required
272
+ def upload_image(current_user):
273
+ if 'file' not in request.files:
274
+ return jsonify({'message': 'No file part in the request'}), 400
275
+ file = request.files['file']
276
+ if file.filename == '':
277
+ return jsonify({'message': 'No file selected for uploading'}), 400
278
+ if file:
279
+ filename = f"uploads/{datetime.now().strftime('%Y%m%d%H%M%S')}_{file.filename}"
280
+ bucket.put_object(filename, file)
281
+ url = f"https://{bucket_name}.{endpoint}/{filename}"
282
+ return jsonify({'message': 'File uploaded successfully', 'url': url}), 200
283
+
284
+ @app.route('/api/auth/logout', methods=['POST'])
285
+ @token_required
286
+ def logout(current_user):
287
+ # 在这里,我们实际上不需要做太多事情,因为 JWT 是无状态的
288
+ # 客户端只需要删除本地存储的 token 即可
289
+ # 但是,我们可以在这里添加一些额外的逻辑,比如记录用户登出时间等
290
+ return jsonify({'message': 'Successfully logged out'}), 200
291
+
292
+ if __name__ == '__main__':
293
+ app.run(debug=True, port=5000)