Skip to content

Commit 62b9582

Browse files
Merge pull request #74 from Mr-Sunglasses/feat/design-improvements
Feat/design improvements
2 parents c5f2ac6 + 993e1a1 commit 62b9582

File tree

8 files changed

+1240
-352
lines changed

8 files changed

+1240
-352
lines changed

.pdm-python

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/paste/main.py

Lines changed: 56 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
from . import __version__, __author__, __contact__, __url__
3737
from .schema import PasteCreate, PasteResponse, PasteDetails
3838

39-
description: str = "paste.py 🐍 - A pastebin written in python."
39+
DESCRIPTION: str = "paste.py 🐍 - A pastebin written in python."
4040

4141
limiter = Limiter(key_func=get_remote_address)
4242
app: FastAPI = FastAPI(
@@ -54,16 +54,13 @@
5454
app.state.limiter = limiter
5555

5656

57-
def rate_limit_exceeded_handler(request: Request, exc: Exception) -> Union[Response, Awaitable[Response]]:
57+
def rate_limit_exceeded_handler(
58+
request: Request, exc: Exception
59+
) -> Union[Response, Awaitable[Response]]:
5860
if isinstance(exc, RateLimitExceeded):
59-
return Response(
60-
content="Rate limit exceeded",
61-
status_code=429
62-
)
63-
return Response(
64-
content="An error occurred",
65-
status_code=500
66-
)
61+
return Response(content="Rate limit exceeded", status_code=429)
62+
return Response(content="An error occurred", status_code=500)
63+
6764

6865
app.add_exception_handler(RateLimitExceeded, rate_limit_exceeded_handler)
6966

@@ -84,13 +81,14 @@ def rate_limit_exceeded_handler(request: Request, exc: Exception) -> Union[Respo
8481

8582
BASE_DIR: Path = Path(__file__).resolve().parent
8683

87-
templates: Jinja2Templates = Jinja2Templates(
88-
directory=str(Path(BASE_DIR, "templates")))
84+
templates: Jinja2Templates = Jinja2Templates(directory=str(Path(BASE_DIR, "templates")))
8985

9086

9187
@app.post("/file")
9288
@limiter.limit("100/minute")
93-
async def post_as_a_file(request: Request, file: UploadFile = File(...)) -> PlainTextResponse:
89+
async def post_as_a_file(
90+
request: Request, file: UploadFile = File(...)
91+
) -> PlainTextResponse:
9492
try:
9593
uuid: str = generate_uuid()
9694
if uuid in large_uuid_storage:
@@ -119,7 +117,9 @@ async def post_as_a_file(request: Request, file: UploadFile = File(...)) -> Plai
119117

120118

121119
@app.get("/paste/{uuid}")
122-
async def get_paste_data(uuid: str, user_agent: Optional[str] = Header(None)) -> Response:
120+
async def get_paste_data(
121+
request: Request, uuid: str, user_agent: Optional[str] = Header(None)
122+
) -> Response:
123123
if not "." in uuid:
124124
uuid = _find_without_extension(uuid)
125125
path: str = f"data/{uuid}"
@@ -143,104 +143,26 @@ async def get_paste_data(uuid: str, user_agent: Optional[str] = Header(None)) ->
143143
try:
144144
lexer = get_lexer_by_name(file_extension, stripall=True)
145145
except ClassNotFound:
146-
lexer = get_lexer_by_name(
147-
"text", stripall=True) # Default lexer
146+
lexer = get_lexer_by_name("text", stripall=True) # Default lexer
147+
148148
formatter = HtmlFormatter(
149-
style="colorful", full=True, linenos="inline", cssclass="code")
149+
style="monokai", # Dark theme base
150+
linenos="inline",
151+
cssclass="highlight",
152+
nowrap=False,
153+
)
154+
150155
highlighted_code: str = highlight(content, lexer, formatter)
151-
# print(highlighted_code)
152-
custom_style = """
153-
.code pre span.linenos {
154-
color: #999;
155-
padding-right: 10px;
156-
-webkit-user-select: none;
157-
-webkit-touch-callout: none;
158-
-moz-user-select: none;
159-
-ms-user-select: none;
160-
user-select: none;
161-
}
162-
163-
span {
164-
font-size: 1.1em !important;
165-
}
166-
167-
pre {
168-
line-height: 1.4 !important;
169-
}
170-
171-
.code pre span.linenos::after {
172-
content: "";
173-
border-right: 1px solid #999;
174-
height: 100%;
175-
margin-left: 10px;
176-
}
177-
178-
.code {
179-
background-color: #fff;
180-
border: 1.5px solid #ddd;
181-
border-radius: 5px;
182-
margin-bottom: 20px;
183-
overflow: auto;
184-
}
185-
186-
pre {
187-
font-family: 'Consolas','Monaco','Andale Mono','Ubuntu Mono','monospace;' !important;
188-
}
189-
.copy-button {
190-
position: fixed;
191-
top: 10px;
192-
right: 10px;
193-
padding: 10px;
194-
background-color: #4CAF50;
195-
color: #fff;
196-
cursor: pointer;
197-
border: none;
198-
border-radius: 5px;
199-
outline: none;
200-
}
201-
"""
202-
custom_script = """
203-
function copyAllText() {
204-
// Create a range object to select the entire document
205-
const range = document.createRange();
206-
range.selectNode(document.body);
207-
208-
// Create a selection object and add the range to it
209-
const selection = window.getSelection();
210-
selection.removeAllRanges();
211-
selection.addRange(range);
212-
213-
// Copy the selected text to the clipboard
214-
document.execCommand('copy');
215-
216-
// Clear the selection to avoid interfering with the user's selection
217-
selection.removeAllRanges();
218-
219-
// You can customize the copied message
220-
alert('All text copied to clipboard!');
221-
}
222-
223-
"""
224-
response_content: str = f"""
225-
<html>
226-
<head>
227-
<title>{uuid} | paste.py 🐍</title>
228-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
229-
<style>{custom_style}</style>
230-
<style>{formatter.get_style_defs('.highlight')}</style>
231-
</head>
232-
<body>
233-
<div id="copyButton" class="copy-button" onclick="copyAllText()">
234-
<i class="fas fa-copy"></i>
235-
</div>
236-
{highlighted_code}
237-
</body>
238-
<script>
239-
{custom_script}
240-
</script>
241-
</html>
242-
"""
243-
return HTMLResponse(content=response_content)
156+
157+
return templates.TemplateResponse(
158+
"paste.html",
159+
{
160+
"request": request,
161+
"uuid": uuid,
162+
"highlighted_code": highlighted_code,
163+
"pygments_css": formatter.get_style_defs(".highlight"),
164+
},
165+
)
244166
except Exception:
245167
raise HTTPException(
246168
detail="404: The Requested Resource is not found",
@@ -261,11 +183,13 @@ async def delete_paste(uuid: str) -> PlainTextResponse:
261183
os.remove(path)
262184
return PlainTextResponse(f"File successfully deleted {uuid}")
263185
except FileNotFoundError:
264-
raise HTTPException(detail="File Not Found",
265-
status_code=status.HTTP_404_NOT_FOUND)
186+
raise HTTPException(
187+
detail="File Not Found", status_code=status.HTTP_404_NOT_FOUND
188+
)
266189
except Exception as e:
267190
raise HTTPException(
268-
detail=f"The exception is {e}", status_code=status.HTTP_409_CONFLICT)
191+
detail=f"The exception is {e}", status_code=status.HTTP_409_CONFLICT
192+
)
269193

270194

271195
@app.get("/web", response_class=HTMLResponse)
@@ -276,8 +200,9 @@ async def web(request: Request) -> Response:
276200

277201
@app.post("/web", response_class=PlainTextResponse)
278202
@limiter.limit("100/minute")
279-
async def web_post(request: Request, content: str = Form(...),
280-
extension: Optional[str] = Form(None)) -> RedirectResponse:
203+
async def web_post(
204+
request: Request, content: str = Form(...), extension: Optional[str] = Form(None)
205+
) -> RedirectResponse:
281206
try:
282207
file_content: bytes = content.encode()
283208
uuid: str = generate_uuid()
@@ -297,7 +222,9 @@ async def web_post(request: Request, content: str = Form(...),
297222
status_code=status.HTTP_403_FORBIDDEN,
298223
)
299224

300-
return RedirectResponse(f"{BASE_URL}/paste/{uuid_}", status_code=status.HTTP_303_SEE_OTHER)
225+
return RedirectResponse(
226+
f"{BASE_URL}/paste/{uuid_}", status_code=status.HTTP_303_SEE_OTHER
227+
)
301228

302229

303230
@app.get("/health", status_code=status.HTTP_200_OK)
@@ -322,54 +249,53 @@ async def get_languages() -> JSONResponse:
322249
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
323250
)
324251

