Skip to content

Commit

Permalink
Just to share relevant links
Browse files Browse the repository at this point in the history
  • Loading branch information
lifeisacanvas24 committed Oct 13, 2024
1 parent 922783f commit fa6a8ee
Show file tree
Hide file tree
Showing 15 changed files with 126 additions and 116 deletions.
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
# Ignore the Zola build output folder
working-rough-css-lifeisacanvas/


#Ignore the venv environment related
bin/
include/
lib/
lib64/
pyenv.cfg

## Ignore Db files
admin_app.db
test.db


# Ignore temporary files created by editors or OS
*.swp
*.swo
Expand Down
Binary file modified zola-admin/app/__pycache__/auth.cpython-312.pyc
Binary file not shown.
Binary file modified zola-admin/app/__pycache__/crud.cpython-312.pyc
Binary file not shown.
Binary file modified zola-admin/app/__pycache__/database.cpython-312.pyc
Binary file not shown.
Binary file modified zola-admin/app/__pycache__/main.cpython-312.pyc
Binary file not shown.
Binary file modified zola-admin/app/__pycache__/models.cpython-312.pyc
Binary file not shown.
20 changes: 2 additions & 18 deletions zola-admin/app/crud.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# app/crud.py
from sqlalchemy.orm import Session
from fastapi import HTTPException, Request # Import Request from FastAPI
from app.models import User
from app.schemas import UserCreate # Ensure this is the updated version without email
from fastapi import HTTPException, Request
from app.models import User, UserCreate # Import UserCreate from models
from app.utils import hash_password
import logging

Expand All @@ -14,21 +13,6 @@ def get_user(db: Session, username: str):
raise HTTPException(status_code=404, detail="User not found")
return user

# Function to get the user from the session token
async def get_user_from_token(request: Request):
"""Retrieve user from the session token."""
token = request.cookies.get("session_token")
# Logic to fetch the user from the token or session
# This should return a User object
if not token:
raise HTTPException(status_code=401, detail="Unauthorized")

user = await get_user_by_token(token) # Implement this function to return a User object
if user is None:
raise HTTPException(status_code=401, detail="User not found")

return user

# Function to create a new user
def create_user(db: Session, user: UserCreate):
"""Create a new user in the database."""
Expand Down
6 changes: 4 additions & 2 deletions zola-admin/app/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
import os
from passlib.context import CryptContext

# Define the path for the database file
db_path = os.path.join(os.path.dirname(__file__), 'zola_admin.db')
Expand All @@ -15,6 +16,9 @@
# Base class for declarative models
Base = declarative_base()

# Password context for hashing
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# Dependency to get DB session
def get_db():
db = SessionLocal()
Expand Down Expand Up @@ -49,5 +53,3 @@ class AnotherModel(Base):

id = Column(Integer, primary_key=True, index=True)
some_field = Column(String)

# You can define more models here as required
99 changes: 59 additions & 40 deletions zola-admin/app/main.py
Original file line number Diff line number Diff line change
@@ -1,106 +1,125 @@
# app/main.py
from fastapi.middleware.cors import CORSMiddleware # Ensure this is included
from fastapi import FastAPI, Depends, Request, Form, HTTPException
from fastapi.responses import RedirectResponse, HTMLResponse
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi.staticfiles import StaticFiles
from contextlib import asynccontextmanager # Add this line
import logging

# Import your auth, crud, database, and routers here
from app.auth import authenticate_user, get_current_user, get_user_id_from_cookie
from app.crud import create_user
from app.init_db import init_db
from app.dependencies import get_db
from app.database import init_db, get_db
from app.routers import user as user_router
from app.routers import admin as admin_router
from app.database import Base, engine
from fastapi.staticfiles import StaticFiles
from contextlib import asynccontextmanager
from starlette.middleware.base import BaseHTTPMiddleware
import logging

# Logging configuration
logging.basicConfig(level=logging.INFO)
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)

# Initialize Jinja2 templates
templates = Jinja2Templates(directory="app/templates")

# Create FastAPI app
app = FastAPI()

