commit 1760f36f7b4547c7216e317d2685a01cea14b5a7
Author: superlishunqin <852326703@qq.com>
Date: Wed Jul 3 03:02:24 2024 +0800
first commit
diff --git a/.env b/.env
new file mode 100644
index 0000000..6b614fa
--- /dev/null
+++ b/.env
@@ -0,0 +1,4 @@
+AWS_ACCESS_KEY_ID=AKIAZQ3DT3KLI6N5LQUM
+AWS_SECRET_ACCESS_KEY=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
+AWS_REGION=ap-northeast-1
+S3_BUCKET_NAME=sure-ae-upload
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..35410ca
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/AWS-sure.iml b/.idea/AWS-sure.iml
new file mode 100644
index 0000000..0ed9eec
--- /dev/null
+++ b/.idea/AWS-sure.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..d44a6a9
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..ec6a681
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..fd71e06
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app.py b/app.py
new file mode 100644
index 0000000..d197057
--- /dev/null
+++ b/app.py
@@ -0,0 +1,182 @@
+from flask import Flask, request, jsonify, send_from_directory, make_response, send_file
+from flask_cors import CORS
+import boto3
+from botocore.exceptions import NoCredentialsError, ClientError, EndpointConnectionError
+import os
+from dotenv import load_dotenv
+import logging
+import datetime
+import pytz
+from botocore.client import Config
+import csv
+import pandas as pd
+
+# 配置日志
+logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
+
+load_dotenv() # 从.env文件加载环境变量
+
+app = Flask(__name__, static_url_path='', static_folder='.')
+CORS(app, resources={r"/*": {"origins": "*", "methods": "GET,POST,PUT,DELETE,OPTIONS"}}) # 添加 CORS 支持
+
+aws_access_key_id = os.getenv('AWS_ACCESS_KEY_ID')
+aws_secret_access_key = os.getenv('AWS_SECRET_ACCESS_KEY')
+region_name = os.getenv('AWS_REGION')
+bucket_name = os.getenv('S3_BUCKET_NAME')
+
+# 打印环境变量 (仅用于调试,生产环境中请移除)
+print(f"AWS_ACCESS_KEY_ID: {aws_access_key_id}")
+print(f"AWS_SECRET_ACCESS_KEY: {'*' * len(aws_secret_access_key) if aws_secret_access_key else 'Not set'}")
+print(f"AWS_REGION: {region_name}")
+print(f"S3_BUCKET_NAME: {bucket_name}")
+
+s3_client = boto3.client(
+ 's3',
+ aws_access_key_id=aws_access_key_id,
+ aws_secret_access_key=aws_secret_access_key,
+ region_name=region_name,
+ config=Config(signature_version='s3v4') # 使用 S3v4 签名版本
+)
+
+# 跟踪学生提交信息
+submissions_file = 'submissions.csv'
+
+# 创建或者加载提交文件
+if not os.path.exists(submissions_file):
+ with open(submissions_file, 'w', newline='') as file:
+ writer = csv.writer(file)
+ writer.writerow(['ID', '学生姓名', '学号', '提交的文件'])
+
+
+def add_submission(student, student_id, filename):
+ with open(submissions_file, 'a', newline='') as file:
+ writer = csv.writer(file)
+ writer.writerow([datetime.datetime.now().isoformat(), student, student_id, filename])
+
+
+def generate_presigned_url(object_key, content_type, expiration=3600):
+ try:
+ current_time = datetime.datetime.now(pytz.UTC)
+ logging.info(f"Current UTC time before generating URL: {current_time}")
+
+ response = s3_client.generate_presigned_url('put_object',
+ Params={
+ 'Bucket': bucket_name,
+ 'Key': object_key,
+ 'ContentType': content_type # 使用实际文件的 Content-Type
+ },
+ ExpiresIn=expiration,
+ HttpMethod='PUT'
+ )
+ logging.info(f"Generated presigned URL: {response}")
+ return response
+ except (NoCredentialsError, ClientError, EndpointConnectionError) as e:
+ logging.error(f"Error generating presigned URL: {str(e)}", exc_info=True)
+ return None
+
+
+@app.route('/generate-url', methods=['GET'])
+def get_presigned_url():
+ student = request.args.get('student')
+ student_id = request.args.get('student_id')
+ filename = request.args.get('filename')
+ content_type = request.args.get('content_type', 'application/octet-stream')
+ logging.info(
+ f"Received request for student: {student}, student_id: {student_id}, filename: {filename}, content_type: {content_type}")
+
+ if not student or not filename or not student_id:
+ logging.warning("Missing student, student_id or filename parameter")
+ return jsonify({'error': 'Student, student_id and filename parameters are required'}), 400
+
+ folder_name = 'sure_homework_define_by_qin'
+ object_key = f'{folder_name}/{student}-{filename}'
+
+ url = generate_presigned_url(object_key, content_type) # 包含 content_type
+ if not url:
+ logging.error("Failed to generate presigned URL")
+ return jsonify({'error': 'Failed to generate presigned URL'}), 500
+
+ add_submission(student, student_id, filename)
+
+ logging.info(f"Generated URL: {url}")
+ return jsonify({'url': url, 'content_type': content_type})
+
+
+@app.route('/')
+def serve_index():
+ return send_from_directory('.', 'index.html')
+
+
+@app.route('/health')
+def health_check():
+ logging.info("Health check initiated")
+ try:
+ local_time = datetime.datetime.now()
+ utc_time = datetime.datetime.now(pytz.UTC)
+ logging.info(f"Local time: {local_time}, UTC time: {utc_time}")
+
+ logging.info("Attempting to list S3 buckets")
+ response = s3_client.list_buckets()
+ logging.info(f"Successfully listed buckets: {[bucket['Name'] for bucket in response['Buckets']]}")
+ return jsonify({
+ 'status': 'healthy',
+ 'message': 'AWS credentials are valid',
+ 'local_time': local_time.isoformat(),
+ 'utc_time': utc_time.isoformat()
+ }), 200
+ except NoCredentialsError:
+ logging.error("AWS credentials not found", exc_info=True)
+ return jsonify({'status': 'unhealthy', 'message': 'AWS credentials not found'}), 500
+ except ClientError as e:
+ error_code = e.response['Error']['Code']
+ error_message = e.response['Error']['Message']
+ logging.error(f"AWS client error: {error_code} - {error_message}", exc_info=True)
+ return jsonify({'status': 'unhealthy', 'message': f'AWS client error: {error_code} - {error_message}'}), 500
+ except Exception as e:
+ logging.error(f"Unexpected error during health check: {str(e)}", exc_info=True)
+ return jsonify({'status': 'unhealthy', 'message': f'Unexpected error: {str(e)}'}), 500
+
+
+@app.route('/download-submissions')
+def download_submissions():
+ df = pd.read_csv(submissions_file)
+ output_file = 'submissions.xlsx'
+ df.to_excel(output_file, index=False)
+ return send_file(output_file, as_attachment=True)
+
+
+@app.before_request
+def before_request_func():
+ if request.method == 'OPTIONS':
+ return _build_cors_preflight_response()
+
+
+def _build_cors_preflight_response():
+ response = make_response()
+ response.headers.add("Access-Control-Allow-Origin", "*")
+ response.headers.add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
+ response.headers.add("Access-Control-Allow-Headers", "Content-Type")
+ return response
+
+
+if __name__ == '__main__':
+ local_time = datetime.datetime.now()
+ utc_time = datetime.datetime.now(pytz.UTC)
+ logging.info(f"Application starting. Local time: {local_time}, UTC time: {utc_time}")
+
+ try:
+ logging.info("Validating AWS credentials on startup")
+ sts = boto3.client('sts',
+ aws_access_key_id=aws_access_key_id,
+ aws_secret_access_key=aws_secret_access_key,
+ region_name=region_name)
+ response = sts.get_caller_identity()
+ logging.info(f"AWS credentials validated successfully. Account ID: {response['Account']}")
+ except Exception as e:
+ logging.error(f"Failed to validate AWS credentials: {str(e)}", exc_info=True)
+ # 如果你想在凭证验证失败时退出程序,取消注释下面两行
+ # import sys
+ # sys.exit(1)
+
+ app.run(debug=True)
+
diff --git a/generate_presigned_url.py b/generate_presigned_url.py
new file mode 100644
index 0000000..5384d61
--- /dev/null
+++ b/generate_presigned_url.py
@@ -0,0 +1,31 @@
+import boto3
+from botocore.exceptions import NoCredentialsError, ClientError
+
+# 使用获取的访问密钥ID和秘密访问密钥来初始化S3客户端
+aws_access_key_id = 'AKIAZQ3DT3KLN5WGXZOR' # 替换为你的访问密钥ID
+aws_secret_access_key = '5UZb8SovTrbroT7yU1pBzaR5myLn+NMA+c87RvLH' # 替换为你的秘密访问密钥
+region_name = 'ap-northeast-1' # 替换为你的S3存储桶所在区域
+
+s3_client = boto3.client(
+ 's3',
+ aws_access_key_id=aws_access_key_id,
+ aws_secret_access_key=aws_secret_access_key,
+ region_name=region_name
+)
+
+# 创建一个模拟“文件夹”的空对象
+def create_s3_folder(bucket_name, folder_name):
+ try:
+ s3_client.put_object(Bucket=bucket_name, Key=(folder_name + '/'))
+ print(f"Folder {folder_name} created in bucket {bucket_name}")
+ except NoCredentialsError:
+ print("Credentials not available")
+ except ClientError as e:
+ print(f"Error: {e}")
+
+# Bucket name and folder name
+bucket_name = 'sure-ae-upload'
+folder_name = 'sure_homework_define_by_qin'
+
+# Create folder
+create_s3_folder(bucket_name, folder_name)
diff --git a/image.jpg b/image.jpg
new file mode 100644
index 0000000..32391fa
Binary files /dev/null and b/image.jpg differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..cf2e1a3
--- /dev/null
+++ b/index.html
@@ -0,0 +1,316 @@
+
+
+
+
+
+ 秀儿文件提交系统
+
+
+
+
+
+

