0% found this document useful (0 votes)
36 views31 pages

Folder Structure

Uploaded by

terdqwer2
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
36 views31 pages

Folder Structure

Uploaded by

terdqwer2
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 31

Folder Structure:

FastAPI/
├─ requirements.txt
├─ Dockerfile
├─ app/
│ app/
│ ├─ models/
│ │ models/
│ │ ├─ role.py
│ │ ├─ task.py
│ │ ├─ status.py
│ │ ├─ user.py
│ │ ├─ __pycache__/
│ │ │ __pycache__/
│ │ │ ├─ change.cpython-312.pyc
│ │ │ ├─ task.cpython-312.pyc
│ │ │ ├─ __init__.cpython-312.pyc
│ │ │ ├─ role.cpython-312.pyc
│ │ │ └─ user.cpython-312.pyc
│ │ ├─ __init__.py
│ │ └─ change.py
│ ├─ config/
│ │ config/
│ │ ├─ __pycache__/
│ │ │ __pycache__/
│ │ │ ├─ database.cpython-312.pyc
│ │ │ ├─ __init__.cpython-312.pyc
│ │ │ └─ settings.cpython-312.pyc
│ │ ├─ database.py
│ │ ├─ __init__.py
│ │ └─ settings.py
│ ├─ __pycache__/
│ │ __pycache__/
│ │ ├─ database.cpython-312.pyc
│ │ ├─ main.cpython-312.pyc
│ │ └─ migrations.cpython-312.pyc
│ ├─ migrations.py
│ ├─ alembic/
│ │ alembic/
│ │ ├─ versions/
│ │ │ versions/
│ │ │ ├─ __pycache__/
│ │ │ │ __pycache__/
│ │ │ │ ├─ 905731c6a76a_first_migrations.cpython-312.pyc
│ │ │ │ ├─ 6655c8f0dad7_initial_migration.cpython-312.pyc
│ │ │ │ └─ d89dc7a9d248_initial_migration.cpython-312.pyc
│ │ │ └─ 905731c6a76a_first_migrations.py
│ │ ├─ env.py
│ │ ├─ script.py.mako
│ │ ├─ __pycache__/
│ │ │ __pycache__/
│ │ │ └─ env.cpython-312.pyc
│ │ └─ README
│ ├─ services/
│ │ services/
│ │ ├─ __pycache__/
│ │ │ __pycache__/
│ │ │ ├─ user_service.cpython-312.pyc
│ │ │ ├─ __init__.cpython-312.pyc
│ │ │ ├─ auth_service.cpython-312.pyc
│ │ │ └─ task_service.cpython-312.pyc
│ │ ├─ auth_service.py
│ │ ├─ __init__.py
│ │ ├─ user_service.py
│ │ └─ task_service.py
│ ├─ main.py
│ ├─ utils/
│ │ utils/
│ │ ├─ __pycache__/
│ │ │ __pycache__/
│ │ │ ├─ __init__.cpython-312.pyc
│ │ │ └─ dependencies.cpython-312.pyc
│ │ ├─ dependencies.py
│ │ └─ __init__.py
│ ├─ routes/
│ │ routes/
│ │ ├─ task_routes.py
│ │ ├─ auth_routes.py
│ │ ├─ __pycache__/
│ │ │ __pycache__/
│ │ │ ├─ task_routes.cpython-312.pyc
│ │ │ ├─ user_management_routes.cpython-312.pyc
│ │ │ ├─ __init__.cpython-312.pyc
│ │ │ └─ auth_routes.cpython-312.pyc
│ │ ├─ user_management_routes.py
│ │ └─ __init__.py
│ └─ alembic.ini
├─ alembic.ini
└─ .dockerignore

File Contents:

File: FastAPI/requirements.txt
==============================
alembic==1.13.3
annotated-types==0.7.0
anyio==4.6.0
astroid==3.3.5
black==24.10.0
cffi==1.17.1
click==8.1.7
cryptography==43.0.1
dill==0.3.9
dnspython==2.7.0
ecdsa==0.19.0
email_validator==2.2.0
fastapi==0.115.0
greenlet==3.1.1
h11==0.14.0
idna==3.10
isort==5.13.2
python-multipart==0.0.5

Mako==1.3.5
MarkupSafe==3.0.1
mccabe==0.7.0
mypy-extensions==1.0.0
packaging==24.1
passlib==1.7.4
pathspec==0.12.1
peewee==3.17.6
platformdirs==4.3.6
pyasn1==0.6.1
pycparser==2.22
pydantic==2.9.2
pydantic_core==2.23.4
pylint==3.3.1
PyMySQL==1.1.1
python-dotenv==1.0.1
python-jose==3.3.0
rsa==4.9
six==1.16.0
sniffio==1.3.1
SQLAlchemy==2.0.35
starlette==0.38.6
tomlkit==0.13.2
typing_extensions==4.12.2
uvicorn==0.31.0

File: FastAPI/Dockerfile
========================
FROM python:3.12

COPY ./app /app


COPY ./requirements.txt /app

WORKDIR /app

RUN apt-get update && apt-get upgrade -y && apt-get install -y mariadb-client &&
pip install mysqlclient

RUN pip install --upgrade pip


RUN pip install -r requirements.txt

CMD [ "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80" ]

File: FastAPI/app/models/role.py
================================
"""
This module defines the Role class, which represents a role model used to manage
different roles or permissions within an application.

The Role class includes attributes such as the role's unique identifier and name.

It is built using Pydantic's `BaseModel` to ensure data validation and type


checking.
"""

from pydantic import BaseModel

class Role(BaseModel):
"""
Represents a role with relevant details.

Attributes:
-----------
id : int
Unique identifier for the role.
name : str
The name of the role (e.g., 'admin', 'user'),
representing the permissions associated with it.
"""

id: int
name: str

