triflix commited on
Commit
dd3a65c
·
verified ·
1 Parent(s): 4f462a4

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +181 -179
main.py CHANGED
@@ -1,179 +1,181 @@
1
- from fastapi import FastAPI, Request, Form, Depends, HTTPException
2
- from fastapi.templating import Jinja2Templates
3
- from fastapi.staticfiles import StaticFiles
4
- from fastapi.responses import HTMLResponse, RedirectResponse
5
- from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime, Text
6
- from sqlalchemy.ext.declarative import declarative_base
7
- from sqlalchemy.orm import sessionmaker, Session
8
- from datetime import datetime
9
- import random
10
- import string
11
- import re
12
- import os
13
- import bcrypt
14
- from typing import Optional
15
-
16
- # Create the FastAPI app
17
- app = FastAPI(title="Notepad App")
18
-
19
- # Set up templates and static files directories
20
- templates_dir = os.path.join(os.path.dirname(__file__), "templates")
21
- templates = Jinja2Templates(directory=templates_dir)
22
-
23
- # Create static directory if it doesn't exist
24
- static_dir = os.path.join(os.path.dirname(__file__), "static")
25
- os.makedirs(static_dir, exist_ok=True)
26
- app.mount("/static", StaticFiles(directory=static_dir), name="static")
27
-
28
- # Database setup
29
- DATABASE_URL = "sqlite:///./notepad.db"
30
- engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
31
- SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
32
- Base = declarative_base()
33
-
34
- # Define the Note model
35
- class Note(Base):
36
- __tablename__ = "notes"
37
-
38
- id = Column(Integer, primary_key=True, index=True)
39
- code = Column(String, unique=True, index=True)
40
- content = Column(Text)
41
- is_private = Column(Boolean, default=False)
42
- password = Column(String, nullable=True)
43
- created_at = Column(DateTime, default=datetime.utcnow)
44
-
45
- # Create the database tables
46
- Base.metadata.create_all(bind=engine)
47
-
48
- # Dependency to get the database session
49
- def get_db():
50
- db = SessionLocal()
51
- try:
52
- yield db
53
- finally:
54
- db.close()
55
-
56
- # Function to generate a random code for the note URL
57
- def generate_random_code(length=6):
58
- characters = string.ascii_letters + string.digits
59
- return ''.join(random.choice(characters) for _ in range(length))
60
-
61
- # Function to detect image URLs in text and convert them to HTML img tags
62
- def process_content(content):
63
- # Regular expression to find image URLs
64
- image_pattern = r'(https?://\S+\.(?:jpg|jpeg|png|gif|webp|svg))'
65
-
66
- # Replace image URLs with img tags
67
- processed_content = re.sub(
68
- image_pattern,
69
- r'<img src="\1" class="my-2 max-w-full h-auto rounded" alt="Image">',
70
- content
71
- )
72
-
73
- # Convert newlines to <br> tags for proper HTML rendering
74
- processed_content = processed_content.replace('\n', '<br>')
75
-
76
- return processed_content
77
-
78
- # Home page route
79
- @app.get("/", response_class=HTMLResponse)
80
- async def home(request: Request):
81
- return templates.TemplateResponse("index.html", {"request": request})
82
-
83
- # Create note route
84
- @app.post("/create", response_class=HTMLResponse)
85
- async def create_note(
86
- request: Request,
87
- content: str = Form(...),
88
- is_private: bool = Form(False),
89
- password: Optional[str] = Form(None),
90
- db: Session = Depends(get_db)
91
- ):
92
- # Generate a unique random code
93
- code = generate_random_code()
94
- while db.query(Note).filter(Note.code == code).first():
95
- code = generate_random_code()
96
-
97
- # Hash password if provided
98
- hashed_password = None
99
- if is_private and password:
100
- hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
101
-
102
- # Create new note
103
- new_note = Note(
104
- code=code,
105
- content=content,
106
- is_private=is_private,
107
- password=hashed_password
108
- )
109
-
110
- db.add(new_note)
111
- db.commit()
112
-
113
- # Redirect to the note view page
114
- return RedirectResponse(url=f"/{code}", status_code=303)
115
-
116
- # View note route
117
- @app.get("/{code}", response_class=HTMLResponse)
118
- async def view_note(request: Request, code: str, db: Session = Depends(get_db)):
119
- # Find the note by code
120
- note = db.query(Note).filter(Note.code == code).first()
121
-
122
- if not note:
123
- raise HTTPException(status_code=404, detail="Note not found")
124
-
125
- # If the note is private, show password prompt
126
- if note.is_private:
127
- return templates.TemplateResponse(
128
- "password.html",
129
- {"request": request, "code": code}
130
- )
131
-
132
- # Process content to render images
133
- processed_content = process_content(note.content)
134
-
135
- return templates.TemplateResponse(
136
- "view.html",
137
- {"request": request, "note": note, "content": processed_content}
138
- )
139
-
140
- # Verify password route
141
- @app.post("/{code}/verify", response_class=HTMLResponse)
142
- async def verify_password(
143
- request: Request,
144
- code: str,
145
- password: str = Form(...),
146
- db: Session = Depends(get_db)
147
- ):
148
- # Find the note by code
149
- note = db.query(Note).filter(Note.code == code).first()
150
-
151
- if not note:
152
- raise HTTPException(status_code=404, detail="Note not found")
153
-
154
- # Verify the password
155
- if not note.is_private or not note.password:
156
- # Note is not private or doesn't have a password
157
- return RedirectResponse(url=f"/{code}", status_code=303)
158
-
159
- is_valid = bcrypt.checkpw(password.encode('utf-8'), note.password.encode('utf-8'))
160
-
161
- if not is_valid:
162
- # Password is incorrect
163
- return templates.TemplateResponse(
164
- "password.html",
165
- {"request": request, "code": code, "error": "Invalid password"}
166
- )
167
-
168
- # Process content to render images
169
- processed_content = process_content(note.content)
170
-
171
- return templates.TemplateResponse(
172
- "view.html",
173
- {"request": request, "note": note, "content": processed_content}
174
- )
175
-
176
- # Run the application
177
- if __name__ == "__main__":
178
- import uvicorn
179
- uvicorn.run("main:app", host="0.0.0.0", port=7860, reload=True)
 
 
 
