Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
venv
.env
Binary file added __pycache__/app.cpython-313.pyc
Binary file not shown.
Binary file added __pycache__/config.cpython-313.pyc
Binary file not shown.
Binary file added __pycache__/extensions.cpython-313.pyc
Binary file not shown.
35 changes: 35 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import os
import logging
from flask import Flask
from config import Config
from extensions import db # ✅ import shared db here

def create_app():
app = Flask(__name__)
app.config.from_object(Config)

# Initialize extensions
db.init_app(app) # ✅ binds db to this Flask app

# Configure logging
os.makedirs(app.config['LOG_FOLDER'], exist_ok=True)
logging.basicConfig(
filename=f"{app.config['LOG_FOLDER']}/app.log",
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s'
)

# Import blueprints after db setup
from controllers.file_controller import file_bp
app.register_blueprint(file_bp)

# Create tables
with app.app_context():
db.create_all()

return app


if __name__ == '__main__':
app = create_app()
app.run(debug=True)
25 changes: 25 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import os
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()

class Config:
# ✅ Correct MySQL connection string format
SQLALCHEMY_DATABASE_URI = (
f"mysql+pymysql://{os.getenv('DB_USER')}:{os.getenv('DB_PASSWORD')}@"
f"{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"
)

# ✅ Disable SQLAlchemy event system overhead
SQLALCHEMY_TRACK_MODIFICATIONS = False

# ⚠️ Fixed typo: "UPLOAD_FOLER" → "UPLOAD_FOLDER"
# Also set a fallback path (e.g., "uploads")
UPLOAD_FOLDER = os.getenv('UPLOAD_FOLDER', 'uploads')

# ✅ Set default logging directory
LOG_FOLDER = os.getenv('LOG_FOLDER', 'logs')

# ✅ Enable debug mode if specified, otherwise False
DEBUG = os.getenv('FLASK_DEBUG', 'True').lower() in ('true', '1', 'yes')
Binary file not shown.
70 changes: 70 additions & 0 deletions controllers/file_controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import uuid
from flask import Blueprint, request, jsonify, send_file
from services.file_service import save_file, update_file, delete_file
from models.uploaded_file import UploadedFile
from flask import Blueprint, request, jsonify, send_file, current_app
import logging

file_bp = Blueprint('file_bp', __name__)

# 🟢 POST — Upload file
@file_bp.route('/upload', methods=['POST'])
def upload_file():
try:
if 'file' not in request.files:
return jsonify({'message': 'No file uploaded'}), 400

file = request.files['file']
folder = f"{current_app.config['UPLOAD_FOLDER']}/{uuid.uuid4().hex}"
uploaded = save_file(file, folder)
return jsonify({'message': 'Upload successful', 'id': uploaded.id, 'path': uploaded.file_path}), 201

except Exception as e:
logging.error(f"Upload error: {e}")
return jsonify({'message': str(e)}), 400


# 🟡 GET — Retrieve file info or download
@file_bp.route('/file/<int:file_id>', methods=['GET'])
def get_file(file_id):
try:
file = UploadedFile.query.get(file_id)
if not file:
return jsonify({'message': 'File not found'}), 404

# You can test using Postman → GET http://localhost:5000/file/<id>
return send_file(file.file_path, as_attachment=True)
except Exception as e:
logging.error(f"Get error: {e}")
return jsonify({'message': str(e)}), 400

# 🟠 PUT — Update file
@file_bp.route('/file/<int:file_id>', methods=['PUT'])
def update_existing_file(file_id):
try:
if 'file' not in request.files:
return jsonify({'message': 'No file provided'}), 400

file = request.files['file']

updated = update_file(file_id, file, current_app.config['UPLOAD_FOLDER'])

return jsonify({
'message': 'File updated successfully',
'path': updated.file_path
}), 200

except Exception as e:
logging.error(f"Update error: {e}")
return jsonify({'message': str(e)}), 400

# 🔴 DELETE — Delete file
@file_bp.route('/file/<int:file_id>', methods=['DELETE'])
def delete_existing_file(file_id):
try:
delete_file(file_id)
return jsonify({'message': 'File deleted successfully'}), 200