+
+
秀儿文件提交系统
+
+
+
+
+
0%
+
+ 速度: 0 KB/s
+ 0 KB / 0 KB
+ 剩余时间: 计算中
+
+
+
下载统计表格
+
+
+
+
+
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..5b25c56
--- /dev/null
+++ b/main.py
@@ -0,0 +1,16 @@
+# 这是一个示例 Python 脚本。
+
+# 按 ⌃R 执行或将其替换为您的代码。
+# 按 双击 ⇧ 在所有地方搜索类、文件、工具窗口、操作和设置。
+
+
+def print_hi(name):
+ # 在下面的代码行中使用断点来调试脚本。
+ print(f'Hi, {name}') # 按 ⌘F8 切换断点。
+
+
+# 按间距中的绿色按钮以运行脚本。
+if __name__ == '__main__':
+ print_hi('PyCharm')
+
+# 访问 https://www.jetbrains.com/help/pycharm/ 获取 PyCharm 帮助
diff --git a/submissions.csv b/submissions.csv
new file mode 100644
index 0000000..e8c51f5
--- /dev/null
+++ b/submissions.csv
@@ -0,0 +1,13 @@
+ID,学生姓名,学号,提交的文件
+2024-07-02T15:38:06.844568,嗷呜呜汪汪汪钦,12345,fastgpt.txt
+2024-07-03T02:01:37.364487,王中王火腿肠,123,mao.png
+2024-07-03T02:02:02.087326,王中王火腿肠,123,《移动互联开发》软件设计考查材料.rar
+2024-07-03T02:31:23.019179,秀儿,000,SUS 304 Stainless Steel.png
+2024-07-03T02:31:55.184382,秀儿,000,阅读1.pdf
+2024-07-03T02:35:50.030507,嘿!,324,计算机网络_数据链路层.ppt
+2024-07-03T02:37:23.232007,CC,34534,"性学观止 (贺兰特·凯查杜里安, 胡颖翀) (Z-Library).pdf"
+2024-07-03T02:40:42.161975,4324,4234,数学分析 陈纪修 第三版 上 by 陈纪修,于崇华,金路 (z-lib.org).pdf
+2024-07-03T02:42:47.614487,324,4234,男人来自火星,女人来自金星(套装共4册) (约翰·格雷) (Z-Library).pdf
+2024-07-03T02:43:01.033652,534534,543534,数学分析 陈纪修 第三版 上 by 陈纪修,于崇华,金路 (z-lib.org).pdf
+2024-07-03T02:46:15.397526,CCC,AAA,"周易译注 (黄寿祺,张善文) (Z-Library).pdf"
+2024-07-03T02:48:26.189052,2423,423423,阅读1.pdf
diff --git a/submissions.xlsx b/submissions.xlsx
new file mode 100644
index 0000000..1670d24
Binary files /dev/null and b/submissions.xlsx differ
diff --git a/upload_homework.py b/upload_homework.py
new file mode 100644
index 0000000..f5a4049
--- /dev/null
+++ b/upload_homework.py
@@ -0,0 +1,44 @@
+import boto3
+from botocore.exceptions import NoCredentialsError
+
+# 使用访问密钥ID和秘密访问密钥来初始化S3客户端
+aws_access_key_id = 'AKIAZQ3DT3KLN5WGXZOR' # 替换为你的访问密钥ID
+aws_secret_access_key = '5UZb8SovTrbroT7yU1pBzaR5myLn+NMA+c87RvLH' # 替换为你的秘密访问密钥
+region_name = 'ap-northeast-1' # 替换为你的S3存储桶所在区域
+
+s3_client = boto3.client(
+ 's3',
+ aws_access_key_id=aws_access_key_id,
+ aws_secret_access_key=aws_secret_access_key,
+ region_name=region_name
+)
+
+
+def generate_presigned_url(bucket_name, object_key, expiration=3600):
+ try:
+ response = s3_client.generate_presigned_url(
+ 'put_object',
+ Params={
+ 'Bucket': bucket_name,
+ 'Key': object_key,
+ 'ContentType': 'application/pdf' # 设置Content-Type
+ },
+ ExpiresIn=expiration
+ )
+ except NoCredentialsError:
+ print("Credentials not available")
+ return None
+ return response
+
+
+# 生成每个学生的上传预签名URL
+bucket_name = 'sure-ae-upload'
+folder_name = 'sure_homework_define_by_qin'
+students = ['alice', 'bob', 'charlie'] # 示例学生名单
+
+for student in students:
+ object_key = f'{folder_name}/{student}-assignment.pdf' # 动态生成路径
+ url = generate_presigned_url(bucket_name, object_key)
+
+ if url:
+ print(f"The presigned URL for {student} is: {url}")