252+
325253
# apis to create and get a paste which returns uuid and url (to be used by SDK)
326254
@app.post("/api/paste", response_model=PasteResponse)
327255
async def create_paste(paste: PasteCreate) -> JSONResponse:
328256
try:
329257
uuid: str = generate_uuid()
330258
if uuid in large_uuid_storage:
331259
uuid = generate_uuid()
332-
260+
333261
uuid_with_extension: str = f"{uuid}.{paste.extension}"
334262
path: str = f"data/{uuid_with_extension}"
335-
263+
336264
with open(path, "w", encoding="utf-8") as f:
337265
f.write(paste.content)
338-
266+
339267
large_uuid_storage.append(uuid_with_extension)
340-
268+
341269
return JSONResponse(
342270
content=PasteResponse(
343-
uuid=uuid_with_extension,
344-
url=f"{BASE_URL}/paste/{uuid_with_extension}"
271+
uuid=uuid_with_extension, url=f"{BASE_URL}/paste/{uuid_with_extension}"
345272
).dict(),
346-
status_code=status.HTTP_201_CREATED
273+
status_code=status.HTTP_201_CREATED,
347274
)
348275
except Exception as e:
349276
raise HTTPException(
350277
detail=f"There was an error creating the paste: {str(e)}",
351278
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
352279
)
353280

