docs is ssr'd
This commit is contained in:
parent
429da306ee
commit
d85dd163e3
11 changed files with 500 additions and 556 deletions
542
public/api.html
542
public/api.html
|
@ -1,542 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<link rel="stylesheet" href="/css/main.css">
|
|
||||||
<link rel="stylesheet" href="/css/header.css">
|
|
||||||
<link rel="stylesheet" href="/css/console.css">
|
|
||||||
<link rel="stylesheet" href="/css/api.css">
|
|
||||||
<title>XSSBook - API Documentation</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="header">
|
|
||||||
<span class="logo"><a href="/">xssbook</a></span>
|
|
||||||
<span class="gtext desc" style="margin-left: 6em; font-size: 2em; color: #606770">API Documentation</span>
|
|
||||||
</div>
|
|
||||||
<div id="docs">
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method post">POST</span>
|
|
||||||
<span class="uri">/api/auth/register</span>
|
|
||||||
<span class="desc">Registeres a new account</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Body</h2>
|
|
||||||
<div class="body">
|
|
||||||
<span>{</span><br>
|
|
||||||
<span class="key">"firstname"</span> : <span class="string">"[Object"</span><br>
|
|
||||||
<span class="key">"lastname"</span> : <span class="string">"object]"</span><br>
|
|
||||||
<span class="key">"email"</span> : <span class="string">"object@object.object"</span><br>
|
|
||||||
<span class="key">"password"</span> : <span class="string">"i love js"</span><br>
|
|
||||||
<span class="key">"gender"</span> : <span class="string">"lettuce"</span><br>
|
|
||||||
<span class="key">"day"</span> : <span class="number">1</span><br>
|
|
||||||
<span class="key">"month"</span> : <span class="number">1</span><br>
|
|
||||||
<span class="key">"year"</span> : <span class="number">1970</span><br>
|
|
||||||
<span>}</span><br>
|
|
||||||
</div>
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">201</span>
|
|
||||||
<span class="pdesc">Successfully created new user, auth cookie is returned</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">400</span>
|
|
||||||
<span class="pdesc">Body does not match paramaters</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method post">POST</span>
|
|
||||||
<span class="uri">/api/auth/login</span>
|
|
||||||
<span class="desc">Logs into an existing account</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Body</h2>
|
|
||||||
<div class="body">
|
|
||||||
<span>{</span><br>
|
|
||||||
<span class="key">"email"</span> : <span class="string">"object@object.object"</span><br>
|
|
||||||
<span class="key">"password"</span> : <span class="string">"i love js"</span><br>
|
|
||||||
<span>}</span><br>
|
|
||||||
</div>
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Successfully logged in, auth cookie is returned</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">400</span>
|
|
||||||
<span class="pdesc">Body does not match paramaters, or email/password is already in use</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method post">POST</span>
|
|
||||||
<span class="uri">/api/auth/logout</span>
|
|
||||||
<span class="desc">Logs out of an logged in account</span>
|
|
||||||
<span class="auth"><span>auth</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Successfully logged out</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">Failed to log out user</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method post">POST</span>
|
|
||||||
<span class="uri">/api/posts/create</span>
|
|
||||||
<span class="desc">Creates a new post</span>
|
|
||||||
<span class="auth"><span>auth</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Body</h2>
|
|
||||||
<div class="body">
|
|
||||||
<span>{</span><br>
|
|
||||||
<span class="key">"content"</span> : <span class="string">"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."</span><br>
|
|
||||||
<span>}</span><br>
|
|
||||||
</div>
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">201</span>
|
|
||||||
<span class="pdesc">Successfully created post</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">400</span>
|
|
||||||
<span class="pdesc">Body does not match paramaters</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">Failed to create post</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method post">POST</span>
|
|
||||||
<span class="uri">/api/posts/page</span>
|
|
||||||
<span class="desc">Load a section of posts from newest to oldest</span>
|
|
||||||
<span class="auth"><span>auth</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Body</h2>
|
|
||||||
<div class="body">
|
|
||||||
<span>{</span><br>
|
|
||||||
<span class="key">"page"</span> : <span class="number">0</span><br>
|
|
||||||
<span>}</span><br>
|
|
||||||
</div>
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Returns posts in <span>application/json</span></span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">400</span>
|
|
||||||
<span class="pdesc">Body does not match paramaters</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">Failed to fetch posts</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method post">POST</span>
|
|
||||||
<span class="uri">/api/posts/user</span>
|
|
||||||
<span class="desc">Load a section of posts from newest to oldest from a specific user</span>
|
|
||||||
<span class="auth"><span>auth</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Body</h2>
|
|
||||||
<div class="body">
|
|
||||||
<span>{</span><br>
|
|
||||||
<span class="key">"user_id"</span> : <span class="number">3</span><br>
|
|
||||||
<span class="key">"page"</span> : <span class="number">0</span><br>
|
|
||||||
<span>}</span><br>
|
|
||||||
</div>
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Returns posts in <span>application/json</span></span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">400</span>
|
|
||||||
<span class="pdesc">Body does not match paramaters</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">Failed to fetch posts</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method patch">PATCH</span>
|
|
||||||
<span class="uri">/api/posts/comment</span>
|
|
||||||
<span class="desc">Adds a comment to a post</span>
|
|
||||||
<span class="auth"><span>auth</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Body</h2>
|
|
||||||
<div class="body">
|
|
||||||
<span>{</span><br>
|
|
||||||
<span class="key">"content"</span> : <span class="string">"This is a very good post"</span><br>
|
|
||||||
<span class="key">"post_id"</span> : <span class="number">0</span><br>
|
|
||||||
<span>}</span><br>
|
|
||||||
</div>
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Successfully added comment</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">400</span>
|
|
||||||
<span class="pdesc">Body does not match paramaters</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">Failed to add comment</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method patch">PATCH</span>
|
|
||||||
<span class="uri">/api/posts/like</span>
|
|
||||||
<span class="desc">Set like status on a post</span>
|
|
||||||
<span class="auth"><span>auth</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Body</h2>
|
|
||||||
<div class="body">
|
|
||||||
<span>{</span><br>
|
|
||||||
<span class="key">"state"</span> : <span class="bool">true</span><br>
|
|
||||||
<span class="key">"post_id"</span> : <span class="number">0</span><br>
|
|
||||||
<span>}</span><br>
|
|
||||||
</div>
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Successfully set like status</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">400</span>
|
|
||||||
<span class="pdesc">Body does not match paramaters</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">Failed to set like status</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method post">POST</span>
|
|
||||||
<span class="uri">/api/users/load</span>
|
|
||||||
<span class="desc">Load a requested set of users</span>
|
|
||||||
<span class="auth"><span>auth</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Body</h2>
|
|
||||||
<div class="body">
|
|
||||||
<span>{</span><br>
|
|
||||||
<span class="key">"ids"</span> : [<span class="number">0</span>,<span class="number">3</span>,<span class="number">7</span>]<br>
|
|
||||||
<span>}</span><br>
|
|
||||||
</div>
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Returns users in <span>application/json</span></span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">400</span>
|
|
||||||
<span class="pdesc">Body does not match paramaters</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">Failed to fetch users</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method post">POST</span>
|
|
||||||
<span class="uri">/api/users/page</span>
|
|
||||||
<span class="desc">Load a section of users from newest to oldest</span>
|
|
||||||
<span class="auth"><span>auth</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Body</h2>
|
|
||||||
<div class="body">
|
|
||||||
<span>{</span><br>
|
|
||||||
<span class="key">"page"</span> : <span class="number">0</span><br>
|
|
||||||
<span>}</span><br>
|
|
||||||
</div>
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Returns users in <span>application/json</span></span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">400</span>
|
|
||||||
<span class="pdesc">Body does not match paramaters</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">Failed to fetch users</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method post">POST</span>
|
|
||||||
<span class="uri">/api/users/self</span>
|
|
||||||
<span class="desc">Returns current authenticated user (whoami)</span>
|
|
||||||
<span class="auth"><span>auth</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Returns authed user in <span>application/json</span></span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">Failed to fetch user</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method put">PUT</span>
|
|
||||||
<span class="uri">/api/users/avatar</span>
|
|
||||||
<span class="desc">Set your current profile avatar</span>
|
|
||||||
<span class="auth"><span>auth</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Body</h2>
|
|
||||||
<div class="body">
|
|
||||||
PNG sent as a binary blob
|
|
||||||
</div>
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Successfully updated avatar</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">400</span>
|
|
||||||
<span class="pdesc">Invalid PNG or disallowed size</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">Failed to update avatar</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method put">PUT</span>
|
|
||||||
<span class="uri">/api/users/banner</span>
|
|
||||||
<span class="desc">Set your current profile banner</span>
|
|
||||||
<span class="auth"><span>auth</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Body</h2>
|
|
||||||
<div class="body">
|
|
||||||
PNG sent as a binary blob
|
|
||||||
</div>
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Successfully updated banner</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">400</span>
|
|
||||||
<span class="pdesc">Invalid PNG or disallowed size</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">Failed to update banner</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method post">POST</span>
|
|
||||||
<span class="uri">/api/admin/auth</span>
|
|
||||||
<span class="desc">Authenticates on the admin panel</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Body</h2>
|
|
||||||
<div class="body">
|
|
||||||
<span>{</span><br>
|
|
||||||
<span class="key">"secret"</span> : <span class="string">"admin"</span><br>
|
|
||||||
<span>}</span><br>
|
|
||||||
</div>
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Successfully authed, admin cookie returned</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">400</span>
|
|
||||||
<span class="pdesc">Body does match parameters, or invalid admin scret</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method post">POST</span>
|
|
||||||
<span class="uri">/api/admin/query</span>
|
|
||||||
<span class="desc">Run a SQL query on the database</span>
|
|
||||||
<span class="auth"><span>admin</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Body</h2>
|
|
||||||
<div class="body">
|
|
||||||
<span>{</span><br>
|
|
||||||
<span class="key">"query"</span> : <span class="string">"DROP TABLE users;"</span><br>
|
|
||||||
<span>}</span><br>
|
|
||||||
</div>
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Successfully ran SQL query</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">400</span>
|
|
||||||
<span class="pdesc">Body does match parameters</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">SQL query error</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method post">POST</span>
|
|
||||||
<span class="uri">/api/admin/posts</span>
|
|
||||||
<span class="desc">Returns the entire posts table</span>
|
|
||||||
<span class="auth"><span>admin</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Returns sql table in <span>text/html</span></span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">Failed to fetch data</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method post">POST</span>
|
|
||||||
<span class="uri">/api/admin/users</span>
|
|
||||||
<span class="desc">Returns the entire users table</span>
|
|
||||||
<span class="auth"><span>admin</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Returns sql table in <span>text/html</span></span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">Failed to fetch data</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="endpoint">
|
|
||||||
<span class="method post">POST</span>
|
|
||||||
<span class="uri">/api/admin/sessions</span>
|
|
||||||
<span class="desc">Returns the entire posts sessions</span>
|
|
||||||
<span class="auth"><span>admin</span> cookie is required for authentication</span>
|
|
||||||
</div>
|
|
||||||
<div class="info">
|
|
||||||
<h2>Responses</h2>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">200</span>
|
|
||||||
<span class="pdesc">Returns sql table in <span>text/html</span></span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">401</span>
|
|
||||||
<span class="pdesc">Unauthorized</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span class="ptype">500</span>
|
|
||||||
<span class="pdesc">Failed to fetch data</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
|
@ -6,13 +6,29 @@ use tower_cookies::{Cookie, Cookies};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
database,
|
database,
|
||||||
public::admin,
|
public::{admin, docs::{EndpointDocumentation, EndpointMethod}},
|
||||||
types::{
|
types::{
|
||||||
extract::{AdminUser, Check, CheckResult, Json},
|
extract::{AdminUser, Check, CheckResult, Json},
|
||||||
http::ResponseCode,
|
http::ResponseCode,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const ADMIN_AUTH: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/admin/auth",
|
||||||
|
method: EndpointMethod::Post,
|
||||||
|
description: "Authenticates on the admin panel",
|
||||||
|
body: Some(r#"
|
||||||
|
{
|
||||||
|
"secret" : "admin"
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
responses: &[
|
||||||
|
(200, "Successfully executed SQL query"),
|
||||||
|
(400, " Successfully authed, admin cookie returned")
|
||||||
|
],
|
||||||
|
cookie: None,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct AdminAuthRequest {
|
struct AdminAuthRequest {
|
||||||
secret: String,
|
secret: String,
|
||||||
|
@ -40,6 +56,24 @@ async fn auth(cookies: Cookies, Json(body): Json<AdminAuthRequest>) -> Response
|
||||||
ResponseCode::Success.text("Successfully logged in")
|
ResponseCode::Success.text("Successfully logged in")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const ADMIN_QUERY: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/admin/query",
|
||||||
|
method: EndpointMethod::Post,
|
||||||
|
description: "Run a SQL query on the database",
|
||||||
|
body: Some(r#"
|
||||||
|
{
|
||||||
|
"query" : "DROP TABLE users;"
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
responses: &[
|
||||||
|
(200, "Successfully executed SQL query"),
|
||||||
|
(400, "Body does not match parameters"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "SQL query ran into an error")
|
||||||
|
],
|
||||||
|
cookie: Some("admin"),
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct QueryRequest {
|
struct QueryRequest {
|
||||||
query: String,
|
query: String,
|
||||||
|
@ -60,14 +94,53 @@ async fn query(_: AdminUser, Json(body): Json<QueryRequest>) -> Response {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const ADMIN_POSTS: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/admin/posts",
|
||||||
|
method: EndpointMethod::Post,
|
||||||
|
description: "Returns the entire posts table",
|
||||||
|
body: None,
|
||||||
|
responses: &[
|
||||||
|
(200, "Returns sql table in <span>text/html</span>"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "Failed to fetch data")
|
||||||
|
],
|
||||||
|
cookie: Some("admin"),
|
||||||
|
};
|
||||||
|
|
||||||
async fn posts(_: AdminUser) -> Response {
|
async fn posts(_: AdminUser) -> Response {
|
||||||
admin::generate_posts()
|
admin::generate_posts()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const ADMIN_USERS: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/admin/users",
|
||||||
|
method: EndpointMethod::Post,
|
||||||
|
description: "Returns the entire users table",
|
||||||
|
body: None,
|
||||||
|
responses: &[
|
||||||
|
(200, "Returns sql table in <span>text/html</span>"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "Failed to fetch data")
|
||||||
|
],
|
||||||
|
cookie: Some("admin"),
|
||||||
|
};
|
||||||
|
|
||||||
async fn users(_: AdminUser) -> Response {
|
async fn users(_: AdminUser) -> Response {
|
||||||
admin::generate_users()
|
admin::generate_users()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const ADMIN_SESSIONS: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/admin/sessions",
|
||||||
|
method: EndpointMethod::Post,
|
||||||
|
description: "Returns the entire sessions table",
|
||||||
|
body: None,
|
||||||
|
responses: &[
|
||||||
|
(200, "Returns sql table in <span>text/html</span>"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "Failed to fetch data")
|
||||||
|
],
|
||||||
|
cookie: Some("admin"),
|
||||||
|
};
|
||||||
|
|
||||||
async fn sessions(_: AdminUser) -> Response {
|
async fn sessions(_: AdminUser) -> Response {
|
||||||
admin::generate_sessions()
|
admin::generate_sessions()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,34 @@ use serde::Deserialize;
|
||||||
use time::{Duration, OffsetDateTime};
|
use time::{Duration, OffsetDateTime};
|
||||||
use tower_cookies::{Cookie, Cookies};
|
use tower_cookies::{Cookie, Cookies};
|
||||||
|
|
||||||
use crate::types::{
|
use crate::{types::{
|
||||||
extract::{AuthorizedUser, Check, CheckResult, Json, Log},
|
extract::{AuthorizedUser, Check, CheckResult, Json, Log},
|
||||||
http::ResponseCode,
|
http::ResponseCode,
|
||||||
session::Session,
|
session::Session,
|
||||||
user::User,
|
user::User,
|
||||||
|
}, public::docs::{EndpointDocumentation, EndpointMethod}};
|
||||||
|
|
||||||
|
pub const AUTH_REGISTER: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/auth/register",
|
||||||
|
method: EndpointMethod::Post,
|
||||||
|
description: "Registeres a new account",
|
||||||
|
body: Some(r#"
|
||||||
|
{
|
||||||
|
"firstname": "[Object]",
|
||||||
|
"lastname": "object]",
|
||||||
|
"email": "object@object.object",
|
||||||
|
"password": "i love js",
|
||||||
|
"gender": "object",
|
||||||
|
"day": 1,
|
||||||
|
"month": 1,
|
||||||
|
"year": 1970
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
responses: &[
|
||||||
|
(201, "Successfully registered new user"),
|
||||||
|
(400, "Body does not match parameters"),
|
||||||
|
],
|
||||||
|
cookie: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
|
@ -93,9 +116,26 @@ async fn register(cookies: Cookies, Json(body): Json<RegistrationRequet>) -> Res
|
||||||
|
|
||||||
cookies.add(cookie);
|
cookies.add(cookie);
|
||||||
|
|
||||||
ResponseCode::Created.text("Successfully created new user")
|
ResponseCode::Created.text("Successfully created new user, auth cookie is returned")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const AUTH_LOGIN: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/auth/login",
|
||||||
|
method: EndpointMethod::Post,
|
||||||
|
description: "Logs into an existing account",
|
||||||
|
body: Some(r#"
|
||||||
|
{
|
||||||
|
"email": "object@object.object",
|
||||||
|
"password": "i love js"
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
responses: &[
|
||||||
|
(200, "Successfully logged in, auth cookie is returned"),
|
||||||
|
(400, "Body does not match parameters, or invalid email password combination"),
|
||||||
|
],
|
||||||
|
cookie: None,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct LoginRequest {
|
struct LoginRequest {
|
||||||
email: String,
|
email: String,
|
||||||
|
@ -136,6 +176,19 @@ async fn login(cookies: Cookies, Json(body): Json<LoginRequest>) -> Response {
|
||||||
ResponseCode::Success.text("Successfully logged in")
|
ResponseCode::Success.text("Successfully logged in")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const AUTH_LOGOUT: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/auth/logout",
|
||||||
|
method: EndpointMethod::Post,
|
||||||
|
description: "Logs out of a logged in account",
|
||||||
|
body: None,
|
||||||
|
responses: &[
|
||||||
|
(200, "Successfully logged out"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "Failed to log out user")
|
||||||
|
],
|
||||||
|
cookie: None,
|
||||||
|
};
|
||||||
|
|
||||||
async fn logout(cookies: Cookies, AuthorizedUser(user): AuthorizedUser, _: Log) -> Response {
|
async fn logout(cookies: Cookies, AuthorizedUser(user): AuthorizedUser, _: Log) -> Response {
|
||||||
cookies.remove(Cookie::new("auth", ""));
|
cookies.remove(Cookie::new("auth", ""));
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,10 @@ use tower_governor::{
|
||||||
GovernorLayer,
|
GovernorLayer,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod admin;
|
pub mod admin;
|
||||||
mod auth;
|
pub mod auth;
|
||||||
mod posts;
|
pub mod posts;
|
||||||
mod users;
|
pub mod users;
|
||||||
|
|
||||||
pub use auth::RegistrationRequet;
|
pub use auth::RegistrationRequet;
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,28 @@ use axum::{
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::types::{
|
use crate::{types::{
|
||||||
extract::{AuthorizedUser, Check, CheckResult, Json},
|
extract::{AuthorizedUser, Check, CheckResult, Json},
|
||||||
http::ResponseCode,
|
http::ResponseCode,
|
||||||
post::Post,
|
post::Post,
|
||||||
|
}, public::docs::{EndpointDocumentation, EndpointMethod}};
|
||||||
|
|
||||||
|
pub const POSTS_CREATE: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/posts/create",
|
||||||
|
method: EndpointMethod::Post,
|
||||||
|
description: "Creates a new post",
|
||||||
|
body: Some(r#"
|
||||||
|
{
|
||||||
|
"content" : "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
responses: &[
|
||||||
|
(201, "Successfully created post"),
|
||||||
|
(400, "Body does not match parameters"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "Failed to create post")
|
||||||
|
],
|
||||||
|
cookie: Some("auth"),
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -43,6 +61,24 @@ async fn create(
|
||||||
ResponseCode::Created.json(&json)
|
ResponseCode::Created.json(&json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const POSTS_PAGE: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/posts/page",
|
||||||
|
method: EndpointMethod::Post,
|
||||||
|
description: "Load a section of posts from newest to oldest",
|
||||||
|
body: Some(r#"
|
||||||
|
{
|
||||||
|
"page": 0
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
responses: &[
|
||||||
|
(200, "Returns posts in <span>application/json<span>"),
|
||||||
|
(400, "Body does not match parameters"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "Failed to fetch posts")
|
||||||
|
],
|
||||||
|
cookie: Some("auth"),
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct PostPageRequest {
|
struct PostPageRequest {
|
||||||
page: u64,
|
page: u64,
|
||||||
|
@ -69,10 +105,29 @@ async fn page(
|
||||||
ResponseCode::Success.json(&json)
|
ResponseCode::Success.json(&json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const POSTS_USER: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/posts/user",
|
||||||
|
method: EndpointMethod::Post,
|
||||||
|
description: "Load a section of posts from newest to oldest from a specific user",
|
||||||
|
body: Some(r#"
|
||||||
|
{
|
||||||
|
"user_id": 3,
|
||||||
|
"page": 0
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
responses: &[
|
||||||
|
(200, "Returns posts in <span>application/json<span>"),
|
||||||
|
(400, "Body does not match parameters"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "Failed to fetch posts")
|
||||||
|
],
|
||||||
|
cookie: Some("auth"),
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct UsersPostsRequest {
|
struct UsersPostsRequest {
|
||||||
user_id: u64,
|
user_id: u64,
|
||||||
page: u64
|
page: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Check for UsersPostsRequest {
|
impl Check for UsersPostsRequest {
|
||||||
|
@ -96,6 +151,25 @@ async fn user(
|
||||||
ResponseCode::Success.json(&json)
|
ResponseCode::Success.json(&json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const POSTS_COMMENT: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/posts/comment",
|
||||||
|
method: EndpointMethod::Patch,
|
||||||
|
description: "Add a comment to a post",
|
||||||
|
body: Some(r#"
|
||||||
|
{
|
||||||
|
"content": "This is a very cool comment",
|
||||||
|
"post_id": 0
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
responses: &[
|
||||||
|
(200, "Successfully added comment"),
|
||||||
|
(400, "Body does not match parameters"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "Failed to add comment")
|
||||||
|
],
|
||||||
|
cookie: Some("auth"),
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct PostCommentRequest {
|
struct PostCommentRequest {
|
||||||
content: String,
|
content: String,
|
||||||
|
@ -129,6 +203,25 @@ async fn comment(
|
||||||
ResponseCode::Success.text("Successfully commented on post")
|
ResponseCode::Success.text("Successfully commented on post")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const POSTS_LIKE: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/posts/like",
|
||||||
|
method: EndpointMethod::Patch,
|
||||||
|
description: "Set like status on a post",
|
||||||
|
body: Some(r#"
|
||||||
|
{
|
||||||
|
"post_id" : 0,
|
||||||
|
"status" : true
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
responses: &[
|
||||||
|
(200, "Successfully set like status"),
|
||||||
|
(400, "Body does not match parameters"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "Failed to set like status")
|
||||||
|
],
|
||||||
|
cookie: Some("auth"),
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct PostLikeRequest {
|
struct PostLikeRequest {
|
||||||
state: bool,
|
state: bool,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::types::{
|
use crate::{types::{
|
||||||
extract::{AuthorizedUser, Check, CheckResult, Json, Png},
|
extract::{AuthorizedUser, Check, CheckResult, Json, Png},
|
||||||
http::ResponseCode,
|
http::ResponseCode,
|
||||||
user::User,
|
user::User,
|
||||||
};
|
}, public::docs::{EndpointDocumentation, EndpointMethod}};
|
||||||
use axum::{
|
use axum::{
|
||||||
response::Response,
|
response::Response,
|
||||||
routing::{post, put},
|
routing::{post, put},
|
||||||
|
@ -10,6 +10,24 @@ use axum::{
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
pub const USERS_LOAD: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/users/load",
|
||||||
|
method: EndpointMethod::Post,
|
||||||
|
description: "Loads a requested set of users",
|
||||||
|
body: Some(r#"
|
||||||
|
{
|
||||||
|
"ids": [0, 3, 7]
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
responses: &[
|
||||||
|
(200, "Returns users in <span>application/json</span>"),
|
||||||
|
(400, "Body does not match parameters"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "Failed to fetch users")
|
||||||
|
],
|
||||||
|
cookie: Some("auth"),
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct UserLoadRequest {
|
struct UserLoadRequest {
|
||||||
ids: Vec<u64>,
|
ids: Vec<u64>,
|
||||||
|
@ -33,6 +51,25 @@ async fn load_batch(
|
||||||
ResponseCode::Success.json(&json)
|
ResponseCode::Success.json(&json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const USERS_PAGE: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/users/page",
|
||||||
|
method: EndpointMethod::Post,
|
||||||
|
description: "Load a section of users from newest to oldest",
|
||||||
|
body: Some(r#"
|
||||||
|
{
|
||||||
|
"user_id": 3,
|
||||||
|
"page": 0
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
responses: &[
|
||||||
|
(200, "Returns users in <span>application/json</span>"),
|
||||||
|
(400, "Body does not match parameters"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "Failed to fetch users")
|
||||||
|
],
|
||||||
|
cookie: Some("auth"),
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct UserPageReqiest {
|
struct UserPageReqiest {
|
||||||
page: u64,
|
page: u64,
|
||||||
|
@ -59,6 +96,19 @@ async fn load_page(
|
||||||
ResponseCode::Success.json(&json)
|
ResponseCode::Success.json(&json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const USERS_SELF: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/users/self",
|
||||||
|
method: EndpointMethod::Post,
|
||||||
|
description: "Returns current authenticated user (whoami)",
|
||||||
|
body: None,
|
||||||
|
responses: &[
|
||||||
|
(200, "Successfully executed SQL query"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "Failed to fetch user")
|
||||||
|
],
|
||||||
|
cookie: Some("auth"),
|
||||||
|
};
|
||||||
|
|
||||||
async fn load_self(AuthorizedUser(user): AuthorizedUser) -> Response {
|
async fn load_self(AuthorizedUser(user): AuthorizedUser) -> Response {
|
||||||
let Ok(json) = serde_json::to_string(&user) else {
|
let Ok(json) = serde_json::to_string(&user) else {
|
||||||
return ResponseCode::InternalServerError.text("Failed to fetch user")
|
return ResponseCode::InternalServerError.text("Failed to fetch user")
|
||||||
|
@ -67,6 +117,20 @@ async fn load_self(AuthorizedUser(user): AuthorizedUser) -> Response {
|
||||||
ResponseCode::Success.json(&json)
|
ResponseCode::Success.json(&json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const USERS_AVATAR: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/users/avatar",
|
||||||
|
method: EndpointMethod::Put,
|
||||||
|
description: "Set your current profile avatar",
|
||||||
|
body: Some("PNG sent as a binary blob"),
|
||||||
|
responses: &[
|
||||||
|
(200, "Successfully updated avatar"),
|
||||||
|
(400, "Invalid PNG or disallowed size"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "Failed to update avatar")
|
||||||
|
],
|
||||||
|
cookie: Some("auth"),
|
||||||
|
};
|
||||||
|
|
||||||
async fn avatar(AuthorizedUser(user): AuthorizedUser, Png(img): Png) -> Response {
|
async fn avatar(AuthorizedUser(user): AuthorizedUser, Png(img): Png) -> Response {
|
||||||
let path = format!("./public/image/custom/avatar/{}.png", user.user_id);
|
let path = format!("./public/image/custom/avatar/{}.png", user.user_id);
|
||||||
|
|
||||||
|
@ -77,6 +141,20 @@ async fn avatar(AuthorizedUser(user): AuthorizedUser, Png(img): Png) -> Response
|
||||||
ResponseCode::Success.text("Successfully updated avatar")
|
ResponseCode::Success.text("Successfully updated avatar")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const USERS_BANNER: EndpointDocumentation = EndpointDocumentation {
|
||||||
|
uri: "/api/users/banner",
|
||||||
|
method: EndpointMethod::Put,
|
||||||
|
description: "Set your current profile banner",
|
||||||
|
body: Some("PNG sent as a binary blob"),
|
||||||
|
responses: &[
|
||||||
|
(200, "Successfully updated banner"),
|
||||||
|
(400, "Invalid PNG or disallowed size"),
|
||||||
|
(401, "Unauthorized"),
|
||||||
|
(500, "Failed to update banner")
|
||||||
|
],
|
||||||
|
cookie: Some("auth"),
|
||||||
|
};
|
||||||
|
|
||||||
async fn banner(AuthorizedUser(user): AuthorizedUser, Png(img): Png) -> Response {
|
async fn banner(AuthorizedUser(user): AuthorizedUser, Png(img): Png) -> Response {
|
||||||
let path = format!("./public/image/custom/banner/{}.png", user.user_id);
|
let path = format!("./public/image/custom/banner/{}.png", user.user_id);
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,8 @@ pub fn get_users_post_page(user_id: u64, page: u64) -> Result<Vec<Post>, rusqlit
|
||||||
tracing::trace!("Retrieving users posts");
|
tracing::trace!("Retrieving users posts");
|
||||||
let page_size = 10;
|
let page_size = 10;
|
||||||
let conn = database::connect()?;
|
let conn = database::connect()?;
|
||||||
let mut stmt = conn.prepare("SELECT * FROM posts WHERE user_id = ? ORDER BY post_id DESC LIMIT ? OFFSET ?")?;
|
let mut stmt = conn
|
||||||
|
.prepare("SELECT * FROM posts WHERE user_id = ? ORDER BY post_id DESC LIMIT ? OFFSET ?")?;
|
||||||
let row = stmt.query_map([user_id, page_size, page_size * page], |row| {
|
let row = stmt.query_map([user_id, page_size, page_size * page], |row| {
|
||||||
let row = post_from_row(row)?;
|
let row = post_from_row(row)?;
|
||||||
Ok(row)
|
Ok(row)
|
||||||
|
|
|
@ -15,6 +15,8 @@ use tracing_subscriber::{
|
||||||
};
|
};
|
||||||
use types::extract::RequestIp;
|
use types::extract::RequestIp;
|
||||||
|
|
||||||
|
use crate::public::docs;
|
||||||
|
|
||||||
mod api;
|
mod api;
|
||||||
mod database;
|
mod database;
|
||||||
mod public;
|
mod public;
|
||||||
|
@ -55,6 +57,8 @@ async fn main() {
|
||||||
exit(1)
|
exit(1)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
docs::init().await;
|
||||||
|
|
||||||
fs::create_dir_all("./public/image/custom").expect("Coudn't make custom data directory");
|
fs::create_dir_all("./public/image/custom").expect("Coudn't make custom data directory");
|
||||||
fs::create_dir_all("./public/image/custom/avatar")
|
fs::create_dir_all("./public/image/custom/avatar")
|
||||||
.expect("Coudn't make custom avatar directory");
|
.expect("Coudn't make custom avatar directory");
|
||||||
|
|
181
src/public/docs.rs
Normal file
181
src/public/docs.rs
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
use axum::response::Response;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
use crate::{api::{admin, users, posts, auth}, types::http::ResponseCode};
|
||||||
|
|
||||||
|
use super::console::beautify;
|
||||||
|
|
||||||
|
pub enum EndpointMethod {
|
||||||
|
Post,
|
||||||
|
Put,
|
||||||
|
Patch,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToString for EndpointMethod {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Post => "POST".to_owned(),
|
||||||
|
Self::Put => "PUT".to_owned(),
|
||||||
|
Self::Patch => "PATCH".to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EndpointDocumentation<'a> {
|
||||||
|
pub uri: &'static str,
|
||||||
|
pub method: EndpointMethod,
|
||||||
|
pub description: &'static str,
|
||||||
|
pub body: Option<&'static str>,
|
||||||
|
pub responses: &'a [(u16, &'static str)],
|
||||||
|
pub cookie: Option<&'static str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref ENDPOINTS: Mutex<Vec<String>> = Mutex::new(Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_body(body: Option<&'static str>) -> String {
|
||||||
|
let Some(body) = body else {
|
||||||
|
return String::new()
|
||||||
|
};
|
||||||
|
let html = r#"
|
||||||
|
<h2>Body</h2>
|
||||||
|
<div class="body">
|
||||||
|
$body
|
||||||
|
</div>
|
||||||
|
"#
|
||||||
|
.to_string();
|
||||||
|
let body = body.trim();
|
||||||
|
if body.starts_with('{') {
|
||||||
|
return html.replace(
|
||||||
|
"$body",
|
||||||
|
&beautify(body)
|
||||||
|
.replace("<span class='key'", "<br><span class='key'")
|
||||||
|
.replace('}', "<br>}"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
html.replace("$body", body)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_responses(responses: &[(u16, &'static str)]) -> String {
|
||||||
|
let mut html = r#"
|
||||||
|
<h2>Responses</h2>
|
||||||
|
$responses
|
||||||
|
"#
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
for response in responses {
|
||||||
|
let res = format!(
|
||||||
|
r#"
|
||||||
|
<div>
|
||||||
|
<span class="ptype">{}</span>
|
||||||
|
<span class="pdesc">{}</span>
|
||||||
|
</div>
|
||||||
|
$responses
|
||||||
|
"#,
|
||||||
|
response.0, response.1
|
||||||
|
);
|
||||||
|
html = html.replace("$responses", &res);
|
||||||
|
}
|
||||||
|
|
||||||
|
html.replace("$responses", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_cookie(cookie: Option<&'static str>) -> String {
|
||||||
|
let Some(cookie) = cookie else {
|
||||||
|
return String::new()
|
||||||
|
};
|
||||||
|
format!(
|
||||||
|
r#"<span class="auth"><span>{cookie}</span> cookie is required for authentication</span>"#
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_endpoint(doc: &EndpointDocumentation) -> String {
|
||||||
|
let html = r#"
|
||||||
|
<div>
|
||||||
|
<div class="endpoint">
|
||||||
|
<span class="method $method_class">$method</span>
|
||||||
|
<span class="uri">$uri</span>
|
||||||
|
<span class="desc">$description</span>
|
||||||
|
$cookie
|
||||||
|
</div>
|
||||||
|
<div class="info">
|
||||||
|
$body
|
||||||
|
$responses
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
"#;
|
||||||
|
|
||||||
|
html.replace("$method_class", &doc.method.to_string().to_lowercase())
|
||||||
|
.replace("$method", &doc.method.to_string())
|
||||||
|
.replace("$uri", doc.uri)
|
||||||
|
.replace("$description", doc.description)
|
||||||
|
.replace("$cookie", &generate_cookie(doc.cookie))
|
||||||
|
.replace("$body", &generate_body(doc.body))
|
||||||
|
.replace("$responses", &generate_responses(doc.responses))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn init() {
|
||||||
|
let docs = vec![
|
||||||
|
auth::AUTH_REGISTER,
|
||||||
|
auth::AUTH_LOGIN,
|
||||||
|
auth::AUTH_LOGOUT,
|
||||||
|
posts::POSTS_CREATE,
|
||||||
|
posts::POSTS_PAGE,
|
||||||
|
posts::POSTS_USER,
|
||||||
|
posts::POSTS_COMMENT,
|
||||||
|
posts::POSTS_LIKE,
|
||||||
|
users::USERS_LOAD,
|
||||||
|
users::USERS_PAGE,
|
||||||
|
users::USERS_SELF,
|
||||||
|
users::USERS_AVATAR,
|
||||||
|
users::USERS_BANNER,
|
||||||
|
admin::ADMIN_AUTH,
|
||||||
|
admin::ADMIN_QUERY,
|
||||||
|
admin::ADMIN_POSTS,
|
||||||
|
admin::ADMIN_USERS,
|
||||||
|
admin::ADMIN_SESSIONS,
|
||||||
|
];
|
||||||
|
let mut endpoints = ENDPOINTS.lock().await;
|
||||||
|
for doc in docs {
|
||||||
|
endpoints.push(generate_endpoint(&doc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn generate() -> Response {
|
||||||
|
let mut data = String::new();
|
||||||
|
{
|
||||||
|
let endpoints = ENDPOINTS.lock().await;
|
||||||
|
endpoints.iter().for_each(|endpoint| {
|
||||||
|
data.push_str(endpoint);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let html = format!(
|
||||||
|
r#"
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link rel="stylesheet" href="/css/main.css">
|
||||||
|
<link rel="stylesheet" href="/css/header.css">
|
||||||
|
<link rel="stylesheet" href="/css/console.css">
|
||||||
|
<link rel="stylesheet" href="/css/api.css">
|
||||||
|
<title>XSSBook - API Documentation</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="header">
|
||||||
|
<span class="logo"><a href="/">xssbook</a></span>
|
||||||
|
<span class="gtext desc" style="margin-left: 6em; font-size: 2em; color: #606770">API Documentation</span>
|
||||||
|
</div>
|
||||||
|
<div id="docs">
|
||||||
|
{data}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
ResponseCode::Success.html(&html)
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ use crate::types::http::ResponseCode;
|
||||||
|
|
||||||
pub mod admin;
|
pub mod admin;
|
||||||
pub mod console;
|
pub mod console;
|
||||||
|
pub mod docs;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
pub mod pages;
|
pub mod pages;
|
||||||
|
|
||||||
|
@ -33,7 +34,7 @@ pub fn router() -> Router {
|
||||||
|
|
||||||
Router::new()
|
Router::new()
|
||||||
.nest("/", pages::router())
|
.nest("/", pages::router())
|
||||||
.route("/favicon.ico",get(file::favicon))
|
.route("/favicon.ico", get(file::favicon))
|
||||||
.route("/js/*path", get(file::js))
|
.route("/js/*path", get(file::js))
|
||||||
.route("/css/*path", get(file::css))
|
.route("/css/*path", get(file::css))
|
||||||
.route("/fonts/*path", get(file::fonts))
|
.route("/fonts/*path", get(file::fonts))
|
||||||
|
|
|
@ -12,6 +12,8 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::docs;
|
||||||
|
|
||||||
async fn root(user: Option<AuthorizedUser>, _: Log) -> Response {
|
async fn root(user: Option<AuthorizedUser>, _: Log) -> Response {
|
||||||
if user.is_some() {
|
if user.is_some() {
|
||||||
Redirect::to("/home").into_response()
|
Redirect::to("/home").into_response()
|
||||||
|
@ -49,7 +51,7 @@ async fn admin() -> Response {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn api() -> Response {
|
async fn api() -> Response {
|
||||||
super::serve("/api.html").await
|
docs::generate().await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wordpress(_: Log) -> Response {
|
async fn wordpress(_: Log) -> Response {
|
||||||
|
|
Loading…
Reference in a new issue