summaryrefslogtreecommitdiff
path: root/src/public/docs.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/public/docs.rs')
-rw-r--r--src/public/docs.rs181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/public/docs.rs b/src/public/docs.rs
new file mode 100644
index 0000000..1f1448b
--- /dev/null
+++ b/src/public/docs.rs
@@ -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)
+}