File: FastAPI/app/models/task.py
================================
"""
This module defines the Task class, which represents a task model for handling
task-related data within an application.

The Task class includes attributes such as title, description, creation date,
expiration date, and flags for tracking the status and importance of the task.

It is based on the Pydantic `BaseModel` to ensure data validation and type


checking.
"""

from datetime import date


from typing import List, Optional
from pydantic import BaseModel
from .change import Change

class Task(BaseModel):
"""
Represents a task with relevant details.

Attributes:
-----------
id : int
Unique identifier for the task.
title : str
Title of the task.
description : str
Detailed description of the task.
date_of_creation : date
The date when the task was created.
expiration_date : date
The deadline or expiration date for the task.
status_id : int
The status identifier, representing the current state
of the task (e.g., completed, pending).
user_id : int
The identifier of the user associated with the task.
is_favorite : bool
Flag indicating whether the task is marked as a favorite.
"""

id: int
title: str
description: str
date_of_creation: date
expiration_date: date
status_id: int
user_id: int
is_favorite: bool
changes: Optional[List[Change]] = None

class Config:
from_attributes = True # Cambia 'orm_mode' a 'from_attributes' para
Pydantic v2

class TaskCreate(BaseModel):
title: str
description: Optional[str] = None
expiration_date: Optional[date] = None
status_id: int

class TaskUpdate(BaseModel):
"""
This is so that the task can be updated.
"""
title: Optional[str] = None
description: Optional[str] = None
expiration_date: Optional[date] = None
status_id: Optional[int] = None
is_favorite: Optional[bool] = None

File: FastAPI/app/models/status.py
==================================
"""
This module defines the Status class, which represents a status model for managing
different statuses that can be assigned to tasks or other entities within an
application.

The Status class includes attributes such as the unique identifier and the name of
the status.

It is built using Pydantic's `BaseModel` to ensure data validation and type


checking.
"""

from pydantic import BaseModel

class Status(BaseModel):
"""
Represents a status with relevant details.

Attributes:
-----------
id : int
Unique identifier for the status.
name : str
The name of the status (e.g., 'pending', 'completed', 'in progress'),
describing the current state of an entity.
"""

id: int
name: str

File: FastAPI/app/models/user.py
================================
from typing import Optional
from pydantic import BaseModel, EmailStr
from .role import Role

class UserRead(BaseModel):
id: int
email: EmailStr
role_id: int
is_active: bool
role: Role

class Config:
from_attributes = True

class UserCreate(BaseModel):
email: EmailStr
password: str # Contraseña en texto plano; se hashea antes de almacenar
role_id: int

class UserUpdate(BaseModel):
email: Optional[EmailStr] = None
password: Optional[str] = None
role_id: Optional[int] = None

File: FastAPI/app/models/__pycache__/change.cpython-312.pyc
===========================================================
Contenido binario o no legible.

File: FastAPI/app/models/__pycache__/task.cpython-312.pyc
=========================================================
Contenido binario o no legible.

File: FastAPI/app/models/__pycache__/__init__.cpython-312.pyc
=============================================================
Contenido binario o no legible.

File: FastAPI/app/models/__pycache__/role.cpython-312.pyc
=========================================================
Contenido binario o no legible.

File: FastAPI/app/models/__pycache__/user.cpython-312.pyc
=========================================================
Contenido binario o no legible.

File: FastAPI/app/models/__init__.py
====================================

File: FastAPI/app/models/change.py
==================================
"""
Model for logging changes to tasks.
"""

from datetime import datetime


from typing import Optional
from pydantic import BaseModel

class Change(BaseModel):
"""
Represents a record of a change made to a task.

Attributes:
id (int): Unique identifier of the change.
task_id (int): ID of the task associated with the change.
timestamp (datetime): Date and time when the change was made.
field_changed (str): Field that was changed.
old_value (Optional[str]): Previous value of the field.
new_value (Optional[str]): New value of the field.
"""
id: int
task_id: int
timestamp: datetime
field_changed: str
old_value: Optional[str] = None
new_value: Optional[str] = None

class Config: # pylint: disable=too-few-public-methods


"""
Model Config
"""
from_attributes = True

File: FastAPI/app/config/__pycache__/database.cpython-312.pyc
=============================================================
Contenido binario o no legible.

File: FastAPI/app/config/__pycache__/__init__.cpython-312.pyc
=============================================================
Contenido binario o no legible.

File: FastAPI/app/config/__pycache__/settings.cpython-312.pyc
=============================================================
Contenido binario o no legible.

File: FastAPI/app/config/database.py
====================================
"""
Necessary imports to define data models using Peewee ORM.
- Model: Base class for all models.
- CharField, TextField, DateField, etc.: Database field types.
- ForeignKeyField: Defines relationships between tables.
- Check: Defines column-level constraints.
- AutoField: Auto-incrementing field used as a primary key.
- fn: Provides SQL functions like CURRENT_TIMESTAMP.
"""
from datetime import date, datetime # Importa datetime
from dotenv import load_dotenv
from config.settings import DATABASE
from peewee import (
MySQLDatabase, Model, CharField, TextField, DateField,
ForeignKeyField, BooleanField, DateTimeField, Check, AutoField, fn, SQL
)

# Load environment variables from the .env file


load_dotenv()

# Create a MySQL database instance using environment variables


database = MySQLDatabase(
DATABASE["name"],
user=DATABASE["user"],
passwd=DATABASE["password"],
host=DATABASE["host"],
port=DATABASE["port"],
)

class RoleModel(Model):
"""Role table."""
id = AutoField(primary_key=True)
name = CharField(null=False)

class Meta:# pylint: disable=too-few-public-methods


"""Meta information for the Role model."""
table_name = "role"
database = database

