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
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

.env

__pycache__/
*.pyc

logs/

tempCodeRunnerFile.py

venv/
32 changes: 32 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import os
import logging
from flask import Flask
from config import Config
from extensions import db


app = Flask(__name__)
app.config.from_object(Config)

db.init_app(app)


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'
)

from controllers.file_controller import file_bp
app.register_blueprint(file_bp)

from controllers.auth_controller import auth_bp
app.register_blueprint(auth_bp)


with app.app_context():
db.create_all()

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

class Config:
SQLALCHEMY_DATABASE_URI = (
f"mysql+pymysql://{os.getenv('DB_USER')}:{os.getenv('DB_PASSWORD')}@"
f"{os.getenv('DB_HOST', 'localhost')}:{os.getenv('DB_PORT', '3306')}/{os.getenv('DB_NAME', 'flask_uploads_db')}"
)
SQLALCHEMY_TRACK_MODIFICATIONS = False
UPLOAD_FOLDER = os.getenv('UPLOAD_FOLDER', 'uploads')
LOG_FOLDER = 'logs'
DEBUG = True
26 changes: 26 additions & 0 deletions controllers/auth_controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from flask import Blueprint, request, jsonify, current_app
import logging

auth_bp = Blueprint("auth", __name__, url_prefix="/auth")

VALID_USERNAME = "stephen" # AT VAUGHKET HENDE?!
VALID_PASSWORD = "shetkatalagaballabyu"

@auth_bp.route("/login", methods=["POST"])
def login():
if not request.is_json:
current_app.logger.warning("Login failed: Non-JSON request received")
return jsonify({"error": "Request must be in JSON format"}), 400

data = request.get_json()
username = data.get("username")
password = data.get("password")

current_app.logger.info(f"Login attempt by user: {username}")

if username == VALID_USERNAME and password == VALID_PASSWORD:
current_app.logger.info(f"Login successful for user: {username}")
return jsonify({"message": "Login successful!"}), 200
else:
current_app.logger.warning(f"Login failed for user: {username}")
return jsonify({"error": "Invalid username or password"}), 401
68 changes: 68 additions & 0 deletions controllers/file_controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from flask import Blueprint, request, jsonify, send_file, current_app
from services.file_service import save_file, update_file, delete_file
from models.uploaded_file import UploadedFile
from flask import send_from_directory
import logging
import uuid

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}" # ✅ use current_app
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
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']) # ✅ use current_app
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
4 changes: 4 additions & 0 deletions extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# extensions.py
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
7 changes: 7 additions & 0 deletions models/uploaded_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from extensions import db

# This model represents an uploaded file record in the database
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)
Binary file added requirements.txt
Binary file not shown.
47 changes: 47 additions & 0 deletions services/file_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import os
import uuid
from werkzeug.utils import secure_filename
from models.uploaded_file import UploadedFile
from extensions 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.
Binary file added uploads/8cd3476685c44d888f5416ef9ffe2a09_shirt.png
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.