1
0
mirror of https://gitlab.com/2-chainz/2chainz.git synced 2025-06-16 01:46:39 +00:00

Compare commits

...

3 Commits

Author SHA1 Message Date
49d023b229 fix tests 2025-05-23 21:34:05 -06:00
130a9354cb finish documenting and fixing the site 2025-05-23 21:31:52 -06:00
8421d7092f Remove testing code 2025-05-23 15:59:17 -06:00
3 changed files with 120 additions and 126 deletions

View File

@ -28,8 +28,8 @@ class TestApi:
@pytest.mark.parametrize( @pytest.mark.parametrize(
"mocked_time,start_time,expected", "mocked_time,start_time,expected",
[ [
(100, 50, 50), # 100 - 50 = 50 seconds uptime (100, 50, "50"), # 100 - 50 = 50 seconds uptime
(200, 100, 100), # 200 - 100 = 100 seconds uptime (200, 100, "100"), # 200 - 100 = 100 seconds uptime
], ],
) )
def test_api_uptime_calculation(self, mocked_time, start_time, expected): def test_api_uptime_calculation(self, mocked_time, start_time, expected):

View File

@ -3,18 +3,19 @@ import time
import tomllib import tomllib
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
import logging
from fastapi import FastAPI, Request from fastapi import FastAPI
from fastapi.middleware.trustedhost import TrustedHostMiddleware from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
app = FastAPI() app = FastAPI(
title="2 Chainz REST",
description="A simple API to get 2 Chainz quotes and aliases. See <a href=https://2chainz.ansonbiggs.com>2chainz.ansonbiggs.com</a> for a full explanation.",
)
app.add_middleware( app.add_middleware(
TrustedHostMiddleware, TrustedHostMiddleware,
allowed_hosts=["*"], allowed_hosts=["*"],
) )
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
start_time = time.time() start_time = time.time()
@ -31,37 +32,80 @@ def read_data() -> dict[str, str]:
data = read_data() data = read_data()
# Log all requests to debug issues @app.get(
@app.middleware("http") "/api/",
async def log_requests(request: Request, call_next): summary="Health Check",
# Log what's coming in description="Check API health status and uptime",
logger.info(f"Request: {request.method} {request.url.path}") response_description="Health status with timestamp and uptime",
logger.info(f"Host header: {request.headers.get('host')}") tags=["Health"],
logger.info(f"CF-Ray: {request.headers.get('cf-ray', 'Not from Cloudflare')}") responses={
200: {
"description": "Successful health check",
"content": {
"application/json": {
"example": {
"status": "ok",
"timestamp": "2025-05-24T10:30:00",
"uptime_seconds": "3600.5",
}
}
},
}
},
)
async def ping() -> dict[str, str]:
"""
Endpoint to check on the health of the API and to help diagnose issues.
try: Returns current status, timestamp, and uptime information.
response = await call_next(request) """
return response
except Exception as e:
logger.error(f"Request processing failed: {e}")
raise
@app.get("/api/")
async def ping():
return { return {
"status": "ok", "status": "ok",
"timestamp": datetime.now().isoformat(), "timestamp": datetime.now().isoformat(),
"uptime_seconds": round(time.time() - start_time, 2), "uptime_seconds": str(round(time.time() - start_time, 2)),
} }
@app.get("/api/quote") @app.get(
"/api/quote",
summary="2 Chainz Quote",
description="Get a quote from 2 Chainz",
tags=["Data"],
responses={
200: {
"description": "Successful quote",
"content": {
"application/json": {
"example": {
"quote": "Wood grain chestnut, titty fuck chest nut",
}
}
},
}
},
)
async def quote(): async def quote():
return {"quote": random.choice(data["quotes"])} return {"quote": random.choice(data["quotes"])}
@app.get("/api/alias") @app.get(
"/api/alias",
summary="2 Chainz Alias",
description="Get one of 2 Chainz many aliases",
tags=["Data"],
responses={
200: {
"description": "Successful alias",
"content": {
"application/json": {
"example": {
"alias": "2 Chainz",
}
}
},
}
},
)
async def alias(): async def alias():
return {"alias": random.choice(data["aliases"])} return {"alias": random.choice(data["aliases"])}

View File

