summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@blos.sm>2024-11-13 20:00:15 +0000
committerLibravatar cel 🌸 <cel@blos.sm>2024-11-13 20:00:15 +0000
commitb7a2265e9b29d8fa09f84f5213ef7f8ed3045ca6 (patch)
tree280a31f5887aafdaa200a2b5f4c05ff106d9e365 /src
downloadcritch-b7a2265e9b29d8fa09f84f5213ef7f8ed3045ca6.tar.gz
critch-b7a2265e9b29d8fa09f84f5213ef7f8ed3045ca6.tar.bz2
critch-b7a2265e9b29d8fa09f84f5213ef7f8ed3045ca6.zip
initial commit
Diffstat (limited to 'src')
-rw-r--r--src/artist.rs6
-rw-r--r--src/artwork.rs14
-rw-r--r--src/build.rs8
-rw-r--r--src/comment.rs12
-rw-r--r--src/config.rs43
-rw-r--r--src/db/artworks.rs1
-rw-r--r--src/db/mod.rs20
-rw-r--r--src/error.rs30
-rw-r--r--src/file.rs7
-rw-r--r--src/lib.rs28
-rw-r--r--src/main.rs49
-rw-r--r--src/routes/admin.rs11
-rw-r--r--src/routes/artists.rs21
-rw-r--r--src/routes/artworks.rs23
-rw-r--r--src/routes/artworks/comments.rs11
-rw-r--r--src/routes/mod.rs3
-rw-r--r--src/ructe_poem.rs27
17 files changed, 314 insertions, 0 deletions
diff --git a/src/artist.rs b/src/artist.rs
new file mode 100644
index 0000000..06b90e7
--- /dev/null
+++ b/src/artist.rs
@@ -0,0 +1,6 @@
+pub struct Artist {
+ id: Option<usize>,
+ name: String,
+ bio: Option<String>,
+ site: Option<String>,
+}
diff --git a/src/artwork.rs b/src/artwork.rs
new file mode 100644
index 0000000..78b39af
--- /dev/null
+++ b/src/artwork.rs
@@ -0,0 +1,14 @@
+pub struct Artwork {
+ /// artwork id
+ id: Option<usize>,
+ /// name of the artwork
+ title: Option<String>,
+ /// description of the artwork
+ description: Option<String>,
+ /// source url of the artwork
+ url_source: Option<String>,
+ /// id of the artist
+ artist_id: usize,
+ /// ids of files
+ files: Vec<usize>,
+}
diff --git a/src/build.rs b/src/build.rs
new file mode 100644
index 0000000..16c887c
--- /dev/null
+++ b/src/build.rs
@@ -0,0 +1,8 @@
+use ructe::{Result, Ructe};
+
+fn main() -> Result<()> {
+ let mut ructe = Ructe::from_env()?;
+ ructe.statics()?.add_files("./static")?;
+ // .add_sass_file("./style.scss")?;
+ ructe.compile_templates("templates")
+}
diff --git a/src/comment.rs b/src/comment.rs
new file mode 100644
index 0000000..77b0fc0
--- /dev/null
+++ b/src/comment.rs
@@ -0,0 +1,12 @@
+pub struct Comment {
+ /// id of the comment in the thread
+ id: Option<usize>,
+ /// text of the comment
+ text: String,
+ /// thread comment is in
+ thread: usize,
+ /// comments that are mentioned by the comment
+ in_reply_to: Vec<usize>,
+ /// comments that mention the comment
+ mentioned_by: Vec<usize>,
+}
diff --git a/src/config.rs b/src/config.rs
new file mode 100644
index 0000000..eee2fc2
--- /dev/null
+++ b/src/config.rs
@@ -0,0 +1,43 @@
+use std::{
+ fs::File,
+ io::Read,
+ path::{Path, PathBuf},
+};
+
+use serde::Deserialize;
+
+use crate::Result;
+
+#[derive(Deserialize, Clone)]
+pub struct Config {
+ admin_password: String,
+ site_password: Option<String>,
+ files_dir: std::path::PathBuf,
+ database_connection: String,
+}
+
+impl Config {
+ pub fn from_file(path: &str) -> Result<Self> {
+ let path = PathBuf::from(path);
+ let mut config = String::new();
+ File::open(path)?.read_to_string(&mut config)?;
+ let config: Config = toml::from_str(&config)?;
+ Ok(config)
+ }
+
+ pub fn admin_password(&self) -> &str {
+ &self.admin_password
+ }
+
+ pub fn site_password(&self) -> Option<&str> {
+ self.site_password.as_deref()
+ }
+
+ pub fn files_dir(&self) -> &Path {
+ self.files_dir.as_path()
+ }
+
+ pub fn database_connection(&self) -> &str {
+ &self.database_connection
+ }
+}
diff --git a/src/db/artworks.rs b/src/db/artworks.rs
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/db/artworks.rs
@@ -0,0 +1 @@
+
diff --git a/src/db/mod.rs b/src/db/mod.rs
new file mode 100644
index 0000000..97a5b25
--- /dev/null
+++ b/src/db/mod.rs
@@ -0,0 +1,20 @@
+use sqlx::{postgres::PgPoolOptions, Pool, Postgres};
+
+mod artworks;
+
+#[derive(Clone)]
+pub struct Database(Pool<Postgres>);
+
+impl Database {
+ pub async fn new(connection_string: &str) -> Self {
+ let pool = PgPoolOptions::new()
+ .max_connections(5)
+ .connect(connection_string)
+ .await
+ .unwrap();
+
+ sqlx::migrate!("./migrations").run(&pool).await.unwrap();
+
+ Self(pool)
+ }
+}
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..03cad93
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,30 @@
+use std::fmt::Display;
+
+#[derive(Debug)]
+pub enum Error {
+ IOError(std::io::Error),
+ TOMLError(toml::de::Error),
+}
+
+impl Display for Error {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Error::IOError(error) => write!(f, "IO Error: {}", error),
+ Error::TOMLError(error) => write!(f, "TOML deserialization error: {}", error),
+ }
+ }
+}
+
+impl std::error::Error for Error {}
+
+impl From<std::io::Error> for Error {
+ fn from(e: std::io::Error) -> Self {
+ Self::IOError(e)
+ }
+}
+
+impl From<toml::de::Error> for Error {
+ fn from(e: toml::de::Error) -> Self {
+ Self::TOMLError(e)
+ }
+}
diff --git a/src/file.rs b/src/file.rs
new file mode 100644
index 0000000..8a49839
--- /dev/null
+++ b/src/file.rs
@@ -0,0 +1,7 @@
+use uuid::Uuid;
+
+#[derive(sqlx::FromRow)]
+pub struct File {
+ id: Option<Uuid>,
+ artwork: usize,
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..fc2ab75
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,28 @@
+use config::Config;
+use db::Database;
+
+mod artist;
+mod artwork;
+mod comment;
+pub mod config;
+mod db;
+mod error;
+mod file;
+pub mod routes;
+mod ructe_poem;
+
+pub type Result<T> = std::result::Result<T, error::Error>;
+
+#[derive(Clone)]
+pub struct Critch {
+ db: Database,
+ config: Config,
+}
+
+impl Critch {
+ pub async fn new(config: Config) -> Self {
+ let db = Database::new(config.database_connection()).await;
+
+ Self { db, config }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..639ba2d
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,49 @@
+use poem::{delete, post, put, EndpointExt};
+use poem::{get, listener::TcpListener, Route, Server};
+
+use critch::config::Config;
+use critch::routes;
+use critch::Critch;
+
+#[tokio::main]
+async fn main() -> Result<(), std::io::Error> {
+ let config = Config::from_file("./critch.toml").unwrap();
+ let state = Critch::new(config).await;
+
+ let app = Route::new()
+ .at(
+ "/admin",
+ post(routes::admin::login).get(routes::admin::get_login_form),
+ )
+ .at("/", get(routes::artworks::get))
+ .at(
+ "/artworks",
+ get(routes::artworks::get).post(routes::artworks::post),
+ )
+ .at(
+ "/artworks/:artwork",
+ get(routes::artworks::get)
+ .put(routes::artworks::put)
+ .delete(routes::artworks::delete),
+ )
+ .at(
+ "/artists",
+ get(routes::artists::get).post(routes::artists::post),
+ )
+ .at(
+ "/artists/:artist",
+ get(routes::artists::get)
+ .put(routes::artists::put)
+ .delete(routes::artists::delete),
+ )
+ .at(
+ "/artworks/:artwork/comments",
+ post(routes::artworks::comments::post).delete(routes::artworks::comments::delete),
+ )
+ .data(state);
+
+ Server::new(TcpListener::bind("0.0.0.0:3000"))
+ .run(app)
+ .await?;
+ Ok(())
+}
diff --git a/src/routes/admin.rs b/src/routes/admin.rs
new file mode 100644
index 0000000..98cb954
--- /dev/null
+++ b/src/routes/admin.rs
@@ -0,0 +1,11 @@
+use poem::handler;
+
+#[handler]
+pub async fn login() {
+ todo!()
+}
+
+#[handler]
+pub async fn get_login_form() {
+ todo!()
+}
diff --git a/src/routes/artists.rs b/src/routes/artists.rs
new file mode 100644
index 0000000..79a2ab1
--- /dev/null
+++ b/src/routes/artists.rs
@@ -0,0 +1,21 @@
+use poem::handler;
+
+#[handler]
+pub async fn post() {
+ todo!()
+}
+
+#[handler]
+pub async fn get() {
+ todo!()
+}
+
+#[handler]
+pub async fn put() {
+ todo!()
+}
+
+#[handler]
+pub async fn delete() {
+ todo!()
+}
diff --git a/src/routes/artworks.rs b/src/routes/artworks.rs
new file mode 100644
index 0000000..556265f
--- /dev/null
+++ b/src/routes/artworks.rs
@@ -0,0 +1,23 @@
+use poem::{handler, web::Path};
+
+pub mod comments;
+
+#[handler]
+pub async fn post() {
+ todo!()
+}
+
+#[handler]
+pub async fn get() {
+ todo!()
+}
+
+#[handler]
+pub async fn put() {
+ todo!()
+}
+
+#[handler]
+pub async fn delete() {
+ todo!()
+}
diff --git a/src/routes/artworks/comments.rs b/src/routes/artworks/comments.rs
new file mode 100644
index 0000000..dfac733
--- /dev/null
+++ b/src/routes/artworks/comments.rs
@@ -0,0 +1,11 @@
+use poem::handler;
+
+#[handler]
+pub async fn post() {
+ todo!()
+}
+
+#[handler]
+pub async fn delete() {
+ todo!()
+}
diff --git a/src/routes/mod.rs b/src/routes/mod.rs
new file mode 100644
index 0000000..fe8e0d1
--- /dev/null
+++ b/src/routes/mod.rs
@@ -0,0 +1,3 @@
+pub mod admin;
+pub mod artists;
+pub mod artworks;
diff --git a/src/ructe_poem.rs b/src/ructe_poem.rs
new file mode 100644
index 0000000..fc14048
--- /dev/null
+++ b/src/ructe_poem.rs
@@ -0,0 +1,27 @@
+use poem::{http::StatusCode, Body, IntoResponse};
+
+macro_rules! render {
+ ($template:path) => {{
+ use $crate::axum_ructe::Render;
+ Render(|o| $template(o))
+ }};
+ ($template:path, $($arg:expr),* $(,)*) => {{
+ use $crate::axum_ructe::Render;
+ Render(move |o| $template(o, $($arg),*))
+ }}
+}
+
+pub struct Render<T: FnOnce(&mut Vec<u8>) -> std::io::Result<()> + Send>(pub T);
+
+impl<T: FnOnce(&mut Vec<u8>) -> std::io::Result<()> + Send> IntoResponse for Render<T> {
+ fn into_response(self) -> poem::Response {
+ let mut buf = Vec::new();
+ match self.0(&mut buf) {
+ Ok(()) => Body::from_vec(buf).into_response(),
+ Err(_e) => {
+ // TODO: logging
+ (StatusCode::INTERNAL_SERVER_ERROR, "Render failed").into_response()
+ }
+ }
+ }
+}