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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Binary file added __pycache__/app.cpython-314.pyc
Binary file not shown.
Binary file added __pycache__/config.cpython-314.pyc
Binary file not shown.
Binary file added __pycache__/extensions.cpython-314.pyc
Binary file not shown.
40 changes: 40 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import os
import logging
from flask import Flask
from config import Config
from extensions import db
from models.uploaded_file import UploadedFile

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

# Initialize database
db.init_app(app)

# Logging configuration
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
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'
)

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

# Register blueprints
from controllers.file_controller import file_bp
app.register_blueprint(file_bp)


return app

app = create_app()

if __name__ == '__main__':
print("Starting Flask app...")
app.run(debug=True, use_reloader=False)

14 changes: 14 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
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')}:{os.getenv('DB_PORT')}/{os.getenv('DB_NAME')}"
)
SQLALCHEMY_TRACK_MODIFICATIONS = False
UPLOAD_FOLDER = os.getenv('UPLOAD_FOLDER', 'uploads')
LOG_FOLDER = 'logs'
DEBUG = True
Binary file not shown.
58 changes: 58 additions & 0 deletions controllers/file_controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
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 config import Config
import logging
import uuid

file_bp = Blueprint('file_bp', __name__)

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

print(request.files) # Add this inside upload_file()


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

@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

@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

@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
3 changes: 3 additions & 0 deletions extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
13 changes: 13 additions & 0 deletions logs/app.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
2025-10-19 04:05:39,681 [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 04:05:39,681 [INFO] Press CTRL+C to quit
2025-10-19 04:06:17,914 [INFO] File saved: uploads/ed827ca2e5b64fd690a68ec9019e9f2b\4c9e959cb8504444b9cedf2587bfad11_2.jpg
2025-10-19 04:06:17,919 [INFO] 127.0.0.1 - - [19/Oct/2025 04:06:17] "POST /upload HTTP/1.1" 201 -
2025-10-19 04:06:41,671 [INFO] 127.0.0.1 - - [19/Oct/2025 04:06:41] "GET /file/1 HTTP/1.1" 200 -
2025-10-19 04:06:56,265 [INFO] File saved: uploads\8f99766c07444f449a4f5837e2b8c4d2_killua.png
2025-10-19 04:06:56,274 [INFO] File updated: ID=1
2025-10-19 04:06:56,278 [INFO] 127.0.0.1 - - [19/Oct/2025 04:06:56] "PUT /file/1 HTTP/1.1" 200 -
2025-10-19 04:07:01,122 [INFO] 127.0.0.1 - - [19/Oct/2025 04:07:01] "GET /file/1 HTTP/1.1" 200 -
2025-10-19 04:07:05,944 [INFO] File deleted from storage: uploads\8f99766c07444f449a4f5837e2b8c4d2_killua.png
2025-10-19 04:07:05,948 [INFO] Record deleted: ID=1
2025-10-19 04:07:05,949 [INFO] 127.0.0.1 - - [19/Oct/2025 04:07:05] "DELETE /file/1 HTTP/1.1" 200 -
Binary file added models/__pycache__/uploaded_file.cpython-314.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)
14 changes: 14 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
blinker==1.9.0
click==8.3.0
colorama==0.4.6
Flask==3.1.2
Flask-SQLAlchemy==3.1.1
greenlet==3.2.4
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-314.pyc
Binary file not shown.
58 changes: 58 additions & 0 deletions services/file_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
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.
15 changes: 15 additions & 0 deletions venv/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Ignore Python cache and venv
__pycache__/
venv/
*.pyc

# Ignore environment and local config
.env

# Ignore uploads and logs
uploads/
logs/

# Ignore IDE settings
.vscode/
.idea/
164 changes: 164 additions & 0 deletions venv/Include/site/python3.14/greenlet/greenlet.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/* -*- indent-tabs-mode: nil; tab-width: 4; -*- */

/* Greenlet object interface */

#ifndef Py_GREENLETOBJECT_H
#define Py_GREENLETOBJECT_H


#include <Python.h>

#ifdef __cplusplus
extern "C" {
#endif

/* This is deprecated and undocumented. It does not change. */
#define GREENLET_VERSION "1.0.0"

#ifndef GREENLET_MODULE
#define implementation_ptr_t void*
#endif

typedef struct _greenlet {
PyObject_HEAD
PyObject* weakreflist;
PyObject* dict;
implementation_ptr_t pimpl;
} PyGreenlet;

#define PyGreenlet_Check(op) (op && PyObject_TypeCheck(op, &PyGreenlet_Type))


/* C API functions */

/* Total number of symbols that are exported */
#define PyGreenlet_API_pointers 12

#define PyGreenlet_Type_NUM 0
#define PyExc_GreenletError_NUM 1
#define PyExc_GreenletExit_NUM 2

#define PyGreenlet_New_NUM 3
#define PyGreenlet_GetCurrent_NUM 4
#define PyGreenlet_Throw_NUM 5
#define PyGreenlet_Switch_NUM 6
#define PyGreenlet_SetParent_NUM 7

#define PyGreenlet_MAIN_NUM 8
#define PyGreenlet_STARTED_NUM 9
#define PyGreenlet_ACTIVE_NUM 10
#define PyGreenlet_GET_PARENT_NUM 11

#ifndef GREENLET_MODULE
/* This section is used by modules that uses the greenlet C API */
static void** _PyGreenlet_API = NULL;

# define PyGreenlet_Type \
(*(PyTypeObject*)_PyGreenlet_API[PyGreenlet_Type_NUM])

# define PyExc_GreenletError \
((PyObject*)_PyGreenlet_API[PyExc_GreenletError_NUM])

# define PyExc_GreenletExit \
((PyObject*)_PyGreenlet_API[PyExc_GreenletExit_NUM])

/*
* PyGreenlet_New(PyObject *args)
*
* greenlet.greenlet(run, parent=None)
*/
# define PyGreenlet_New \
(*(PyGreenlet * (*)(PyObject * run, PyGreenlet * parent)) \
_PyGreenlet_API[PyGreenlet_New_NUM])

/*
* PyGreenlet_GetCurrent(void)
*
* greenlet.getcurrent()
*/
# define PyGreenlet_GetCurrent \
(*(PyGreenlet * (*)(void)) _PyGreenlet_API[PyGreenlet_GetCurrent_NUM])

/*
* PyGreenlet_Throw(
* PyGreenlet *greenlet,
* PyObject *typ,
* PyObject *val,
* PyObject *tb)
*
* g.throw(...)
*/
# define PyGreenlet_Throw \
(*(PyObject * (*)(PyGreenlet * self, \
PyObject * typ, \
PyObject * val, \
PyObject * tb)) \
_PyGreenlet_API[PyGreenlet_Throw_NUM])

/*
* PyGreenlet_Switch(PyGreenlet *greenlet, PyObject *args)
*
* g.switch(*args, **kwargs)
*/
# define PyGreenlet_Switch \
(*(PyObject * \
(*)(PyGreenlet * greenlet, PyObject * args, PyObject * kwargs)) \
_PyGreenlet_API[PyGreenlet_Switch_NUM])

/*
* PyGreenlet_SetParent(PyObject *greenlet, PyObject *new_parent)
*
* g.parent = new_parent
*/
# define PyGreenlet_SetParent \
(*(int (*)(PyGreenlet * greenlet, PyGreenlet * nparent)) \
_PyGreenlet_API[PyGreenlet_SetParent_NUM])

/*
* PyGreenlet_GetParent(PyObject* greenlet)
*
* return greenlet.parent;
*
* This could return NULL even if there is no exception active.
* If it does not return NULL, you are responsible for decrementing the
* reference count.
*/
# define PyGreenlet_GetParent \
(*(PyGreenlet* (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_GET_PARENT_NUM])

/*
* deprecated, undocumented alias.
*/
# define PyGreenlet_GET_PARENT PyGreenlet_GetParent

# define PyGreenlet_MAIN \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_MAIN_NUM])

# define PyGreenlet_STARTED \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_STARTED_NUM])

# define PyGreenlet_ACTIVE \
(*(int (*)(PyGreenlet*)) \
_PyGreenlet_API[PyGreenlet_ACTIVE_NUM])




/* Macro that imports greenlet and initializes C API */
/* NOTE: This has actually moved to ``greenlet._greenlet._C_API``, but we
keep the older definition to be sure older code that might have a copy of
the header still works. */
# define PyGreenlet_Import() \
{ \
_PyGreenlet_API = (void**)PyCapsule_Import("greenlet._C_API", 0); \
}

#endif /* GREENLET_MODULE */

#ifdef __cplusplus
}
#endif
#endif /* !Py_GREENLETOBJECT_H */
1 change: 1 addition & 0 deletions venv/Lib/site-packages/blinker-1.9.0.dist-info/INSTALLER
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pip
Loading