# Async context manager to handle the lifespan of the app (e.g., database connections)
@asynccontextmanager
async def lifespan(app: FastAPI):
init_db() # Initialize database connection or other startup tasks
init_db() # Initialize the database on app startup
yield # This is where the app runs

@asynccontextmanager
async def get_db_session():
"""Session generator for database interactions"""
db = next(get_db()) # Use the get_db() dependency for getting the session

# Middleware to log and retrieve user from cookie
@app.middleware("http")
async def dispatch(request: Request, call_next):
try:
yield db
finally:
db.close()
# Allow access to the login page
if request.url.path == "/admin/" or request.url.path == "/login/":
response = await call_next(request)
return response

# Attempt to get the user from cookies
user_id = get_user_id_from_cookie(request.cookies.get("user_id"))
request.state.user = await get_current_user(get_db(), user_id)

app = FastAPI(lifespan=lifespan)
response = await call_next(request)
return response
except Exception as e:
logging.error(f"Error in middleware: {str(e)}")
raise HTTPException(status_code=403, detail="Not authenticated")

# Include routers
# Include admin routes
app.include_router(admin_router.router, prefix="/admin", tags=["admin"])
app.include_router(user_router.router, prefix="/users", tags=["users"])

class AddUserMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
async with get_db_session() as db:
user_id = get_user_id_from_cookie(request.cookies.get("user_id"))
if user_id:
try:
request.state.user = await get_current_user(db=db, user_id=user_id) # Use await here
logging.info(f"User retrieved: {request.state.user.username}")
except HTTPException as e:
logging.error(f"HTTPException in middleware: {e.detail}")
request.state.user = None
else:
logging.warning("No user_id cookie found.")
request.state.user = None
# Add CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Adjust this as necessary
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

response = await call_next(request)
return response

app.add_middleware(AddUserMiddleware)
# Mount static files (e.g., CSS, JavaScript)
app.mount("/static", StaticFiles(directory="app/static"), name="static")
templates = Jinja2Templates(directory="app/templates")

# Root route
@app.get("/")
async def read_root():
return {"message": "Welcome to the Admin Dashboard"}

# Admin login page
@app.get("/admin/")
async def login_page(request: Request):
return templates.TemplateResponse("login.html", {"request": request, "user": request.state.user})
return templates.TemplateResponse("login.html", {"request": request, "title": "Admin Login"})

# Admin login form submission
@app.post("/login/", response_model=None)
async def login(request: Request, username: str = Form(...), password: str = Form(...), db: Session = Depends(get_db)):
user = authenticate_user(username, password, db)
if not user:
logging.warning(f"Failed login attempt for user: {username}")
return templates.TemplateResponse("login.html", {
"request": request, "error": "Invalid credentials, please try again."
"request": request,
"title": "Admin Login",
"error": "Invalid credentials, please try again."
})

response = RedirectResponse(url="/dashboard/", status_code=302)
response.set_cookie(key="user_id", value=str(user.id), httponly=True, secure=False, samesite="Lax")
logging.info(f"User logged in: {username}, user_id set in cookie.")
return response

# Admin dashboard page
@app.get("/dashboard/", response_model=None)
async def dashboard(request: Request):
if not request.state.user:
if request.state.user is None:
return RedirectResponse(url="/admin/")

logging.info(f"Current user: {request.state.user.username}")
return templates.TemplateResponse("dashboard.html", {
"request": request,
"user": request.state.user
"user": request.state.user,
"title": "Admin Dashboard"
})

# Logout functionality
@app.get("/logout/", response_model=None)
async def logout():
response = RedirectResponse(url="/logout-confirmation/")
response.delete_cookie("user_id")
return response

# Logout confirmation page
@app.get("/logout-confirmation/", response_class=HTMLResponse)
async def logout_confirmation(request: Request):
return templates.TemplateResponse("logout_confirmation.html", {
"request": request,
"title": "Logout Confirmation",
"user": request.state.user
})
63 changes: 42 additions & 21 deletions zola-admin/app/models.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,55 @@
# app/models.py

