diff --git a/.env b/.env new file mode 100644 index 0000000..5ac8855 --- /dev/null +++ b/.env @@ -0,0 +1,9 @@ +db_username=postgres # default for windows +db_password= #give it the password used when installing postgres +db_hostname=localhost +db_port=5432 +db_name=postgres #name it anything you want + +secret_key= #give it a strong secret key +algorithm=HS256 +access_token_expire_minutes=30 diff --git a/.gitignore b/.gitignore index 88cc6a1..fb86f22 100644 --- a/.gitignore +++ b/.gitignore @@ -19,11 +19,11 @@ env docs_build site_build venv +venv311 docs.zip archive.zip # alembic alembic/versions/ -.env # vim temporary files *~ .*.sw? diff --git a/README.md b/README.md index 7d2fcdd..8dcb2b7 100644 --- a/README.md +++ b/README.md @@ -111,25 +111,29 @@ A simple Ecommerce API built with Fast API Framework ## Installation -1. **Clone the repository:** +1. **Install Python 3.11** + [Python 3.11 download link](https://www.python.org/downloads/release/python-3110/) + + +2. **Clone the repository:** ```bash git clone https://github.com/aliseyedi01/Ecommerce-Api.git ``` -2. **Navigate to the project directory:** +3. **Navigate to the project directory:** ```bash Ecommerce-Api ``` -3. **Create a virtual environment:** +4. **Create a virtual environment:** ```bash - python3 -m venv venv + python3.11 -m venv venv ``` -4. **Activate the virtual environment:** +5. **Activate the virtual environment:** On Windows: @@ -143,23 +147,31 @@ A simple Ecommerce API built with Fast API Framework source venv/bin/activate ``` -5. **Install dependencies:** +6. **Install dependencies:** ```bash pip install -r requirements.txt ``` +7. **Install postgresql** + + + ## Usage -1. **Run Alembic migrations:** +1. **Edit .env file** + + + +2. **Run Alembic migrations:** ```bash python migrate.py ``` - + if you got error create **versions** directory inside alembic folder. This will apply any pending database migrations. -2. **Run the FastAPI development server:** +3. **Run the FastAPI development server:** ```bash python run.py @@ -167,15 +179,42 @@ A simple Ecommerce API built with Fast API Framework The API will be accessible at [http://127.0.0.1:8000/](http://127.0.0.1:8000/) -3. **Access the Swagger UI and ReDoc:** +4. **Access the Swagger UI and ReDoc:** - Swagger UI: [http://127.0.0.1:8000/docs/](http://127.0.0.1:8000/docs/) - ReDoc: [http://127.0.0.1:8000/redoc/](http://127.0.0.1:8000/redoc/) +5. **First sign up using Swagger** + +6. **Update the first user to admin** + connect to database like this : + ```bash + psql -h localhost -U postgres -d postgres + ``` + with ``` \dt ``` you should see tables. + with + ```sql + SELECT id, username, email, role FROM users; + ``` + you can see the user you created earlier. the role is user for default. + now we change the role to admin with : + ```sql + UPDATE users + SET role = 'admin' + WHERE id = 1; + ``` + enter it line by line.(change your id if it's different) + **Congrats** now you have admin privilage. + + to use swagger simply login with this user. then get the "access_token" from the login response. + + use this token to Authorize. + now you aceess all the request types. + ## Contributing diff --git a/alembic/env.py b/alembic/env.py index ed3645a..1e53250 100644 --- a/alembic/env.py +++ b/alembic/env.py @@ -7,18 +7,23 @@ from app.core.config import settings from app.db.database import Base -config = context.config +# IMPORT ALL MODELS - This is crucial for Alembic to detect them +from app.models.models import User, Cart, CartItem, Category, Product +config = context.config config.set_main_option( "sqlalchemy.url", f"postgresql://{settings.db_username}:{settings.db_password}@{settings.db_hostname}:{settings.db_port}/{settings.db_name}") - if config.config_file_name is not None: fileConfig(config.config_file_name) target_metadata = Base.metadata +# Debug: Print detected tables +print("=== TARGET METADATA DEBUG ===") +print(f"Tables to create: {list(target_metadata.tables.keys())}") +print("================================") def run_migrations_offline() -> None: url = config.get_main_option("sqlalchemy.url") @@ -32,24 +37,40 @@ def run_migrations_offline() -> None: with context.begin_transaction(): context.run_migrations() - def run_migrations_online() -> None: - 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 + print("=== STARTING MIGRATIONS ===") + + # Debug: Print the connection URL (hide password) + url = config.get_main_option("sqlalchemy.url") + print(f"Database URL: {url.replace(':' + settings.db_password, ':****')}") + + try: + connectable = engine_from_config( + config.get_section(config.config_ini_section, {}), + prefix="sqlalchemy.", + poolclass=pool.NullPool, ) - - with context.begin_transaction(): - context.run_migrations() - + print("Database engine created successfully") + + with connectable.connect() as connection: + print("Database connection established") + + context.configure( + connection=connection, target_metadata=target_metadata + ) + + with context.begin_transaction(): + print("Running migrations...") + context.run_migrations() + print("Migrations completed") + + except Exception as e: + print(f"Migration error: {e}") + import traceback + traceback.print_exc() + raise if context.is_offline_mode(): run_migrations_offline() else: - run_migrations_online() + run_migrations_online() \ No newline at end of file diff --git a/migrate.py b/migrate.py index ddabcd7..0613109 100644 --- a/migrate.py +++ b/migrate.py @@ -1,6 +1,52 @@ # migrate.py +import os from alembic.config import Config from alembic import command +from alembic.script import ScriptDirectory -alembic_cfg = Config("alembic.ini") -command.upgrade(alembic_cfg, "head") +def run_migrations(): + # Load Alembic configuration + alembic_cfg = Config("alembic.ini") + + # Get the script directory (where migration files are stored) + script = ScriptDirectory.from_config(alembic_cfg) + + # Check if any migration files exist + versions_dir = script.versions + migration_files = [f for f in os.listdir(versions_dir) if f.endswith('.py') and f != '__pycache__'] + + print(f"Checking migrations in: {versions_dir}") + print(f"Found {len(migration_files)} migration files") + + # If no migration files exist, create initial migration + if not migration_files: + print("No migration files found. Creating initial migration...") + try: + command.revision(alembic_cfg, autogenerate=True, message="Create initial tables") + print("✓ Initial migration created successfully") + except Exception as e: + print(f"✗ Error creating initial migration: {e}") + return False + else: + print("Migration files already exist:") + for file in migration_files: + print(f" - {file}") + + # Run all pending migrations + print("Running migrations...") + try: + command.upgrade(alembic_cfg, "head") + print("✓ All migrations completed successfully") + return True + except Exception as e: + print(f"✗ Error running migrations: {e}") + return False + +if __name__ == "__main__": + print("=== Database Migration Script ===") + success = run_migrations() + if success: + print("=== Migration process completed ===") + else: + print("=== Migration process failed ===") + exit(1) \ No newline at end of file