IPFS CDN directory listing

This commit is contained in:
Timo Ley 2021-12-18 21:15:06 +01:00
parent fc2fb200f0
commit c479c24928
5 changed files with 86 additions and 3 deletions

View file

@ -21,3 +21,4 @@ reqwest = { version = "0.11", features = ["stream", "multipart"] }
new_mime_guess = "3.0.2"
headers = "0.3.5"
url = {version = "2.2.2", features = ["serde"]}
askama = "0.10"

View file

@ -6,10 +6,15 @@ use sqlx::{Error, MySqlPool};
use crate::config::ConfVars;
use self::templates::{DirTemplate, HtmlTemplate};
mod sql;
mod templates;
pub fn routes() -> Router<BoxRoute> {
Router::new()
.route("/", get(users))
.route("/:user/", get(memes))
.route("/:user/:filename", get(image))
.boxed()
}
@ -49,3 +54,27 @@ async fn image(Path((user, filename)): Path<(String, String)>, Extension(db_pool
},
}
}
async fn users(Extension(db_pool): Extension<MySqlPool>, Extension(vars): Extension<ConfVars>) -> Result<impl IntoResponse, StatusCode> {
let q = sql::get_users(&db_pool).await;
match q {
Ok(users) => Ok(HtmlTemplate(DirTemplate {
entries: users,
prefix: vars.cdn,
suffix: "/".to_string(),
})),
Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR),
}
}
async fn memes(Path(user): Path<String>, Extension(db_pool): Extension<MySqlPool>) -> Result<impl IntoResponse, StatusCode> {
let q = sql::get_memes(user, &db_pool).await;
match q {
Ok(memes) => Ok(HtmlTemplate(DirTemplate {
entries: memes,
prefix: ".".to_string(),
suffix: "".to_string(),
})),
Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR),
}
}

View file

@ -2,10 +2,22 @@ use sqlx::{MySqlPool, Result, Row, mysql::MySqlRow};
pub async fn get_cid(user: String, filename: String, pool: &MySqlPool) -> Result<String> {
let q: String = sqlx::query("SELECT cid FROM memes WHERE user = ? AND filename = ? ORDER BY id DESC").bind(user).bind(filename)
.map(|row: MySqlRow| row.get("cid"))
.fetch_one(pool).await?;
Ok(q)
}
pub async fn get_memes(user: String, pool: &MySqlPool) -> Result<Vec<String>> {
let q: Vec<String> = sqlx::query("SELECT filename FROM memes WHERE user = ? ORDER BY filename").bind(user)
.map(|row: MySqlRow| row.get("filename"))
.fetch_all(pool).await?;
Ok(q)
}
pub async fn get_users(pool: &MySqlPool) -> Result<Vec<String>> {
let q: Vec<String> = sqlx::query("SELECT id FROM users ORDER BY id")
.map(|row: MySqlRow| row.get("id"))
.fetch_all(pool).await?;
Ok(q)
}

30
src/cdn/templates.rs Normal file
View file

@ -0,0 +1,30 @@
use askama::Template;
use axum::response::{IntoResponse, Html};
use axum::body::{Full, Bytes};
use axum::http::{Response, StatusCode};
use std::convert::Infallible;
pub struct HtmlTemplate<T>(pub T);
impl<T> IntoResponse for HtmlTemplate<T>
where
T: Template,
{
type Body = Full<Bytes>;
type BodyError = Infallible;
fn into_response(self) -> Response<Self::Body> {
match self.0.render() {
Ok(html) => Html(html).into_response(),
Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, "").into_response()
}
}
}
#[derive(Template)]
#[template(path = "dir.html")]
pub struct DirTemplate {
pub entries: Vec<String>,
pub prefix: String,
pub suffix: String,
}

11
templates/dir.html Normal file
View file

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
{% for entry in entries %}
<a href="{{prefix}}/{{entry}}{{suffix}}">{{entry}}</a><br>
{% endfor %}
</body>
</html>