mirror of
https://gitlab.com/2-chainz/2chainz.git
synced 2025-08-06 13:41:29 +00:00
Compare commits
25 Commits
9725f84268
...
revert-1da
Author | SHA1 | Date | |
---|---|---|---|
0af8711276 | |||
1da2d71eeb | |||
fbf10556ee | |||
52dd2fd00f | |||
49d023b229 | |||
130a9354cb | |||
8421d7092f | |||
08c4b96918 | |||
6bb53f6f7d | |||
69238678b8 | |||
964ba43a2b | |||
455fd28bc2 | |||
db169159e6 | |||
3a1c7a904c | |||
b5f8dae3b9 | |||
8263480b72 | |||
05f2bba568 | |||
e152f9e4ad | |||
972ce7c8cb | |||
fdcf5be4c9 | |||
99a07a7493 | |||
d05cc46660 | |||
a683fceb10 | |||
5687871b86 | |||
e488f979c1 |
@@ -6,6 +6,11 @@
|
|||||||
"image": "mcr.microsoft.com/devcontainers/base:bullseye",
|
"image": "mcr.microsoft.com/devcontainers/base:bullseye",
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/va-h/devcontainers-features/uv:1": {}
|
"ghcr.io/va-h/devcontainers-features/uv:1": {}
|
||||||
|
},
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": ["tamasfe.even-better-toml"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||||
|
@@ -1,10 +1,51 @@
|
|||||||
pages:
|
variables:
|
||||||
stage: deploy
|
UV_VERSION: 0.5
|
||||||
|
PYTHON_VERSION: 3.12
|
||||||
|
BASE_LAYER: bookworm-slim
|
||||||
|
# GitLab CI creates a separate mountpoint for the build directory,
|
||||||
|
# so we need to copy instead of using hard links.
|
||||||
|
UV_LINK_MODE: copy
|
||||||
|
|
||||||
|
.base_ruff:
|
||||||
|
stage: build
|
||||||
|
interruptible: true
|
||||||
|
image:
|
||||||
|
name: ghcr.io/astral-sh/ruff:0.11.10-alpine
|
||||||
|
before_script:
|
||||||
|
- cd $CI_PROJECT_DIR
|
||||||
|
- ruff --version
|
||||||
|
|
||||||
|
Ruff Check:
|
||||||
|
extends: .base_ruff
|
||||||
script:
|
script:
|
||||||
- mkdir public
|
- ruff check --output-format=gitlab > code-quality-report.json
|
||||||
- cp -r website/* public/
|
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
reports:
|
||||||
- public
|
codequality: $CI_PROJECT_DIR/code-quality-report.json
|
||||||
only:
|
|
||||||
- main
|
Ruff Format:
|
||||||
|
extends: .base_ruff
|
||||||
|
script:
|
||||||
|
- ruff format --diff
|
||||||
|
|
||||||
|
pytest:
|
||||||
|
image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
|
||||||
|
stage: test
|
||||||
|
script:
|
||||||
|
- uv run pytest --junitxml=report.xml
|
||||||
|
artifacts:
|
||||||
|
when: always
|
||||||
|
reports:
|
||||||
|
junit: report.xml
|
||||||
|
|
||||||
|
create_container:
|
||||||
|
stage: deploy
|
||||||
|
image:
|
||||||
|
name: gcr.io/kaniko-project/executor:v1.23.2-debug
|
||||||
|
entrypoint: [""]
|
||||||
|
script:
|
||||||
|
- /kaniko/executor
|
||||||
|
--context "${CI_PROJECT_DIR}"
|
||||||
|
--dockerfile "${CI_PROJECT_DIR}/Dockerfile"
|
||||||
|
--destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_BRANCH}"
|
||||||
|
--cleanup
|
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"[python]": {
|
||||||
|
"editor.defaultFormatter": "charliermarsh.ruff"
|
||||||
|
}
|
||||||
|
}
|
26
Dockerfile
Normal file
26
Dockerfile
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Use a Python image with uv pre-installed
|
||||||
|
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
|
||||||
|
|
||||||
|
# Install the project into `/app`
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Enable bytecode compilation
|
||||||
|
ENV UV_COMPILE_BYTECODE=1
|
||||||
|
|
||||||
|
# Copy from the cache instead of linking since it's a mounted volume
|
||||||
|
ENV UV_LINK_MODE=copy
|
||||||
|
|
||||||
|
# Copy dependency files
|
||||||
|
COPY uv.lock pyproject.toml ./
|
||||||
|
|
||||||
|
# Install the project's dependencies using the lockfile and settings
|
||||||
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||||
|
uv sync --locked --no-install-project --no-dev
|
||||||
|
|
||||||
|
# Then, add the rest of the project source code and install it
|
||||||
|
COPY . /app
|
||||||
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||||
|
uv sync --locked --no-dev
|
||||||
|
|
||||||
|
CMD ["uv", "run", "fastapi", "run", "src/two_chainz", "--port", "80", "--proxy-headers"]
|
||||||
|
|
44
data.toml
44
data.toml
@@ -1,50 +1,50 @@
|
|||||||
quotes = [
|
quotes = [
|
||||||
"My side chick got pregnant by her main dude and i'm offended.",
|
"My side chick got pregnant by her main dude and i'm offended",
|
||||||
"I kiss your lady, eat her pussy, then kiss the baby.",
|
"I kiss your lady, eat her pussy, then kiss the baby",
|
||||||
"Left hand on that steering wheel, right hand on that pussy!",
|
"Left hand on that steering wheel, right hand on that pussy!",
|
||||||
"For my birthday I threw me a surprise party!",
|
"For my birthday I threw me a surprise party!",
|
||||||
"She got a big booty so I call her big booty",
|
"She got a big booty so I call her big booty",
|
||||||
"My girl got a big purse with a purse in it, and her pussy so clean, I can go to church in it!",
|
"My girl got a big purse with a purse in it, and her pussy so clean, I can go to church in it!",
|
||||||
"Beat the pussy up, I need riot gear.",
|
"Beat the pussy up, I need riot gear",
|
||||||
"Gas in a Ziplock, now thats loud and clear.",
|
"Gas in a Ziplock, now thats loud and clear",
|
||||||
"My wrist deserve a shout out, 'I'm like what up wrist?'\nMy stove deserve a shout out, 'I'm like what up stove?'",
|
"My wrist deserve a shout out, 'I'm like what up wrist?'\nMy stove deserve a shout out, 'I'm like what up stove?'",
|
||||||
"I'm in the kitchen. Yams errrrrwhere.",
|
"I'm in the kitchen. Yams errrrrwhere",
|
||||||
"I encourage everyone to pay attention to the issues that matter to you, from jobs and the economy, to education and our schools, to criminal justice reform. Whatever it is that you care about, make sure you use your voice.",
|
"I encourage everyone to pay attention to the issues that matter to you, from jobs and the economy, to education and our schools, to criminal justice reform. Whatever it is that you care about, make sure you use your voice",
|
||||||
"If you a chicken head, go somewhere and lay some eggs",
|
"If you a chicken head, go somewhere and lay some eggs",
|
||||||
"Chain hang to my ding-a-ling, chain hang, chain hang to my ding-a-ling",
|
"Chain hang to my ding-a-ling, chain hang, chain hang to my ding-a-ling",
|
||||||
"I tried to get a tan but I'm black already.",
|
"I tried to get a tan but I'm black already",
|
||||||
"Then I put a fat rabbit on a Craftmatic!",
|
"Then I put a fat rabbit on a Craftmatic!",
|
||||||
"Yeah, I love them strippers",
|
"Yeah, I love them strippers",
|
||||||
"If I wasn't rapping I'd be trapping.",
|
"If I wasn't rapping I'd be trapping",
|
||||||
"Started from the trap, now I rap",
|
"Started from the trap, now I rap",
|
||||||
"I'm so high I can sing to a chandelier\nMy flow a glass of Ace of Spade and yours a can of beer.",
|
"I'm so high I can sing to a chandelier\nMy flow a glass of Ace of Spade and yours a can of beer",
|
||||||
"I look you right in your face, sing to your bitch like I'm Drake!",
|
"I look you right in your face, sing to your bitch like I'm Drake!",
|
||||||
"Ass so big, I told her to look back at it!",
|
"Ass so big, I told her to look back at it!",
|
||||||
"Drunk and high at the same time.\nDrinking champagne on an airplane!",
|
"Drunk and high at the same time.\nDrinking champagne on an airplane!",
|
||||||
"Wood grain, chestnut\nTitty fuck, chest nut",
|
"Wood grain, chestnut\nTitty fuck, chest nut",
|
||||||
"Horsepower, horsepower, all this Polo on, I got horsepower",
|
"Horsepower, horsepower, all this Polo on, I got horsepower",
|
||||||
"If I die, bury me inside the Louis store",
|
"If I die, bury me inside the Louis store",
|
||||||
"GI-VEN-CHY, nigga God Bless you.",
|
"GI-VEN-CHY, nigga God Bless you",
|
||||||
"My favorite dish is turkey lasagna\nEven my pajamas designer.",
|
"My favorite dish is turkey lasagna\nEven my pajamas designer",
|
||||||
"Walked in, ill nigga alert! ill nigga alert!",
|
"Walked in, ill nigga alert! ill nigga alert!",
|
||||||
"Like fuck your baby daddy, his daddy should've worn a condom",
|
"Like fuck your baby daddy, his daddy should've worn a condom",
|
||||||
"I'm the type of nigga thats built to last.\nYou fuck with me, Ill put my foot in your ass.",
|
"I'm the type of nigga thats built to last.\nYou fuck with me, Ill put my foot in your ass",
|
||||||
"I wish a nigga would like a kitchen cabinet.",
|
"I wish a nigga would like a kitchen cabinet",
|
||||||
"Louie V is my kryptonite.",
|
"Louie V is my kryptonite",
|
||||||
"If you woke up this morning, Nigga you winnin!",
|
"If you woke up this morning, Nigga you winnin!",
|
||||||
"I use good pussy like its lotion.",
|
"I use good pussy like its lotion",
|
||||||
"Big shit like a dinosaur did it.",
|
"Big shit like a dinosaur did it",
|
||||||
"#making bands, yes I am.",
|
"#making bands, yes I am",
|
||||||
"I wear versace like its nike, you don't like it do you?",
|
"I wear versace like its nike, you don't like it do you?",
|
||||||
"I bet you feel this bank roll if I bump into you.",
|
"I bet you feel this bank roll if I bump into you",
|
||||||
"Like fuck your baby daddy, his daddy should've wore a condom.",
|
"Like fuck your baby daddy, his daddy should've wore a condom",
|
||||||
"Sprinter van on me, I got them xans on me,\nDriveway so damn long by the time I leave I'm damn asleep",
|
"Sprinter van on me, I got them xans on me,\nDriveway so damn long by the time I leave I'm damn asleep",
|
||||||
"Bitches round my pool, I made them hoes look like my landscape.",
|
"Bitches round my pool, I made them hoes look like my landscape",
|
||||||
"Everything Proper, no propaganda.",
|
"Everything Proper, no propaganda",
|
||||||
"Big sack, a lotta hoes like Santa",
|
"Big sack, a lotta hoes like Santa",
|
||||||
"Attitude on some 'Fuck you too!'\nBankroll on 'What it do, boo?'",
|
"Attitude on some 'Fuck you too!'\nBankroll on 'What it do, boo?'",
|
||||||
"I got a pocket full of money, it got me walking all slew-foot",
|
"I got a pocket full of money, it got me walking all slew-foot",
|
||||||
"I'm on my wave like a cruise ship.",
|
"I'm on my wave like a cruise ship",
|
||||||
"In that hoe mouth like a toothpick",
|
"In that hoe mouth like a toothpick",
|
||||||
"My new bitch gon' pull me a new bitch,\nThen pull me a new bitch\nSee that is a snowball effect",
|
"My new bitch gon' pull me a new bitch,\nThen pull me a new bitch\nSee that is a snowball effect",
|
||||||
"I got a mansion full of marble floors,\nIt look like I could go bowl in this bitch",
|
"I got a mansion full of marble floors,\nIt look like I could go bowl in this bitch",
|
||||||
|
@@ -3,30 +3,19 @@ name = "2chainz"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "Add your description here"
|
description = "Add your description here"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = [
|
authors = [{ name = "Anson", email = "anson@ansonbiggs.com" }]
|
||||||
{ name = "Anson", email = "anson@ansonbiggs.com" }
|
|
||||||
]
|
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
dependencies = [
|
dependencies = ["fastapi[standard]>=0.115.12"]
|
||||||
"fastapi[standard]>=0.115.12",
|
|
||||||
]
|
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
two_chainz = "two_chainz:main"
|
two_chainz = "two_chainz:main"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["hatchling"]
|
requires = ["hatchling"]
|
||||||
build-backend = "hatchling.build"
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel]
|
[tool.hatch.build.targets.wheel]
|
||||||
packages = ["src/two_chainz"]
|
packages = ["src/two_chainz"]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
dev = [
|
dev = ["httpx>=0.28.1", "pytest>=8.3.5", "ruff>=0.11.11"]
|
||||||
"httpx>=0.28.1",
|
|
||||||
"pytest>=8.3.5",
|
|
||||||
"ruff>=0.11.11",
|
|
||||||
]
|
|
||||||
|
88
src/test/test_two_chainz.py
Normal file
88
src/test/test_two_chainz.py
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
import two_chainz
|
||||||
|
from two_chainz import app
|
||||||
|
|
||||||
|
client = TestClient(app, base_url="http://chainz.ansonbiggs.com")
|
||||||
|
|
||||||
|
|
||||||
|
class TestApi:
|
||||||
|
def test_api_endpoint(self):
|
||||||
|
response = client.get("/api/")
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
assert "status" in data
|
||||||
|
assert data["status"] == "ok"
|
||||||
|
assert "timestamp" in data
|
||||||
|
assert "uptime_seconds" in data
|
||||||
|
|
||||||
|
# Validate timestamp format (ISO format)
|
||||||
|
assert datetime.fromisoformat(data["timestamp"])
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"mocked_time,start_time,expected",
|
||||||
|
[
|
||||||
|
(100, 50, "50"), # 100 - 50 = 50 seconds uptime
|
||||||
|
(200, 100, "100"), # 200 - 100 = 100 seconds uptime
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_api_uptime_calculation(self, mocked_time, start_time, expected):
|
||||||
|
with patch("time.time", return_value=mocked_time):
|
||||||
|
with patch("two_chainz.start_time", start_time):
|
||||||
|
response = client.get("/api/")
|
||||||
|
assert response.json()["uptime_seconds"] == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("endpoint", ["/api/quote", "/api/alias"])
|
||||||
|
class TestDataEndpoints:
|
||||||
|
def test_endpoint_nonempty(self, endpoint):
|
||||||
|
for _ in range(1000): # Data is random so run the test a ton
|
||||||
|
# Given we have an endpoint
|
||||||
|
|
||||||
|
# When we do a get request
|
||||||
|
response = client.get(endpoint)
|
||||||
|
|
||||||
|
# Then we should get a 200 status code
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
# Then there should be a single entry in the dict
|
||||||
|
assert len(data) == 1
|
||||||
|
|
||||||
|
# Then the values should not be empty
|
||||||
|
key, value = next(iter(data.items()))
|
||||||
|
assert key
|
||||||
|
assert value
|
||||||
|
|
||||||
|
|
||||||
|
class TestData:
|
||||||
|
def test_data_exists(self):
|
||||||
|
assert two_chainz.data
|
||||||
|
assert two_chainz.data["quotes"]
|
||||||
|
assert two_chainz.data["aliases"]
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("quote", two_chainz.data["quotes"])
|
||||||
|
class TestQuotes:
|
||||||
|
def test_no_empty(self, quote):
|
||||||
|
assert quote
|
||||||
|
|
||||||
|
def test_no_ending_period(self, quote):
|
||||||
|
assert quote[-1] != "."
|
||||||
|
|
||||||
|
def test_no_ending_newline(self, quote):
|
||||||
|
assert quote[-1] != "\n"
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("alias", two_chainz.data["quotes"])
|
||||||
|
class TestAlias:
|
||||||
|
def test_no_empty(self, alias):
|
||||||
|
assert alias
|
||||||
|
|
||||||
|
def test_no_ending_newline(self, alias):
|
||||||
|
assert alias[-1] != "\n"
|
114
src/two_chainz/__init__.py
Normal file
114
src/two_chainz/__init__.py
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
import random
|
||||||
|
import time
|
||||||
|
import tomllib
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.middleware.trustedhost import TrustedHostMiddleware
|
||||||
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
|
||||||
|
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(
|
||||||
|
TrustedHostMiddleware,
|
||||||
|
allowed_hosts=["*"],
|
||||||
|
)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
|
||||||
|
def read_data() -> dict[str, str]:
|
||||||
|
raw_data = tomllib.loads(Path("data.toml").read_text())
|
||||||
|
raw_data["aliases"] = [
|
||||||
|
alias["name"] for alias in raw_data["aliases"] for _ in range(alias["weight"])
|
||||||
|
]
|
||||||
|
|
||||||
|
return raw_data
|
||||||
|
|
||||||
|
|
||||||
|
data = read_data()
|
||||||
|
|
||||||
|
|
||||||
|
@app.get(
|
||||||
|
"/api/",
|
||||||
|
summary="Health Check",
|
||||||
|
description="Check API health status and uptime",
|
||||||
|
response_description="Health status with timestamp and uptime",
|
||||||
|
tags=["Health"],
|
||||||
|
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.
|
||||||
|
|
||||||
|
Returns current status, timestamp, and uptime information.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"status": "ok",
|
||||||
|
"timestamp": datetime.now().isoformat(),
|
||||||
|
"uptime_seconds": str(round(time.time() - start_time, 2)),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@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():
|
||||||
|
return {"quote": random.choice(data["quotes"])}
|
||||||
|
|
||||||
|
|
||||||
|
@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():
|
||||||
|
return {"alias": random.choice(data["aliases"])}
|
||||||
|
|
||||||
|
|
||||||
|
# Mount static files
|
||||||
|
app.mount("/", StaticFiles(directory="website", html=True), name="static")
|
@@ -1,11 +1,13 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
|
||||||
<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32" />
|
<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32" />
|
||||||
<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16" />
|
<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16" />
|
||||||
<link rel="stylesheet" href="css/mvp.css" />
|
<link rel="stylesheet" href="css/mvp.css" />
|
||||||
|
|
||||||
<meta charset="utf-8" />
|
<title>2chainz.ansonbiggs.com</title>
|
||||||
<meta name="description" content="A REST API for 2 Chainz Quotes." />
|
<meta name="description" content="A REST API for 2 Chainz Quotes." />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta property="og:title" content="2 Chainz Rest API" />
|
<meta property="og:title" content="2 Chainz Rest API" />
|
||||||
@@ -14,16 +16,6 @@
|
|||||||
property="og:description"
|
property="og:description"
|
||||||
content="A free REST API for 2 Chainz quotes"
|
content="A free REST API for 2 Chainz quotes"
|
||||||
/>
|
/>
|
||||||
<meta property="og:type" content="website" />
|
|
||||||
|
|
||||||
<meta name="twitter:card" content="summary" />
|
|
||||||
<meta name="twitter:creator" content="@Anson_3D" />
|
|
||||||
<meta name="twitter:url" content="https://2chainz.ansonbiggs.com" />
|
|
||||||
<meta name="twitter:title" content="2chainz.ansonbiggs.com" />
|
|
||||||
<meta
|
|
||||||
name="twitter:description"
|
|
||||||
content="A free REST API for 2 Chainz quotes"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
@@ -48,107 +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>
|
||||||
<title>2chainz.ansonbiggs.com</title>
|
|
||||||
</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-rest.azurewebsites.net/quote"
|
><a href="https://2chainz.ansonbiggs.com/api/quote"
|
||||||
>https://chainz-rest.azurewebsites.net/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-rest.azurewebsites.net/quote?batch=2"
|
|
||||||
>https://chainz-rest.azurewebsites.net/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
|
||||||
@@ -160,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-rest.azurewebsites.net/alias"
|
><a href="https://2chainz.ansonbiggs.com/api/alias"
|
||||||
>https://chainz-rest.azurewebsites.net/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>
|
||||||
@@ -223,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
|
||||||
>
|
>
|
||||||
@@ -233,68 +186,56 @@
|
|||||||
<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();
|
||||||
|
|
||||||
function getQuote() {
|
function getQuote() {
|
||||||
fetch("https://chainz-rest.azurewebsites.net/quote", { method: "GET" })
|
fetch("/api/quote", { method: "GET" })
|
||||||
.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("https://chainz-rest.azurewebsites.net/alias", { method: "GET" })
|
fetch("/api/alias", { method: "GET" })
|
||||||
.then((resp) => resp.json())
|
.then((resp) => resp.json())
|
||||||
.then(function (data) {
|
.then(function (data) {
|
||||||
document.getElementById("alias").innerHTML = "- " + data.alias;
|
document.getElementById("alias").innerHTML = "- " + data.alias;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</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>
|
||||||
|
Reference in New Issue
Block a user