except Exception as e:
logging.error(f"Delete error: {e}")
return jsonify({'message': str(e)}), 400
5 changes: 5 additions & 0 deletions extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# extensions.py
from flask_sqlalchemy import SQLAlchemy

# Single shared SQLAlchemy instance
db = SQLAlchemy()
148 changes: 148 additions & 0 deletions logs/app.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
2025-10-19 20:27:54,937 [INFO] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
2025-10-19 20:27:54,937 [INFO] Press CTRL+C to quit
2025-10-19 20:28:18,581 [INFO] 127.0.0.1 - - [19/Oct/2025 20:28:18] "GET / HTTP/1.1" 404 -
2025-10-19 20:28:18,645 [INFO] 127.0.0.1 - - [19/Oct/2025 20:28:18] "GET /favicon.ico HTTP/1.1" 404 -
2025-10-19 20:28:24,008 [INFO] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
2025-10-19 20:28:24,008 [INFO] Press CTRL+C to quit
2025-10-19 20:28:33,931 [INFO] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
2025-10-19 20:28:33,932 [INFO] Press CTRL+C to quit
2025-10-19 20:30:26,578 [INFO] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
2025-10-19 20:30:26,579 [INFO] Press CTRL+C to quit
2025-10-19 20:36:57,756 [INFO] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
2025-10-19 20:36:57,756 [INFO] Press CTRL+C to quit
2025-10-19 20:36:57,757 [INFO] * Restarting with stat
2025-10-19 20:36:58,481 [WARNING] * Debugger is active!
2025-10-19 20:36:58,484 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:37:12,841 [INFO] 127.0.0.1 - - [19/Oct/2025 20:37:12] "GET / HTTP/1.1" 404 -
2025-10-19 20:37:15,626 [INFO] 127.0.0.1 - - [19/Oct/2025 20:37:15] "GET /info HTTP/1.1" 404 -
2025-10-19 20:37:20,569 [INFO] 127.0.0.1 - - [19/Oct/2025 20:37:20] "GET /info HTTP/1.1" 404 -
2025-10-19 20:37:51,421 [INFO] 127.0.0.1 - - [19/Oct/2025 20:37:51] "GET /upload HTTP/1.1" 405 -
2025-10-19 20:38:15,012 [ERROR] Upload error: name 'app' is not defined
2025-10-19 20:38:15,013 [INFO] 127.0.0.1 - - [19/Oct/2025 20:38:15] "POST /upload HTTP/1.1" 400 -
2025-10-19 20:40:05,751 [INFO] * Detected change in 'C:\\Users\\Ginand\\Documents\\Proglan\\file-upload\\controllers\\file_controller.py', reloading
2025-10-19 20:40:05,865 [INFO] * Restarting with stat
2025-10-19 20:40:06,796 [WARNING] * Debugger is active!
2025-10-19 20:40:06,799 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:40:11,979 [INFO] * Detected change in 'C:\\Users\\Ginand\\Documents\\Proglan\\file-upload\\controllers\\file_controller.py', reloading
2025-10-19 20:40:12,084 [INFO] * Restarting with stat
2025-10-19 20:40:16,288 [INFO] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
2025-10-19 20:40:16,288 [INFO] Press CTRL+C to quit
2025-10-19 20:40:16,290 [INFO] * Restarting with stat
2025-10-19 20:40:17,037 [WARNING] * Debugger is active!
2025-10-19 20:40:17,040 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:40:19,334 [ERROR] Upload error: The current Flask app is not registered with this 'SQLAlchemy' instance. Did you forget to call 'init_app', or did you create multiple 'SQLAlchemy' instances?
2025-10-19 20:40:19,334 [INFO] 127.0.0.1 - - [19/Oct/2025 20:40:19] "POST /upload HTTP/1.1" 400 -
2025-10-19 20:40:44,268 [INFO] * Detected change in 'C:\\Users\\Ginand\\Documents\\Proglan\\file-upload\\app.py', reloading
2025-10-19 20:40:44,401 [INFO] * Restarting with stat
2025-10-19 20:40:45,110 [WARNING] * Debugger is active!
2025-10-19 20:40:45,112 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:40:47,214 [INFO] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
2025-10-19 20:40:47,214 [INFO] Press CTRL+C to quit
2025-10-19 20:40:47,215 [INFO] * Restarting with stat
2025-10-19 20:40:47,916 [WARNING] * Debugger is active!
2025-10-19 20:40:47,919 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:40:56,168 [INFO] * Detected change in 'C:\\Users\\Ginand\\Documents\\Proglan\\file-upload\\models\\uploaded_file.py', reloading
2025-10-19 20:40:56,270 [INFO] * Restarting with stat
2025-10-19 20:40:57,028 [WARNING] * Debugger is active!
2025-10-19 20:40:57,030 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:41:02,408 [ERROR] Upload error: The current Flask app is not registered with this 'SQLAlchemy' instance. Did you forget to call 'init_app', or did you create multiple 'SQLAlchemy' instances?
2025-10-19 20:41:02,408 [INFO] 127.0.0.1 - - [19/Oct/2025 20:41:02] "POST /upload HTTP/1.1" 400 -
2025-10-19 20:41:03,492 [ERROR] Upload error: The current Flask app is not registered with this 'SQLAlchemy' instance. Did you forget to call 'init_app', or did you create multiple 'SQLAlchemy' instances?
2025-10-19 20:41:03,493 [INFO] 127.0.0.1 - - [19/Oct/2025 20:41:03] "POST /upload HTTP/1.1" 400 -
2025-10-19 20:41:24,425 [INFO] * Detected change in 'C:\\Users\\Ginand\\Documents\\Proglan\\file-upload\\__init__.py', reloading
2025-10-19 20:41:24,545 [INFO] * Restarting with stat
2025-10-19 20:41:25,287 [WARNING] * Debugger is active!
2025-10-19 20:41:25,289 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:41:27,688 [INFO] * Detected change in 'C:\\Users\\Ginand\\Documents\\Proglan\\file-upload\\app.py', reloading
2025-10-19 20:41:27,830 [INFO] * Restarting with stat
2025-10-19 20:41:28,583 [WARNING] * Debugger is active!
2025-10-19 20:41:28,586 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:41:30,220 [INFO] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
2025-10-19 20:41:30,220 [INFO] Press CTRL+C to quit
2025-10-19 20:41:30,221 [INFO] * Restarting with stat
2025-10-19 20:41:30,894 [WARNING] * Debugger is active!
2025-10-19 20:41:30,896 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:41:32,813 [ERROR] Upload error: The current Flask app is not registered with this 'SQLAlchemy' instance. Did you forget to call 'init_app', or did you create multiple 'SQLAlchemy' instances?
2025-10-19 20:41:32,813 [INFO] 127.0.0.1 - - [19/Oct/2025 20:41:32] "POST /upload HTTP/1.1" 400 -
2025-10-19 20:41:40,769 [INFO] * Detected change in 'C:\\Users\\Ginand\\Documents\\Proglan\\file-upload\\app.py', reloading
2025-10-19 20:41:40,879 [INFO] * Restarting with stat
2025-10-19 20:41:41,672 [WARNING] * Debugger is active!
2025-10-19 20:41:41,674 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:42:00,185 [INFO] * Detected change in 'C:\\Users\\Ginand\\Documents\\Proglan\\file-upload\\config.py', reloading
2025-10-19 20:42:00,290 [INFO] * Restarting with stat
2025-10-19 20:42:01,026 [WARNING] * Debugger is active!
2025-10-19 20:42:01,028 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:42:02,820 [INFO] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
2025-10-19 20:42:02,833 [INFO] Press CTRL+C to quit
2025-10-19 20:42:02,834 [INFO] * Restarting with stat
2025-10-19 20:42:03,538 [WARNING] * Debugger is active!
2025-10-19 20:42:03,541 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:42:08,910 [ERROR] Upload error: The current Flask app is not registered with this 'SQLAlchemy' instance. Did you forget to call 'init_app', or did you create multiple 'SQLAlchemy' instances?
2025-10-19 20:42:08,911 [INFO] 127.0.0.1 - - [19/Oct/2025 20:42:08] "POST /upload HTTP/1.1" 400 -
2025-10-19 20:42:09,766 [ERROR] Upload error: The current Flask app is not registered with this 'SQLAlchemy' instance. Did you forget to call 'init_app', or did you create multiple 'SQLAlchemy' instances?
2025-10-19 20:42:09,766 [INFO] 127.0.0.1 - - [19/Oct/2025 20:42:09] "POST /upload HTTP/1.1" 400 -
2025-10-19 20:42:52,811 [INFO] * Detected change in 'C:\\Users\\Ginand\\Documents\\Proglan\\file-upload\\extensions.py', reloading
2025-10-19 20:42:52,907 [INFO] * Restarting with stat
2025-10-19 20:42:53,689 [WARNING] * Debugger is active!
2025-10-19 20:42:53,691 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:42:56,066 [INFO] * Detected change in 'C:\\Users\\Ginand\\Documents\\Proglan\\file-upload\\app.py', reloading
2025-10-19 20:42:56,180 [INFO] * Restarting with stat
2025-10-19 20:42:56,870 [WARNING] * Debugger is active!
2025-10-19 20:42:56,872 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:43:00,870 [INFO] * Detected change in 'C:\\Users\\Ginand\\Documents\\Proglan\\file-upload\\models\\uploaded_file.py', reloading
2025-10-19 20:43:00,982 [INFO] * Restarting with stat
2025-10-19 20:43:01,658 [WARNING] * Debugger is active!
2025-10-19 20:43:01,660 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:43:03,863 [INFO] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
2025-10-19 20:43:03,863 [INFO] Press CTRL+C to quit
2025-10-19 20:43:03,865 [INFO] * Restarting with stat
2025-10-19 20:43:04,496 [WARNING] * Debugger is active!
2025-10-19 20:43:04,498 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:43:09,374 [INFO] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
2025-10-19 20:43:09,374 [INFO] Press CTRL+C to quit
2025-10-19 20:43:09,375 [INFO] * Restarting with stat
2025-10-19 20:43:10,140 [WARNING] * Debugger is active!
2025-10-19 20:43:10,142 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:43:10,721 [INFO] File saved: uploads/193c202f11214be3993a2069f3f64b11\a0cac6305fbe4037b993ef66d4c76e51_Group_1857.png
2025-10-19 20:43:10,724 [INFO] 127.0.0.1 - - [19/Oct/2025 20:43:10] "POST /upload HTTP/1.1" 201 -
2025-10-19 20:44:02,894 [INFO] 127.0.0.1 - - [19/Oct/2025 20:44:02] "GET /file/1 HTTP/1.1" 200 -
2025-10-19 20:44:04,816 [INFO] 127.0.0.1 - - [19/Oct/2025 20:44:04] "GET /file/2 HTTP/1.1" 404 -
2025-10-19 20:44:06,667 [INFO] 127.0.0.1 - - [19/Oct/2025 20:44:06] "GET /file/1 HTTP/1.1" 200 -
2025-10-19 20:44:24,236 [ERROR] Update error: name 'app' is not defined
2025-10-19 20:44:24,236 [INFO] 127.0.0.1 - - [19/Oct/2025 20:44:24] "PUT /file/1 HTTP/1.1" 400 -
2025-10-19 20:44:44,337 [ERROR] Update error: name 'app' is not defined
2025-10-19 20:44:44,337 [INFO] 127.0.0.1 - - [19/Oct/2025 20:44:44] "PUT /file/1 HTTP/1.1" 400 -
2025-10-19 20:45:17,046 [INFO] * Detected change in 'C:\\Users\\Ginand\\Documents\\Proglan\\file-upload\\controllers\\file_controller.py', reloading
2025-10-19 20:45:17,165 [INFO] * Restarting with stat
2025-10-19 20:45:18,995 [INFO] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
2025-10-19 20:45:18,995 [INFO] Press CTRL+C to quit
2025-10-19 20:45:18,996 [INFO] * Restarting with stat
2025-10-19 20:45:19,668 [WARNING] * Debugger is active!
2025-10-19 20:45:19,670 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:45:21,695 [INFO] File saved: uploads\e491524ff26f42ca911ac06bf4e6c1f9_24SDFDSF.png
2025-10-19 20:45:21,702 [INFO] File updated: ID=1
2025-10-19 20:45:21,704 [INFO] 127.0.0.1 - - [19/Oct/2025 20:45:21] "PUT /file/1 HTTP/1.1" 200 -
2025-10-19 20:45:29,079 [INFO] * Detected change in 'C:\\Users\\Ginand\\Documents\\Proglan\\file-upload\\controllers\\file_controller.py', reloading
2025-10-19 20:45:29,180 [INFO] * Restarting with stat
2025-10-19 20:45:29,863 [WARNING] * Debugger is active!
2025-10-19 20:45:29,865 [INFO] * Debugger PIN: 881-545-031
2025-10-19 20:45:32,003 [INFO] 127.0.0.1 - - [19/Oct/2025 20:45:32] "GET /file/1 HTTP/1.1" 200 -
2025-10-19 20:45:40,098 [INFO] File deleted from storage: uploads\e491524ff26f42ca911ac06bf4e6c1f9_24SDFDSF.png
2025-10-19 20:45:40,104 [INFO] Record deleted: ID=1
2025-10-19 20:45:40,105 [INFO] 127.0.0.1 - - [19/Oct/2025 20:45:40] "DELETE /file/1 HTTP/1.1" 200 -
2025-10-19 20:45:43,580 [INFO] 127.0.0.1 - - [19/Oct/2025 20:45:43] "GET /file/1 HTTP/1.1" 404 -
2025-10-19 20:45:48,919 [INFO] 127.0.0.1 - - [19/Oct/2025 20:45:48] "POST /file HTTP/1.1" 404 -
2025-10-19 20:45:57,444 [INFO] File saved: uploads/16da22714b6e48c7855fb6f2e3035742\a1c64dfdddbf48e7b5634925b0df4811_24SDFDSF.png
2025-10-19 20:45:57,447 [INFO] 127.0.0.1 - - [19/Oct/2025 20:45:57] "POST /upload HTTP/1.1" 201 -
Binary file added models/__pycache__/uploaded_file.cpython-313.pyc
Binary file not shown.
6 changes: 6 additions & 0 deletions models/uploaded_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from extensions import db