281+
354282
@app.get("/api/paste/{uuid}", response_model=PasteDetails)
355283
async def get_paste_details(uuid: str) -> JSONResponse:
356284
if not "." in uuid:
357285
uuid = _find_without_extension(uuid)
358286
path: str = f"data/{uuid}"
359-
287+
360288
try:
361289
with open(path, "r", encoding="utf-8") as f:
362290
content: str = f.read()
363-
291+
364292
extension: str = Path(path).suffix[1:]
365-
293+
366294
return JSONResponse(
367295
content=PasteDetails(
368-
uuid=uuid,
369-
content=content,
370-
extension=extension
296+
uuid=uuid, content=content, extension=extension
371297
).dict(),
372-
status_code=status.HTTP_200_OK
298+
status_code=status.HTTP_200_OK,
373299
)
374300
except FileNotFoundError:
375301
raise HTTPException(
@@ -381,4 +307,3 @@ async def get_paste_details(uuid: str) -> JSONResponse:
381307
detail=f"Error retrieving paste: {str(e)}",
382308
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
383309
)
384-

src/paste/schema.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
from typing import Optional
22
from pydantic import BaseModel
33

4+
45
class Data(BaseModel):
56
input_data: str
67

8+
79
class PasteCreate(BaseModel):
810
content: str
911
extension: Optional[str] = None
1012

13+
1114
class PasteResponse(BaseModel):
1215
uuid: str
1316
url: str
1417

18+
1519
class PasteDetails(BaseModel):
1620
uuid: str
1721
content: str

src/paste/templates/base.html

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title> {% block title %} {% endblock %} </title>
5+
{% block headlinks %} {% endblock %}
6+
<meta charset="UTF-8"/>
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
8+
<meta name="og:title" content="paste.py 🐍"/>
9+
<meta name="og:site_name" content="paste.py"/>
10+
<meta
11+
name="og:description"
12+
content="A simple pastebin powered by FastAPI."
13+
/>
14+
<meta name="og:type" content="website"/>
15+
<meta name="og:url" content="https://paste.fosscu.org"/>
16+
<meta name="og:locale" content="en_US"/>
17+
<style>
18+
{% block style %}
19+
{% endblock %}
20+
</style>
21+
</head>
22+
<body>
23+
{% block content %}
24+
{% endblock %}
25+
<script>
26+
{% block script %}
27+
{% endblock %}
28+
</script>
29+
</body>
30+
</html>

0 commit comments

Comments
 (0)