class StatusModel(Model):
"""Status table with constraints on the name field."""
id = AutoField(primary_key=True)
name = CharField(
null=False,
constraints=[Check(SQL('"name" IN
(\'TO_DO\', \'IN_PROGRESS\', \'COMPLETED\')'))]
)

class Meta:# pylint: disable=too-few-public-methods


"""Meta information for the Status model."""
table_name = "status"
database = database
class UserModel(Model):
"""User table with a relation to Role."""
id = AutoField(primary_key=True)
email = CharField(unique=True, null=False)
password = CharField(null=False)
role = ForeignKeyField(RoleModel, backref='users', null=True, on_delete='SET
NULL')
is_active = BooleanField(default=True)

class Meta:# pylint: disable=too-few-public-methods


"""Meta information for the User model."""
table_name = "user"
database = database

class TaskModel(Model):
"""Task table with relationships to User and Status."""
id = AutoField(primary_key=True)
title = CharField(null=False)
description = TextField(null=True)
date_of_creation = DateField(default=date.today, null=False)
expiration_date = DateField(null=True)
status = ForeignKeyField(StatusModel, backref='tasks', on_delete='CASCADE')
user = ForeignKeyField(UserModel, backref='tasks', on_delete='CASCADE')
is_favorite = BooleanField(default=False)

class Meta:# pylint: disable=too-few-public-methods


"""Meta information for the Task model."""
table_name = "task"
database = database
constraints = [
Check('expiration_date IS NULL OR expiration_date >= date_of_creation')
]

class ChangeModel(Model):
"""Change table to log modifications in Task."""
id = AutoField(primary_key=True)
task = ForeignKeyField(TaskModel, backref='changes', on_delete='CASCADE')
timestamp = DateTimeField(default=datetime.utcnow)
field_changed = CharField(null=False)
old_value = TextField(null=True)
new_value = TextField(null=True)

class Meta:# pylint: disable=too-few-public-methods


"""Meta information for the Change model."""
table_name = "change"
database = database

File: FastAPI/app/config/__init__.py
====================================

File: FastAPI/app/config/settings.py
====================================
"""
This module loads the environment configuration for the application.
Uses `dotenv` to load environment variables from a `.env` file.
Defines the database configuration based on the application's environment.

Variables:
ENV (str): Specifies the application environment. Defaults to 'dev' if not set.
DATABASE (dict): Dictionary containing the database configuration.
- name: Name of the database.
- engine: Database engine used.
- user: Username for the database connection.
- password: Password for the database connection.
- host: Host address of the database.
- port: Port used for the database connection.
"""

import os
from dotenv import load_dotenv

# Load environment variables from the .env file.


load_dotenv()

# Set environment to 'dev' by default if 'ENV' is not provided.


ENV = os.getenv("ENV", "dev")

if ENV == "production":
DATABASE = {
"name": os.getenv("MYSQL_DATABASE"),
"engine": "peewee.MySQLDatabase", # MySQL as the database engine
"user": os.getenv("MYSQL_USER"),
"password": os.getenv("MYSQL_PASSWORD"),
"host": os.getenv("MYSQL_HOST"),
"port": int(os.getenv("MYSQL_PORT")),
}
else:
DATABASE = {
"name": os.getenv("MYSQL_DATABASE"),
"engine": "peewee.MySQLDatabase", # MySQL as the database engine
"user": os.getenv("MYSQL_USER"),
"password": os.getenv("MYSQL_PASSWORD"),
"host": os.getenv("MYSQL_HOST"),
"port": int(os.getenv("MYSQL_PORT")),
}

# Configuración de JWT
SECRET_KEY = os.getenv("SECRET_KEY")
ALGORITHM = os.getenv("ALGORITHM", "HS256")
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "30"))

File: FastAPI/app/__pycache__/database.cpython-312.pyc
======================================================
Contenido binario o no legible.

File: FastAPI/app/__pycache__/main.cpython-312.pyc
==================================================
Contenido binario o no legible.
File: FastAPI/app/__pycache__/migrations.cpython-312.pyc
========================================================
Contenido binario o no legible.

File: FastAPI/app/migrations.py
===============================
"""
Necessary imports to define data models using SQLAlchemy ORM.
- Column: Defines a column in a table.
- Integer: Integer data type for columns.
- String: Variable-length string data type.
- Text: Large text data type for columns.
- Date: Date data type for columns.
- Boolean: Boolean data type for columns.
- ForeignKey: Defines a foreign key constraint.
- CheckConstraint: Adds a check constraint to a column.
- declarative_base: Base class for declarative model definitions.
- relationship: Establishes relationships between models.
- sessionmaker: Factory for creating new Session objects.
- create_engine: Creates a new SQLAlchemy Engine instance.
"""
from sqlalchemy import Column, Integer, String, Text, Date, Boolean, ForeignKey,
CheckConstraint
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy import create_engine
from config.settings import DATABASE

# Base declarative class for SQLAlchemy models


Base = declarative_base()

class Role(Base):# pylint: disable=too-few-public-methods


"""Role table for storing user roles."""
__tablename__ = "role"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(50),nullable=False)

class Status(Base):# pylint: disable=too-few-public-methods


"""Status table defining the various states for tasks."""
__tablename__ = "status"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(255), nullable=False)

__table_args__ = (
CheckConstraint("name IN ('TO_DO', 'IN_PROGRESS', 'COMPLETED')",
name="check_status_name"),
)

class User(Base): # pylint: disable=too-few-public-methods


"""User table for storing user information and their associated roles."""
__tablename__ = "user"
id = Column(Integer, primary_key=True, index=True)
email = Column(String(100), unique=True, nullable=False)
password = Column(String(255)) # Solo aquí se maneja hashed_password
role_id = Column(Integer, ForeignKey('role.id'), nullable=True)
role = relationship("Role", back_populates="users")
is_active = Column(Boolean, default=True)

class Task(Base): # pylint: disable=too-few-public-methods