from sqlalchemy import Column, Integer, String
from pydantic import BaseModel
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from pydantic import BaseModel, constr
from app.utils import hash_password
from sqlalchemy.orm import sessionmaker, Session
import os
from passlib.context import CryptContext

# Set up password hashing context
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# Define the path for the database file
db_path = os.path.join(os.path.dirname(__file__), 'zola_admin.db')
SQLALCHEMY_DATABASE_URL = f"sqlite:///{db_path}" # Correct format for SQLite

# Create engine and session local
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base() # Ensure this is created once
# Base class for declarative models
Base = declarative_base()

# Pydantic schemas
class UserCreate(BaseModel):
username: str
password: str

class UserResponse(BaseModel):
id: int
username: str

class Config:
from_attributes = True # Enable ORM mode to convert SQLAlchemy models to Pydantic models

# SQLAlchemy User model
class User(Base):
__tablename__ = "users"

id = Column(Integer, primary_key=True, index=True)
username = Column(String(150), unique=True, index=True, nullable=False)
hashed_password = Column(String(255), nullable=False)
username = Column(String, unique=True, index=True)
hashed_password = Column(String)

# Pydantic models for user creation and response
class UserBase(BaseModel):
username: str
def set_password(self, password: str):
self.hashed_password = pwd_context.hash(password)

class UserCreate(UserBase):
password: constr(min_length=6) # Minimum length for passwords
def verify_password(self, password: str) -> bool:
return pwd_context.verify(password, self.hashed_password)

class UserResponse(UserBase):
id: int
# Add additional models as needed
class AnotherModel(Base):
__tablename__ = "another_table"

class Config:
orm_mode = True # Enable compatibility with ORM objects
id = Column(Integer, primary_key=True, index=True)
some_field = Column(String)

# Function to hash the password and create a new User object
def create_user_hashed(user: UserCreate):
"""Hash the password for a new user."""
return User(username=user.username, hashed_password=hash_password(user.password))
# You can define more models here as required
Binary file modified zola-admin/app/routers/__pycache__/admin.cpython-312.pyc
Binary file not shown.
Binary file modified zola-admin/app/routers/__pycache__/user.cpython-312.pyc
Binary file not shown.
3 changes: 2 additions & 1 deletion zola-admin/app/routers/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# app/routers/admin.py
from fastapi import APIRouter, Depends, Request, Form, HTTPException
from fastapi.responses import RedirectResponse, HTMLResponse
from sqlalchemy.orm import Session
Expand All @@ -24,4 +25,4 @@ async def create_user_route(
logging.error(f"Error creating user: {str(e)}")
raise HTTPException(status_code=400, detail="User creation failed.")

return RedirectResponse(url="/admin/", status_code=302)
return RedirectResponse(url="/admin/", status_code=302)
8 changes: 4 additions & 4 deletions zola-admin/app/routers/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
from fastapi.templating import Jinja2Templates
from fastapi.responses import RedirectResponse
from sqlalchemy.orm import Session
from app import crud, schemas
from app import crud
from app.database import get_db
from app.dependencies import get_current_user
from app.models import User
from app.models import User, UserCreate, UserResponse # Import UserResponse

router = APIRouter()
templates = Jinja2Templates(directory="app/templates")
Expand All @@ -23,11 +23,11 @@ def create_user_page(request: Request):

@router.post("/users/create-user")
def create_user(username: str = Form(...), password: str = Form(...), db: Session = Depends(get_db)):
user_data = schemas.UserCreate(username=username, password=password)
user_data = UserCreate(username=username, password=password)
new_user = crud.create_user(db, user_data)
return RedirectResponse(url="/users/list?success=User%20created%20successfully", status_code=303)

@router.get("/users/{user_id}", response_model=schemas.User)
@router.get("/users/{user_id}", response_model=UserResponse) # Use UserResponse here
def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.get_user_by_id(db, user_id)
if not db_user:
Expand Down
30 changes: 0 additions & 30 deletions zola-admin/app/schemas.py

This file was deleted.

0 comments on commit fa6a8ee

Please sign in to comment.