1
+ from fastapi import FastAPI, Request, Form, Depends, HTTPException
2
+ from fastapi.templating import Jinja2Templates
3
+ from fastapi.staticfiles import StaticFiles
4
+ from fastapi.responses import HTMLResponse, RedirectResponse
5
+ from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime, Text
6
+ from sqlalchemy.ext.declarative import declarative_base
7
+ from sqlalchemy.orm import sessionmaker, Session
8
+ from datetime import datetime
9
+ import random
10
+ import string
11
+ import re
12
+ import os
13
+ import bcrypt
14
+ from typing import Optional
15
+
16
+ # Define your base URL
17
+ BASE_URL = "https://triflix-notepad.hf.space"
18
+
19
+ # Create the FastAPI app
20
+ app = FastAPI(title="Notepad App")
21
+
22
+ # Set up templates and static files directories
23
+ templates_dir = os.path.join(os.path.dirname(__file__), "templates")
24
+ templates = Jinja2Templates(directory=templates_dir)
25
+
26
+ # Create static directory if it doesn't exist
27
+ static_dir = os.path.join(os.path.dirname(__file__), "static")
28
+ os.makedirs(static_dir, exist_ok=True)
29
+ app.mount("/static", StaticFiles(directory=static_dir), name="static")
30
+
31
+ # Database setup
32
+ DATABASE_URL = "sqlite:///./notepad.db"
33
+ engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
34
+ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
35
+ Base = declarative_base()
36
+
37
+ # Define the Note model
38
+ class Note(Base):
39
+ __tablename__ = "notes"
40
+
41
+ id = Column(Integer, primary_key=True, index=True)
42
+ code = Column(String, unique=True, index=True)
43
+ content = Column(Text)
44
+ is_private = Column(Boolean, default=False)
45
+ password = Column(String, nullable=True)
46
+ created_at = Column(DateTime, default=datetime.utcnow)
47
+
48
+ # Create the database tables
49
+ Base.metadata.create_all(bind=engine)
50
+
51
+ # Dependency to get the database session
52
+ def get_db():
53
+ db = SessionLocal()
54
+ try:
55
+ yield db
56
+ finally:
57
+ db.close()
58
+
59
+ # Function to generate a random code for the note URL
60
+ def generate_random_code(length=6):
61
+ characters = string.ascii_letters + string.digits
62
+ return ''.join(random.choice(characters) for _ in range(length))
63
+
64
+ # Function to detect image URLs in text and convert them to HTML img tags
65
+ def process_content(content):
66
+ # Regular expression to find image URLs
67
+ image_pattern = r'(https?://\S+\.(?:jpg|jpeg|png|gif|webp|svg))'
68
+
69
+ # Replace image URLs with img tags
70
+ processed_content = re.sub(
71
+ image_pattern,
72
+ r'<img src="\1" class="my-2 max-w-full h-auto rounded" alt="Image">',
73
+ content
74
+ )
75
+
76
+ # Convert newlines to <br> tags for proper HTML rendering
77
+ processed_content = processed_content.replace('\n', '<br>')
78
+
79
+ return processed_content
80
+
81
+ # Home page route
82
+ @app.get("/", response_class=HTMLResponse)
83
+ async def home(request: Request):
84
+ return templates.TemplateResponse("index.html", {"request": request})
85
+
86
+ # Create note route
87
+ @app.post("/create", response_class=HTMLResponse)
88
+ async def create_note(
89
+ request: Request,
90
+ content: str = Form(...),
91
+ is_private: bool = Form(False),
92
+ password: Optional[str] = Form(None),
93
+ db: Session = Depends(get_db)
94
+ ):
95
+ # Generate a unique random code
96
+ code = generate_random_code()
97
+ while db.query(Note).filter(Note.code == code).first():
98
+ code = generate_random_code()
99
+
100
+ # Hash password if provided
101
+ hashed_password = None
102
+ if is_private and password:
103
+ hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
104
+
105
+ # Create new note
106
+ new_note = Note(
107
+ code=code,
108
+ content=content,
109
+ is_private=is_private,
110
+ password=hashed_password
111
+ )
112
+
113
+ db.add(new_note)
114
+ db.commit()
115
+
116
+ # Redirect to the note view page using the BASE_URL
117
+ return RedirectResponse(url=f"{BASE_URL}/{code}", status_code=303)
118
+
119
+ # View note route
120
+ @app.get("/{code}", response_class=HTMLResponse)
121
+ async def view_note(request: Request, code: str, db: Session = Depends(get_db)):
122
+ # Find the note by code
123
+ note = db.query(Note).filter(Note.code == code).first()
124
+
125
+ if not note:
126
+ raise HTTPException(status_code=404, detail="Note not found")
127
+
128
+ # If the note is private, show password prompt
129
+ if note.is_private:
130
+ return templates.TemplateResponse(
131
+ "password.html",
132
+ {"request": request, "code": code}
133
+ )
134
+
135
+ # Process content to render images
136
+ processed_content = process_content(note.content)
137
+
138
+ return templates.TemplateResponse(
139
+ "view.html",
140
+ {"request": request, "note": note, "content": processed_content}
141
+ )
142
+
143
+ # Verify password route
144
+ @app.post("/{code}/verify", response_class=HTMLResponse)
145
+ async def verify_password(
146
+ request: Request,
147
+ code: str,
148
+ password: str = Form(...),
149
+ db: Session = Depends(get_db)
150
+ ):
151
+ # Find the note by code
152
+ note = db.query(Note).filter(Note.code == code).first()
153
+
154
+ if not note:
155
+ raise HTTPException(status_code=404, detail="Note not found")
156
+
157
+ # Verify the password
158
+ if not note.is_private or not note.password:
159
+ return RedirectResponse(url=f"{BASE_URL}/{code}", status_code=303)
160
+
161
+ is_valid = bcrypt.checkpw(password.encode('utf-8'), note.password.encode('utf-8'))
162
+
163
+ if not is_valid:
164
+ return templates.TemplateResponse(
165
+ "password.html",
166
+ {"request": request, "code": code, "error": "Invalid password"}
167
+ )
168
+
169
+ # Process content to render images
170
+ processed_content = process_content(note.content)
171
+
172
+ return templates.TemplateResponse(
173
+ "view.html",
174
+ {"request": request, "note": note, "content": processed_content}
175
+ )
176
+
177
+ # Run the application
178
+ if __name__ == "__main__":
179
+ import uvicorn
180
+ # Running the app on host 0.0.0.0 and port 7860.
181
+ uvicorn.run("main:app", host="0.0.0.0", port=7860, reload=True)