NotePad / main.py
triflix's picture
Update main.py
dd3a65c verified
from fastapi import FastAPI, Request, Form, Depends, HTTPException
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse, RedirectResponse
from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime, Text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from datetime import datetime
import random
import string
import re
import os
import bcrypt
from typing import Optional
# Define your base URL
BASE_URL = "https://triflix-notepad.hf.space"
# Create the FastAPI app
app = FastAPI(title="Notepad App")
# Set up templates and static files directories
templates_dir = os.path.join(os.path.dirname(__file__), "templates")
templates = Jinja2Templates(directory=templates_dir)
# Create static directory if it doesn't exist
static_dir = os.path.join(os.path.dirname(__file__), "static")
os.makedirs(static_dir, exist_ok=True)
app.mount("/static", StaticFiles(directory=static_dir), name="static")
# Database setup
DATABASE_URL = "sqlite:///./notepad.db"
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
# Define the Note model
class Note(Base):
__tablename__ = "notes"
id = Column(Integer, primary_key=True, index=True)
code = Column(String, unique=True, index=True)
content = Column(Text)
is_private = Column(Boolean, default=False)
password = Column(String, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
# Create the database tables
Base.metadata.create_all(bind=engine)
# Dependency to get the database session
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# Function to generate a random code for the note URL
def generate_random_code(length=6):
characters = string.ascii_letters + string.digits
return ''.join(random.choice(characters) for _ in range(length))
# Function to detect image URLs in text and convert them to HTML img tags
def process_content(content):
# Regular expression to find image URLs
image_pattern = r'(https?://\S+\.(?:jpg|jpeg|png|gif|webp|svg))'
# Replace image URLs with img tags
processed_content = re.sub(
image_pattern,
r'<img src="\1" class="my-2 max-w-full h-auto rounded" alt="Image">',
content
)
# Convert newlines to <br> tags for proper HTML rendering
processed_content = processed_content.replace('\n', '<br>')
return processed_content
# Home page route
@app.get("/", response_class=HTMLResponse)
async def home(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
# Create note route
@app.post("/create", response_class=HTMLResponse)
async def create_note(
request: Request,
content: str = Form(...),
is_private: bool = Form(False),
password: Optional[str] = Form(None),
db: Session = Depends(get_db)
):
# Generate a unique random code
code = generate_random_code()
while db.query(Note).filter(Note.code == code).first():
code = generate_random_code()
# Hash password if provided
hashed_password = None
if is_private and password:
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
# Create new note
new_note = Note(
code=code,
content=content,
is_private=is_private,
password=hashed_password
)
db.add(new_note)
db.commit()
# Redirect to the note view page using the BASE_URL
return RedirectResponse(url=f"{BASE_URL}/{code}", status_code=303)
# View note route
@app.get("/{code}", response_class=HTMLResponse)
async def view_note(request: Request, code: str, db: Session = Depends(get_db)):
# Find the note by code
note = db.query(Note).filter(Note.code == code).first()
if not note:
raise HTTPException(status_code=404, detail="Note not found")
# If the note is private, show password prompt
if note.is_private:
return templates.TemplateResponse(
"password.html",
{"request": request, "code": code}
)
# Process content to render images
processed_content = process_content(note.content)
return templates.TemplateResponse(
"view.html",
{"request": request, "note": note, "content": processed_content}
)
# Verify password route
@app.post("/{code}/verify", response_class=HTMLResponse)
async def verify_password(
request: Request,
code: str,
password: str = Form(...),
db: Session = Depends(get_db)
):
# Find the note by code
note = db.query(Note).filter(Note.code == code).first()
if not note:
raise HTTPException(status_code=404, detail="Note not found")
# Verify the password
if not note.is_private or not note.password:
return RedirectResponse(url=f"{BASE_URL}/{code}", status_code=303)
is_valid = bcrypt.checkpw(password.encode('utf-8'), note.password.encode('utf-8'))
if not is_valid:
return templates.TemplateResponse(
"password.html",
{"request": request, "code": code, "error": "Invalid password"}
)
# Process content to render images
processed_content = process_content(note.content)
return templates.TemplateResponse(
"view.html",
{"request": request, "note": note, "content": processed_content}
)
# Run the application
if __name__ == "__main__":
import uvicorn
# Running the app on host 0.0.0.0 and port 7860.
uvicorn.run("main:app", host="0.0.0.0", port=7860, reload=True)