@ -40,106 +40,67 @@
:root { :root {
--color: darkviolet; --color: darkviolet;
--color-bg-secondary: black; --color-bg-secondary: black;
} --color-link: darkviolet;
@media screen and (max-width: 400px) {
#scroll-icon {
display: none;
}
} }
</style> </style>
</head> </head>
<body> <body>
<header style="height: 70vh;"> <header style="height: 90vh">
<nav> <nav>
<ul> <a href="https://2chainz.ansonbiggs.com">2chainz.ansonbiggs.com</a>
<li> <p>A REST API for 2 Chainz Quotes</p>
<a href="https://2chainz.ansonbiggs.com">2chainz.ansonbiggs.com</a> - A REST API for 2 <a href="https://gitlab.com/2-chainz/2chainz">Source Code</a>
Chainz Quotes
</li>
</ul>
</nav> </nav>
<section> <section style="height: 50vh">
<blockquote> <blockquote style="margin: auto">
<span id="quote"></span> <span id="quote">TRUUUUUUUU</span>
<footer><i id="alias">- 2 Chainz</i></footer> <footer><i id="alias">- 2 Chainz</i></footer>
</blockquote> </blockquote>
</section> </section>
<p> <section>
<a onclick="getQuote()" href="#" <a onclick="getQuote()" href="#"
><b> ><b style="width: 20vw">
<ion-icon size="large" name="refresh-circle"></ion-icon><br /> <ion-icon size="large" name="refresh-circle"></ion-icon>
New Quote</b <span style="display: grid; place-items: center">New Quote</span>
></a </b>
> </a>
<a id="tweet" href="#" </section>
><b <a href="#scroll" id="scroll-icon" style="padding-top: 10vh"
><ion-icon size="large" name="logo-twitter"></ion-icon> <br />
Tweet Quote
</b></a
>
</p>
<a href="#scroll" id="scroll-icon" style="padding-top: 10vh;"
><ion-icon size="large" name="arrow-down-sharp"></ion-icon ><ion-icon size="large" name="arrow-down-sharp"></ion-icon
></a> ></a>
</header> </header>
<main> <main>
<hr style="padding-top: 0;" /> <hr style="padding-top: 0" />
<header id="scroll"> <header id="scroll">
<h2>Usage</h2> <h2>Usage</h2>
<p>
For exhaustive and up to date documentation see
<a href="/docs">/docs</a>
</p>
</header> </header>
<details open> <details open>
<summary>Quote</summary> <summary>Quote</summary>
<p> <p>
Returns a random 2 Chainz Quote in <code>json</code> format like the Returns a random 2 Chainz Quote in <code>json</code> format like the
following example: following example:
</p> </p>
<p> <p>
send a <code>get</code> request to send a <code>get</code> request to
<code <code
><a href="https://chainz.ansonbiggs.com/api/quote" ><a href="https://2chainz.ansonbiggs.com/api/quote"
>https://chainz.ansonbiggs.com/api/quote</a >https://2chainz.ansonbiggs.com/api/quote</a
></code ></code
> >
</p> </p>
<pre><code>{ <pre><code>{
"quote": "I got a pocket full of money, it got me walking all slew-foot" "quote": "I got a pocket full of money, it got me walking all slew-foot"
}</code></pre> }</code></pre>
<details style="margin-left: 5%;">
<summary>Parameters</summary>
<p>
This endpoint also supports an optional <code>batch</code> parameter
to get more than one quote per request. Maximum quotes that the
endpoint will return is the amount of quotes in
<a
href="https://gitlab.com/2-chainz/2-chainz-rest/-/blob/master/quote/quotes.py"
>quotes.py</a
>
and is subject to change. An example return from
<code>
<a href="https://chainz.ansonbiggs.com/api/quote?batch=2"
>https://chainz.ansonbiggs.com/api/quote?batch=2</a
></code
>
</p>
<pre><code class="json">{
"quotes": [
"I'm in the kitchen. Yams errrrrwhere.",
"Started from the trap, now I rap"
]
}</code></pre>
</details>
</details> </details>
<details <details>
><summary>Alias</summary> <summary>Alias</summary>
<p> <p>
Returns a random 2 Chainz alias in <code>json</code> format. The Returns a random 2 Chainz alias in <code>json</code> format. The
return values are weighted and a full list can be seen in return values are weighted and a full list can be seen in
@ -151,20 +112,21 @@
<p> <p>
send a <code>get</code> request to send a <code>get</code> request to
<code <code
><a href="https://chainz.ansonbiggs.com/api/alias" ><a href="https://2chainz.ansonbiggs.com/api/alias"
>https://chainz.ansonbiggs.com/api/alias</a >https://2chainz.ansonbiggs.com/api/alias</a
></code ></code
> >
</p> </p>
<pre><code>{ <pre><code>{
"alias": "Dos Cadenas" "alias": "Dos Cadenas"
}</code></pre> }</code></pre>
</details> </details>
<hr /> <hr />
<section> <section>
<header> <header>
<h2> <h2>
Projects built using 2chainz.ansonbiggs.com (Your project could be here!) Projects built using 2chainz.ansonbiggs.com (Your project could be
here!)
</h2> </h2>
</header> </header>
<aside> <aside>
@ -214,7 +176,7 @@
</p> </p>
<p> <p>
<small <small
><a href="https://twitter.com/Anson_3D" ><a href="https://ansonbiggs.com/#connect"
>Please let me know if you use it though!</a >Please let me know if you use it though!</a
></small ></small
> >
@ -224,43 +186,31 @@
<h3>Do I need an API key or is this API rate limited?</h3> <h3>Do I need an API key or is this API rate limited?</h3>
<p> <p>
No, the API is totally free and unlimited. However, its being hosted No, the API is totally free and unlimited. However, its being hosted
by a college student so be nice. on a tiny machine that is overburdened by docker containers.
</p> </p>
</aside> </aside>
<aside> <aside>
<h3>Is this project open source? Can I contribute?</h3> <h3>Is this project open source? Can I contribute?</h3>
<p> <p>
Yes and Yes! Check out the Yes and Yes! Check out the
<a href="https://gitlab.com/2-chainz">Project on GitLab.</a> <a href="https://gitlab.com/2-chainz/2chainz">Project on GitLab.</a>
</p> </p>
</aside> </aside>
<aside> <aside>
<h3>Does 2 Chainz know about this?</h3> <h3>Does 2 Chainz know about this?</h3>
<p> <p>Probably not.</p>
Probably not.
</p>
</aside> </aside>
<aside> <aside>
<h3>Why?</h3> <h3>Why?</h3>
<p> <p>Because 2 Chainz has some of the best lines in the rap game.</p>
Because 2 Chainz has some of the best lines in the rap game.
</p>
</aside> </aside>
</section> </section>
</main> </main>
<footer> <footer>
<hr /> <hr />
<p> <p>Made by <a href="https://ansonbiggs.com">Anson</a></p>
Made by <a href="https://gitlab.com/MisterBiggs">Anson Biggs</a>, <p>Inspired By <a href="https://kanye.rest/">kanye.rest</a>.</p>
<a href="https://twitter.com/Anson_3D">@Anson_3D </a> <p><small>Truuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu</small></p>
</p>
<p>
Inspired By <a href="https://kanye.rest/">kanye.rest</a> which was
created by:
<a href="https://ajzbc.com" target="_blank">Andrew Jazbec</a>,
<a href="https://twitter.com/ajzbc" target="_blank">@ajzbc</a>
</p>
<p><small>Truuuuuuuu</small></p>
</footer> </footer>
<script> <script>
getQuote(); getQuote();
@ -270,13 +220,6 @@
.then((resp) => resp.json()) .then((resp) => resp.json())
.then(function (data) { .then(function (data) {
document.getElementById("quote").innerHTML = data.quote; document.getElementById("quote").innerHTML = data.quote;
const tweet = encodeURIComponent(
`"${data.quote}" -@2chainz via https://2chainz.ansonbiggs.com`
);
document.getElementById(
"tweet"
).href = `https://twitter.com/intent/tweet?text=${tweet}`;
}); });
fetch("/api/alias", { method: "GET" }) fetch("/api/alias", { method: "GET" })
@ -286,6 +229,13 @@
}); });
} }
</script> </script>
<script src="https://unpkg.com/ionicons@5.0.0/dist/ionicons.js"></script> <script
type="module"
src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"
></script>
<script
nomodule
src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"
></script>
</body> </body>
</html> </html>