"""Task table for storing tasks with relationships to users and statuses."""
__tablename__ = "task"
id = Column(Integer, primary_key=True, index=True)
title = Column(String(100), nullable=False)
description = Column(Text, nullable=True)
date_of_creation = Column(Date, nullable=False)
expiration_date = Column(Date, nullable=True)
status_id = Column(Integer, ForeignKey('status.id'), nullable=False)
user_id = Column(Integer, ForeignKey('user.id'), nullable=False)
is_favorite = Column(Boolean, default=False)

status = relationship("Status", back_populates="tasks")


user = relationship("User", back_populates="tasks")

# Constraints for the table (comparison between columns)


__table_args__ = (
CheckConstraint(
"expiration_date IS NULL OR expiration_date >= date_of_creation",
name="check_expiration_date"
),
)

class Change(Base):# pylint: disable=too-few-public-methods


"""Change table for logging modifications to tasks."""
__tablename__ = "change"
id = Column(Integer, primary_key=True, index=True)
task_id = Column(Integer, ForeignKey('task.id'), nullable=False)
timestamp = Column(Date, nullable=False)
field_changed = Column(String(100), nullable=False)
old_value = Column(Text, nullable=True)
new_value = Column(Text, nullable=True)

task = relationship("Task", back_populates="changes")

# Configurar la base de datos


DATABASE_URL = (
f"mysql+pymysql://{DATABASE['user']}:{DATABASE['password']}@"
f"{DATABASE['host']}/{DATABASE['name']}"
)
engine = create_engine(DATABASE_URL)

# Crear una sesión de base de datos


SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

File:
FastAPI/app/alembic/versions/__pycache__/905731c6a76a_first_migrations.cpython-
312.pyc
===================================================================================
=========
Contenido binario o no legible.

File:
FastAPI/app/alembic/versions/__pycache__/6655c8f0dad7_initial_migration.cpython-
312.pyc
===================================================================================
==========
Contenido binario o no legible.

File:
FastAPI/app/alembic/versions/__pycache__/d89dc7a9d248_initial_migration.cpython-
312.pyc
===================================================================================
==========
Contenido binario o no legible.

File: FastAPI/app/alembic/versions/905731c6a76a_first_migrations.py
===================================================================
"""first_migrations

Revision ID: 905731c6a76a


Revises:
Create Date: 2024-11-06 18:26:01.991411

"""
from typing import Sequence, Union

from alembic import op


import sqlalchemy as sa

# revision identifiers, used by Alembic.