class UploadedFile(db.Model):
id = db.Column(db.Integer, primary_key=True)
filename = db.Column(db.String(255), nullable=False)
file_path = db.Column(db.String(255), nullable=False)
12 changes: 12 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
blinker==1.9.0
click==8.3.0
Flask==3.1.2
Flask-SQLAlchemy==3.1.1
itsdangerous==2.2.0
Jinja2==3.1.6
MarkupSafe==3.0.3
PyMySQL==1.1.2
python-dotenv==1.1.1
SQLAlchemy==2.0.44
typing_extensions==4.15.0
Werkzeug==3.1.3
Binary file added services/__pycache__/file_service.cpython-313.pyc
Binary file not shown.
49 changes: 49 additions & 0 deletions services/file_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import os
import uuid
from werkzeug.utils import secure_filename
from models.uploaded_file import UploadedFile
from app import db
import logging
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'pdf', 'txt'}
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def save_file(file, base_folder):
if not allowed_file(file.filename):
raise ValueError('File type not allowed')

os.makedirs(base_folder, exist_ok=True)
filename = secure_filename(file.filename)
unique_name = f"{uuid.uuid4().hex}_{filename}"
save_path = os.path.join(base_folder, unique_name)
file.save(save_path)
new_file = UploadedFile(filename=unique_name, file_path=save_path)
db.session.add(new_file)
db.session.commit()
logging.info(f"File saved: {save_path}")
return new_file

def update_file(file_id, new_file, base_folder):
existing = UploadedFile.query.get(file_id)
if not existing:
raise ValueError('File not found')
if os.path.exists(existing.file_path):
os.remove(existing.file_path)

new_record = save_file(new_file, base_folder)
existing.filename = new_record.filename
existing.file_path = new_record.file_path
db.session.commit()
logging.info(f"File updated: ID={file_id}")
return existing

def delete_file(file_id):
file_record = UploadedFile.query.get(file_id)
if not file_record:
raise ValueError('File not found')
if os.path.exists(file_record.file_path):
os.remove(file_record.file_path)
logging.info(f"File deleted from storage: {file_record.file_path}")

db.session.delete(file_record)
db.session.commit()
logging.info(f"Record deleted: ID={file_id}")
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.