revision: str = '905731c6a76a'
down_revision: Union[str, None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None

def upgrade() -> None:


# ### commands auto generated by Alembic - please adjust! ###
op.create_table('role',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=50), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_role_id'), 'role', ['id'], unique=False)
op.create_table('status',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=255), nullable=False),
sa.CheckConstraint("name IN ('TO_DO', 'IN_PROGRESS', 'COMPLETED')",
name='check_status_name'),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_status_id'), 'status', ['id'], unique=False)
op.create_table('user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('email', sa.String(length=100), nullable=False),
sa.Column('password', sa.String(length=255), nullable=False),
sa.Column('role_id', sa.Integer(), nullable=True),
sa.Column('is_active', sa.Boolean(), nullable=True),
sa.ForeignKeyConstraint(['role_id'], ['role.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('email')
)
op.create_index(op.f('ix_user_id'), 'user', ['id'], unique=False)
op.create_table('task',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('title', sa.String(length=100), nullable=False),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('date_of_creation', sa.Date(), nullable=False),
sa.Column('expiration_date', sa.Date(), nullable=True),
sa.Column('status_id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('is_favorite', sa.Boolean(), nullable=True),
sa.CheckConstraint('expiration_date IS NULL OR expiration_date >=
date_of_creation', name='check_expiration_date'),
sa.ForeignKeyConstraint(['status_id'], ['status.id'], ),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_task_id'), 'task', ['id'], unique=False)
op.create_table('change',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('task_id', sa.Integer(), nullable=False),
sa.Column('timestamp', sa.Date(), nullable=False),
sa.Column('field_changed', sa.String(length=100), nullable=False),
sa.Column('old_value', sa.Text(), nullable=True),
sa.Column('new_value', sa.Text(), nullable=True),
sa.ForeignKeyConstraint(['task_id'], ['task.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_change_id'), 'change', ['id'], unique=False)
# ### end Alembic commands ###
op.execute("""
INSERT INTO status (name)
VALUES ('TO_DO'), ('IN_PROGRESS'), ('COMPLETED');
""")

# Insertar los roles por defecto


op.execute("""
INSERT INTO role (name)
VALUES ('Administrator'), ('User');
""")

def downgrade() -> None:


# Borrar los datos insertados durante la migración
op.execute("""
DELETE FROM status WHERE name IN ('TO_DO', 'IN_PROGRESS', 'COMPLETED');
""")

op.execute("""
DELETE FROM role WHERE name IN ('Administrator', 'User');
""")

def downgrade() -> None:


# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_change_id'), table_name='change')
op.drop_table('change')
op.drop_index(op.f('ix_task_id'), table_name='task')
op.drop_table('task')
op.drop_index(op.f('ix_user_id'), table_name='user')
op.drop_table('user')
op.drop_index(op.f('ix_status_id'), table_name='status')
op.drop_table('status')
op.drop_index(op.f('ix_role_id'), table_name='role')
op.drop_table('role')
# ### end Alembic commands ###

File: FastAPI/app/alembic/env.py
================================
"""
Este módulo configura Alembic para manejar migraciones de base de datos.

Se encarga de establecer la conexión a la base de datos y definir


el comportamiento de las migraciones, tanto en modo 'offline' como 'online'.
"""

from logging.config import fileConfig


from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
from migrations import Base, DATABASE_URL # pylint: disable=import-error

# Este objeto de configuración de Alembic proporciona acceso a los


# valores dentro del archivo .ini en uso.
config = context.config # pylint: disable=no-member
config.set_main_option("sqlalchemy.url", DATABASE_URL)

# Interpreta el archivo de configuración para la configuración de registro.


# Esta línea configura los registradores en esencia.
if config.config_file_name is not None:
fileConfig(config.config_file_name)

# Agrega el objeto MetaData de tu modelo aquí para el soporte de 'autogenerar'


target_metadata = Base.metadata

def run_migrations_offline() -> None:


"""Ejecuta migraciones en modo 'offline'.

Esto configura el contexto solo con una URL y no con un Engine,


aunque un Engine es aceptable aquí también. Al omitir la creación
del Engine, ni siquiera necesitamos que un DBAPI esté disponible.

Las llamadas a context.execute() aquí emiten la cadena dada en


la salida del script.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure( # pylint: disable=no-member
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction(): # pylint: disable=no-member
context.run_migrations() # pylint: disable=no-member

def run_migrations_online() -> None:


"""Ejecuta migraciones en modo 'online'.

En este escenario, necesitamos crear un Engine y asociar una


conexión con el contexto.
"""
connectable = engine_from_config(
config.get_section(config.config_ini_section, {}),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)

with connectable.connect() as connection:


context.configure(connection=connection, target_metadata=target_metadata) #
pylint: disable=no-member

with context.begin_transaction(): # pylint: disable=no-member


context.run_migrations() # pylint: disable=no-member

if context.is_offline_mode(): # pylint: disable=no-member


run_migrations_offline()
else:
run_migrations_online()

File: FastAPI/app/alembic/script.py.mako
========================================
Contenido binario o no legible.

File: FastAPI/app/alembic/__pycache__/env.cpython-312.pyc
=========================================================
Contenido binario o no legible.

File: FastAPI/app/alembic/README
================================
Contenido binario o no legible.

File: FastAPI/app/services/__pycache__/user_service.cpython-312.pyc
===================================================================
Contenido binario o no legible.

File: FastAPI/app/services/__pycache__/__init__.cpython-312.pyc
===============================================================
Contenido binario o no legible.

File: FastAPI/app/services/__pycache__/auth_service.cpython-312.pyc
===================================================================
Contenido binario o no legible.
File: FastAPI/app/services/__pycache__/task_service.cpython-312.pyc
===================================================================
Contenido binario o no legible.

File: FastAPI/app/services/auth_service.py
==========================================
"""
Authentication Service for handling password hashing and JWT.

Includes functions for verifying passwords, hashing passwords,


authenticating users, and creating access tokens.
"""
from datetime import datetime, timedelta
from typing import Optional

from fastapi import HTTPException, status


from jose import JWTError, jwt
from passlib.context import CryptContext
from config.settings import SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES
from services.user_service import UserService
from models.user import UserRead # Asegúrate de importar UserRead correctamente
from config.database import UserModel
# Configurar passlib context para password hashing

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

class AuthService:
"""Authentication Service."""

@staticmethod
def verify_password(plain_password: str, password: str) -> bool:
"""Verifica si la contraseña en texto plano coincide con la contraseña
hasheada."""
return pwd_context.verify(plain_password, password)

@staticmethod
def get_password_hash(password: str) -> str:
"""Hashea una contraseña en texto plano antes de almacenarla."""
return pwd_context.hash(password)

@staticmethod
def authenticate_user(email: str, password: str) -> Optional[UserModel]:
"""
Autentica a un usuario utilizando su email y contraseña.
"""
user = UserService.get_user_by_email_login(email)
if not user or not AuthService.verify_password(password, user.password): #
Usa `user.password`
return None
return user

@staticmethod
def create_access_token(
data: dict, expires_delta: Optional[timedelta] = None
) -> str:
"""
Crea un token de acceso JWT.
"""
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() +
timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt

@staticmethod
def get_current_user(token: str) -> Optional[UserRead]:
"""
Decodes the JWT token and retrieves the user based on the email.
"""
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
# Decodifica el token JWT
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
email: str = payload.get("sub")
if email is None:
raise credentials_exception
except JWTError:
raise credentials_exception

# Busca el usuario en la base de datos usando el email


user = UserService.get_user_by_email(email)
if user is None:
raise credentials_exception
return user

File: FastAPI/app/services/__init__.py
======================================

File: FastAPI/app/services/user_service.py
==========================================
"""
Service layer for User operations.

This module contains the business logic for managing users.


It interacts with the `UserModel` and uses the `User` model from Pydantic for data
validation.
"""

from typing import Optional, List


from peewee import DoesNotExist
from config.database import UserModel, RoleModel
from models.user import UserRead
from models.role import Role

class UserService:
"""Service layer for User operations."""
@staticmethod
def create_user(email: str, password: str, role_id: int) -> UserRead:
"""
Crear un nuevo usuario.
"""
try:
role_instance = RoleModel.get_by_id(role_id)
user_instance = UserModel.create(email=email, password=password,
role=role_instance)

# Preparar datos para Pydantic


user_data = user_instance.__data__.copy()
user_data['role_id'] = role_instance.id # Añadir role_id
explícitamente

# Serializar el campo 'role' correctamente


role_data = {
"id": role_instance.id,
"name": role_instance.name
}
user_data['role'] = Role.model_validate(role_data) # Usar el modelo
Pydantic Role

return UserRead.model_validate(user_data)
except DoesNotExist as exc:
raise ValueError(f"Role with id {role_id} not found") from exc

@staticmethod
def get_user_by_email_login(email: str) -> Optional[UserModel]:
"""
Recupera el usuario completo desde la base de datos por su email.
"""
try:
return UserModel.get(UserModel.email == email)
except UserModel.DoesNotExist:
return None

@staticmethod
def get_user_by_email(email: str) -> Optional[UserRead]:
"""
Obtener un usuario por su email.
"""
try:
user_instance = UserModel.get(UserModel.email == email)
user_data = user_instance.__data__.copy()
user_data['role_id'] = user_instance.role.id # Añadir role_id
explícitamente

# Serializar el campo 'role' correctamente


role_instance = user_instance.role
role_data = {
"id": role_instance.id,
"name": role_instance.name
}
user_data['role'] = Role.model_validate(role_data) # Usar el modelo
Pydantic Role
return UserRead.model_validate(user_data)
except DoesNotExist:
return None

@staticmethod
def get_user_by_id(user_id: int) -> Optional[UserRead]:
"""
Obtener un usuario por su ID.
"""
try:
user_instance = UserModel.get_by_id(user_id)
user_data = user_instance.__data__.copy()
user_data['role_id'] = user_instance.role.id # Añadir role_id
explícitamente

# Serializar el campo 'role' correctamente


role_instance = user_instance.role
role_data = {
"id": role_instance.id,
"name": role_instance.name
}
user_data['role'] = Role.model_validate(role_data) # Usar el modelo
Pydantic Role

return UserRead.model_validate(user_data)
except DoesNotExist:
return None

@staticmethod
def update_user_status(user_id: int, is_active: bool) -> bool:
"""
Actualiza el estado activo de un usuario.
"""
try:
user_instance = UserModel.get_by_id(user_id)
user_instance.is_active = is_active
user_instance.save()
return True
except DoesNotExist:
return False

@staticmethod
def update_user(
user_id: int,
email: Optional[str] = None,
password: Optional[str] = None,
role_id: Optional[int] = None,
) -> Optional[UserRead]:
"""
Actualizar un usuario existente por su ID.
"""
try:
user_instance = UserModel.get_by_id(user_id)

if email:
user_instance.email = email
if password:
user_instance.password = password
if role_id:
try:
role_instance = RoleModel.get_by_id(role_id)
user_instance.role = role_instance
except DoesNotExist as exc:
raise ValueError(f"Role with id {role_id} not found") from exc

user_instance.save()

# Preparar datos para Pydantic


user_data = user_instance.__data__.copy()
user_data['role_id'] = user_instance.role.id
user_data['role'] = user_instance.role

return UserRead.model_validate(user_data)
except DoesNotExist:
return None

@staticmethod
def delete_user(user_id: int) -> bool:
"""
Eliminar un usuario por su ID.
"""
try:
user_instance = UserModel.get_by_id(user_id)
user_instance.delete_instance()
return True
except DoesNotExist:
return False

@staticmethod
def list_all_users() -> List[UserRead]:
"""
Obtener una lista de todos los usuarios.
"""
users = UserModel.select().where(UserModel.role == 2)
return users

File: FastAPI/app/services/task_service.py
==========================================
"""
Module defining services for managing tasks.
"""

from datetime import date, datetime


from typing import List, Optional
from models.task import Task
from models.change import Change
from config.database import TaskModel, ChangeModel

class TaskService:
"""
Module defining the services.
"""

@staticmethod
def create_task(
title: str,
description: Optional[str],
expiration_date: Optional[date],
status_id: int,
user_id: int,
) -> TaskModel: # Devuelve el modelo de la base de datos
"""Creates a new task."""
task = TaskModel.create( # Asegúrate de usar el modelo ORM aquí
title=title,
description=description,
expiration_date=expiration_date,
status_id=status_id,
user_id=user_id,
)
return task

@staticmethod
def get_task_by_id(task_id: int, user_id: int, is_admin: bool) ->
Optional[TaskModel]:
"""Retrieves a task by ID, checking user permissions."""
task = TaskModel.get_or_none(TaskModel.id == task_id) # Usa el modelo ORM
aquí
if task and (task.user_id == user_id or is_admin):
return task
return None

@staticmethod
def update_task(
task_id: int, user_id: int, is_admin: bool, **updates
) -> Optional[Task]:
"""Updates a task, logging changes, and checking user permissions."""
task = TaskModel.get_or_none(TaskModel.id == task_id)
if task and (task.user_id == user_id or is_admin):
for key, value in updates.items():
setattr(task, key, value)
task.save()

# Log changes to the change history


for field, new_value in updates.items():
ChangeModel.create(
task=task,
field_changed=field,
old_value=getattr(task, field, None),
new_value=new_value,
)
return task
return None

@staticmethod
def delete_task(task_id: int, user_id: int, is_admin: bool) -> bool:
"""Deletes a task, checking user permissions."""
task = TaskModel.get_or_none(TaskModel.id == task_id)
if task and (task.user_id == user_id or is_admin):
task.delete_instance()
return True
return False

@staticmethod
def list_tasks(
user_id: int,
status: Optional[str],
expiration_date: Optional[date],
is_admin: bool,
) -> List[Task]:
"""Lists tasks, applying filters and checking user permissions."""
query = TaskModel.select().where((TaskModel.user_id == user_id) |
(is_admin))
if status:
query = query.where(TaskModel.status_id == status)
if expiration_date:
query = query.where(TaskModel.expiration_date <= expiration_date)
return list(query)

@staticmethod
def toggle_favorite(task_id: int, user_id: int, is_admin: bool) ->
Optional[Task]:
"""Toggles the favorite status of a task, checking user permissions."""
task = TaskModel.get_or_none(TaskModel.id == task_id)
if task and (task.user_id == user_id or is_admin):
task.is_favorite = not task.is_favorite
task.save()
return task
return None

@staticmethod
def get_changes_by_task_id(task_id: int) -> List[Change]:
"""Retrieves changes for a specific task."""
return list(
ChangeModel.select()
.where(ChangeModel.task == task_id)
.order_by(ChangeModel.timestamp.desc())
)

File: FastAPI/app/main.py
=========================
"""
Main module for the FastAPI application.
"""

from contextlib import asynccontextmanager


from fastapi import FastAPI
from starlette.responses import RedirectResponse
from routes import auth_router, task_router, user_management_router
from config.database import database as connection

@asynccontextmanager
async def lifespan(api: FastAPI):
if connection.is_closed():
connection.connect()
try:
yield
finally:
if not connection.is_closed():
connection.close()

app = FastAPI(lifespan=lifespan)

@app.get("/")
async def docs_redirect():
"""Redirige a la documentación de la API."""
return RedirectResponse(url="/docs")

app.include_router(auth_router)
app.include_router(task_router)
app.include_router(user_management_router)

File: FastAPI/app/utils/__pycache__/__init__.cpython-312.pyc
============================================================
Contenido binario o no legible.

File: FastAPI/app/utils/__pycache__/dependencies.cpython-312.pyc
================================================================
Contenido binario o no legible.

File: FastAPI/app/utils/dependencies.py
=======================================
"""
Security dependencies for authentication and authorization handling.
Includes functions to obtain the current user and verify roles.
"""
from fastapi import Depends, HTTPException, status, Form
from fastapi.security import OAuth2PasswordBearer

from models.user import UserRead


from services.auth_service import AuthService

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/login")

class OAuth2PasswordRequestFormEmail:
def __init__(self, email: str = Form(...), password: str = Form(...)):
self.email = email
self.password = password

def get_current_user(token: str = Depends(oauth2_scheme)) -> UserRead:


"""Retrieves the current user from the JWT token."""
user = AuthService.get_current_user(token)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
return user

def get_current_active_user(current_user: UserRead = Depends(get_current_user)) ->


UserRead:
"""Verifies that the user is active."""
if not current_user.is_active:
raise HTTPException(status_code=400, detail="Inactive user")
return current_user

def get_current_admin(current_user: UserRead = Depends(get_current_user)) ->


UserRead:
"""Verifies if the user is an administrator."""
if current_user.role.name != "Administrator":
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access forbidden: Administrator access required"
)
return current_user

File: FastAPI/app/utils/__init__.py
===================================

File: FastAPI/app/routes/task_routes.py
=======================================
"""
Module defining routes for managing tasks.

This module uses FastAPI to define routes that allow


creating, reading, updating, and deleting tasks through a REST API.
"""
from datetime import date
from typing import List, Optional
from fastapi import APIRouter, HTTPException, Depends, status
from models.user import UserRead
from models.task import Task, TaskUpdate, TaskCreate
from models.change import Change
from services.task_service import TaskService
from utils.dependencies import get_current_user

router = APIRouter(
prefix="/tasks",
tags=["tasks"],
)
@router.post("/", response_model=Task, status_code=status.HTTP_201_CREATED)
def create_task(
task_data: TaskCreate,
current_user: UserRead = Depends(get_current_user)
) -> Task:
task_model = TaskService.create_task(
title=task_data.title,
description=task_data.description,
expiration_date=task_data.expiration_date,
status_id=task_data.status_id,
user_id=current_user.id
)
# Convierte el modelo ORM a un modelo Pydantic
return Task.from_orm(task_model)

@router.get("/{task_id}", response_model=Task)
def get_task(
task_id: int,
current_user: UserRead = Depends(get_current_user)
) -> Task:
"""
Get a task by its ID.
"""
is_admin = current_user.role.name == "Administrator"
task = TaskService.get_task_by_id(task_id, user_id=current_user.id,
is_admin=is_admin)
if task:
return Task.from_orm(task) # Convierte de ORM a modelo Pydantic
raise HTTPException(status_code=404, detail="Task not found")

@router.put("/{task_id}", response_model=Task)
def update_task(
task_id: int,
task_update: TaskUpdate,
current_user: UserRead = Depends(get_current_user) # Cambiado de User a
UserRead
) -> Task:
"""Update an existing task."""
is_admin = current_user.role.name == "Administrator"
task = TaskService.update_task(
task_id=task_id,
user_id=current_user.id,
is_admin=is_admin,
**task_update.model_dump(exclude_unset=True)
)
if task:
return task
raise HTTPException(status_code=404, detail="Task not found")

@router.delete("/{task_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_task(
task_id: int,
current_user: UserRead = Depends(get_current_user) # Cambiado de User a
UserRead
):
"""
Delete a task by its ID.
"""
is_admin = current_user.role.name == "Administrator"
success = TaskService.delete_task(
task_id=task_id,
user_id=current_user.id,
is_admin=is_admin
)
if success:
return
raise HTTPException(status_code=404, detail="Task not found")

@router.get("/", response_model=List[Task])
def list_tasks(
task_status: Optional[str] = None,
expiration_date: Optional[date] = None,
current_user: UserRead = Depends(get_current_user) # Cambiado de User a
UserRead
) -> List[Task]:
"""
List all tasks for the user with filtering options.
"""
is_admin = current_user.role.name == "Administrator"
tasks = TaskService.list_tasks(
user_id=current_user.id,
status=task_status,
expiration_date=expiration_date,
is_admin=is_admin
)
return tasks

@router.patch("/{task_id}/favorite", response_model=Task)
def toggle_favorite(
task_id: int,
current_user: UserRead = Depends(get_current_user) # Cambiado de User a
UserRead
) -> Task:
"""
Toggle the favorite status of a task.
"""
is_admin = current_user.role.name == "Administrator"
task = TaskService.toggle_favorite(
task_id=task_id,
user_id=current_user.id,
is_admin=is_admin
)
if task:
return task
raise HTTPException(status_code=404, detail="Task not found")

@router.get("/{task_id}/changes", response_model=List[Change])
def get_task_changes(
task_id: int,
current_user: UserRead = Depends(get_current_user) # Cambiado de User a
UserRead
) -> List[Change]:
"""
Get the change history of a specific task.
"""
is_admin = current_user.role.name == "Administrator"
task = TaskService.get_task_by_id(task_id, user_id=current_user.id,
is_admin=is_admin)
if not task:
raise HTTPException(status_code=404, detail="Task not found")

changes = TaskService.get_changes_by_task_id(task_id)
return changes

File: FastAPI/app/routes/auth_routes.py
=======================================
"""
Module defining authentication routes.

Includes endpoints for user registration and login,


providing JWT tokens for authentication.
"""
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, status, Form
from pydantic import BaseModel, EmailStr
from datetime import timedelta
from config.settings import ACCESS_TOKEN_EXPIRE_MINUTES
from models.user import UserRead, UserCreate
from services.auth_service import AuthService
from services.user_service import UserService
from utils.dependencies import OAuth2PasswordRequestFormEmail

router = APIRouter(
tags=["Authentication"],
)

class Token(BaseModel):
access_token: str
token_type: str

class TokenData(BaseModel):
email: Optional[EmailStr] = None

@router.post("/register", response_model=UserRead,
status_code=status.HTTP_201_CREATED)
def register(user: UserCreate):
existing_user = UserService.get_user_by_email(user.email)
if existing_user:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Email already registered",
)
hashed_password = AuthService.get_password_hash(user.password)
try:
new_user = UserService.create_user(
email=user.email,
password=hashed_password,
role_id=user.role_id
)
return new_user
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
) from e

@router.post("/login", response_model=Token)
def login(form_data: OAuth2PasswordRequestFormEmail = Depends()):
# Autenticación usando el email
user = AuthService.authenticate_user(form_data.email, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid credentials",
headers={"WWW-Authenticate": "Bearer"},
)
access_token = AuthService.create_access_token(
data={"sub": user.email} # Guarda el email en el token
)
return {"access_token": access_token, "token_type": "bearer"}

File: FastAPI/app/routes/__pycache__/task_routes.cpython-312.pyc
================================================================
Contenido binario o no legible.
File: FastAPI/app/routes/__pycache__/user_management_routes.cpython-312.pyc
===========================================================================
Contenido binario o no legible.

File: FastAPI/app/routes/__pycache__/__init__.cpython-312.pyc
=============================================================
Contenido binario o no legible.

File: FastAPI/app/routes/__pycache__/auth_routes.cpython-312.pyc
================================================================
Contenido binario o no legible.

File: FastAPI/app/routes/user_management_routes.py
==================================================
"""
Module that defines routes for managing users.

This module uses FastAPI to define the routes that allow


creating, reading, updating, and deleting users through a REST API.
"""
from typing import List
from fastapi import APIRouter, HTTPException, Depends, status
from models.user import UserRead, UserCreate, UserUpdate
from services.user_service import UserService
from utils.dependencies import get_current_admin

router = APIRouter(
prefix="/admin/users",
tags=["admin users"],
)

# Helper function to verify admin permissions


def verify_admin(current_admin: UserRead): # Cambiar tipo a UserRead
"""Verifies if the user is an administrator."""
if current_admin.role.name != "Administrator":
raise HTTPException(status_code=403, detail="Insufficient permissions")

@router.get("/", response_model=List[UserRead])
def list_users() -> List[UserRead]:
"""List all registered users."""
return UserService.list_all_users()

@router.post("/", response_model=UserRead, status_code=status.HTTP_201_CREATED)


def create_user(
user: UserCreate,
current_admin: UserRead = Depends(get_current_admin) # Cambiar tipo a UserRead
) -> UserRead:
# """Create a new user (for administrators only)."""
verify_admin(current_admin)

try:
created_user = UserService.create_user(
email=user.email, password=user.password, role_id=user.role_id
)
return created_user
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e)) from e
except Exception as e:
raise HTTPException(status_code=500, detail="Error creating user") from e

@router.get("/{user_id}", response_model=UserRead)
def get_user(
user_id: int,
current_admin: UserRead = Depends(get_current_admin) # Cambiar tipo a UserRead
) -> UserRead:
"""Get user information by their ID (for administrators only)."""
verify_admin(current_admin)

user = UserService.get_user_by_id(user_id)
if user:
return user
raise HTTPException(status_code=404, detail="User not found")

@router.put("/{user_id}", response_model=UserRead)
def update_user(
user_id: int,
user_update: UserUpdate,
current_admin: UserRead = Depends(get_current_admin) # Cambiar tipo a UserRead
) -> UserRead:
"""Update existing user information (for administrators only)."""
verify_admin(current_admin)

updates = {}
if user_update.email is not None:
updates['email'] = user_update.email
if user_update.password is not None:
updates['password'] = user_update.password # Hash the password before
calling
if user_update.role_id is not None:
updates['role_id'] = user_update.role_id

if not updates:
raise HTTPException(status_code=400, detail="No data to update")

try:
user = UserService.update_user(
user_id=user_id,
email=updates.get("email"),
password=updates.get("password"),
role_id=updates.get("role_id")
)
if user:
return user
raise HTTPException(status_code=404, detail="User not found")
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e)) from e

@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_user(
user_id: int,
current_admin: UserRead = Depends(get_current_admin) # Cambiar tipo a UserRead
):
"""Deletes a user by their ID (admin only)."""
verify_admin(current_admin)
success = UserService.delete_user(user_id)
if success:
return
raise HTTPException(status_code=404, detail="User not found")

@router.patch("/{user_id}/active")
def toggle_user_active(
user_id: int,
current_admin: UserRead = Depends(get_current_admin) # Cambiar tipo a UserRead
):
"""Activate or deactivate a user (for administrators only)."""
verify_admin(current_admin)

user = UserService.get_user_by_id(user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")

user.is_active = not user.is_active


# Ya que UserRead es de solo lectura, necesitas actualizar el modelo ORM
directamente
UserService.update_user_status(user_id, user.is_active)
return {"message": f"User {user_id} is now {'active' if user.is_active else
'inactive'}"}

File: FastAPI/app/routes/__init__.py
====================================
"""
init.py
"""
from .auth_routes import router as auth_router
from .task_routes import router as task_router
from .user_management_routes import router as user_management_router

__all__ = ["auth_router", "task_router", "user_management_router"]

File: FastAPI/app/alembic.ini
=============================
Contenido binario o no legible.

File: FastAPI/alembic.ini
=========================
Contenido binario o no legible.

File: FastAPI/.dockerignore
===========================
Contenido binario o no legible.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy