summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdam T. Carpenter <atc@53hor.net>2024-09-14 20:30:05 -0400
committerAdam T. Carpenter <atc@53hor.net>2024-09-14 20:30:05 -0400
commit9f341d439f7aa5fd2365024169ead2d6bdc3210c (patch)
treec9967da54d4f8ca02385fc3fac4989572fd00eee /src
parent340a804e550cb5b733bd2e64e515e79740bb6338 (diff)
downloadcarpentertutoring-9f341d439f7aa5fd2365024169ead2d6bdc3210c.tar.xz
carpentertutoring-9f341d439f7aa5fd2365024169ead2d6bdc3210c.zip
feat: rewrite complete
Diffstat (limited to 'src')
-rw-r--r--src/handlers.rs34
-rw-r--r--src/helpers.rs5
-rw-r--r--src/main.rs213
-rw-r--r--src/posts.rs3
-rw-r--r--src/posts/abstractions.rs2
-rw-r--r--src/posts/abstractions/post.rs6
-rw-r--r--src/posts/abstractions/repo.rs5
-rw-r--r--src/posts/fs_post.rs24
-rw-r--r--src/posts/fs_post_repo.rs23
-rw-r--r--src/tutors.rs3
-rw-r--r--src/tutors/abstractions.rs2
-rw-r--r--src/tutors/abstractions/tutor.rs7
-rw-r--r--src/tutors/abstractions/tutor_repo.rs5
-rw-r--r--src/tutors/fs_tutor.rs48
-rw-r--r--src/tutors/fs_tutor_repo.rs29
-rw-r--r--src/views.rs5
-rw-r--r--src/views/about.rs17
-rw-r--r--src/views/brochure.rs6
-rw-r--r--src/views/index.rs6
-rw-r--r--src/views/policies.rs6
-rw-r--r--src/views/posts.rs17
21 files changed, 267 insertions, 199 deletions
diff --git a/src/handlers.rs b/src/handlers.rs
new file mode 100644
index 0000000..db5cf7c
--- /dev/null
+++ b/src/handlers.rs
@@ -0,0 +1,34 @@
+use askama::Template;
+use crate::views::posts::PostsView;
+use crate::posts::abstractions::repo::PostRepo;
+use crate::views::policies::PoliciesTemplate;
+use crate::views::index::IndexTemplate;
+use crate::views::brochure::BrochureTemplate;
+use crate::views::about::AboutView;
+use crate::tutors::abstractions::tutor_repo::TutorRepo;
+use std::sync::Arc;
+use axum::response::Html;
+use axum::extract::State;
+
+pub async fn about_handler(State(repo): State<Arc<impl TutorRepo>>) -> Html<String> {
+ let view = AboutView::with_tutors(repo.load());
+ Html(view.render().unwrap())
+}
+
+pub async fn brochure_handler() -> Html<String> {
+ Html(BrochureTemplate{}.render().unwrap())
+}
+
+pub async fn index_handler() -> Html<String> {
+ Html(IndexTemplate {}.render().unwrap())
+}
+
+pub async fn policies_handler() -> Html<String> {
+ Html(PoliciesTemplate{}.render().unwrap())
+}
+
+pub async fn posts_handler(State(repo): State<Arc<impl PostRepo>>) -> Html<String> {
+ let view = PostsView::with_posts(repo.load());
+ Html(view.render().unwrap())
+}
+
diff --git a/src/helpers.rs b/src/helpers.rs
new file mode 100644
index 0000000..c7509de
--- /dev/null
+++ b/src/helpers.rs
@@ -0,0 +1,5 @@
+use chrono::{prelude::*, Utc};
+
+pub fn current_year() -> i32 {
+ Utc::now().year()
+}
diff --git a/src/main.rs b/src/main.rs
index 7b5ddfc..fb15e51 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,199 +1,14 @@
-use std::cmp::Ordering;
-use std::borrow::Cow;
-use tower_http::services::ServeDir;
-use axum::response::Html;
-use axum::extract::State;
-use std::sync::Arc;
-use askama_axum::Template;
use axum::{routing::get, Router};
-use std::fmt;
-use std::fs;
-use std::path::PathBuf;
-use chrono::Datelike;
-
-fn current_year() -> i32 {
- chrono::Utc::now().year()
-}
-
-trait Post: fmt::Debug {
- fn get_title(&self) -> &str;
- fn get_article(&self) -> Cow<str>;
-}
-
-#[derive(Debug)]
-struct FsPost {
- file: PathBuf,
-}
-
-impl Post for FsPost {
- fn get_title(&self) -> &str {
- self.file.file_name().unwrap().to_str().unwrap()
- }
-
- fn get_article(&self) -> Cow<str> {
- let article = fs::read_to_string(&self.file).unwrap();
- Cow::Owned(article)
- }
-}
-
-trait PostRepo {
- fn load(&self) -> impl IntoIterator<Item = impl Post>;
-}
-
-struct FsPostRepo {
- dir: PathBuf,
-}
-
-impl FsPostRepo {
- fn with_dir(path: impl Into<PathBuf>) -> Self {
- Self {
- dir: path.into()
- }
- }
-}
-
-impl PostRepo for FsPostRepo {
- fn load(&self) -> impl IntoIterator<Item = FsPost> {
- let files = fs::read_dir(&self.dir).unwrap();
- files
- .flatten()
- .filter(|d| !d.file_name().to_string_lossy().starts_with('.'))
- .map(|d| FsPost { file: d.path() })
- }
-}
-
-
-#[derive(Template)]
-#[template(path = "posts.html")]
-struct PostsView<P: Post> {
- posts: Vec<P>
-}
-
-impl<P: Post> PostsView<P> {
- fn with_posts(posts: impl IntoIterator<Item = P>) -> Self {
- Self {
- posts: posts.into_iter().collect()
- }
- }
-}
-
-async fn posts_handler(State(repo): State<Arc<impl PostRepo>>) -> Html<String> {
- let view = PostsView::with_posts(repo.load());
- Html(view.render().unwrap())
-}
-
-trait Tutor: fmt::Debug + Ord {
- fn get_name(&self) -> &str;
- fn get_id(&self) -> &str;
- fn get_blurb(&self) -> Cow<str>;
-}
-
-#[derive(Debug, Eq)]
-struct FsTutor {
- dir: PathBuf
-}
-
-impl Tutor for FsTutor {
- fn get_id(&self) -> &str {
- self.dir.file_name().unwrap().to_str().unwrap()
- }
-
- fn get_name(&self) -> &str {
- self.get_id()
- }
-
- fn get_blurb(&self) -> Cow<str> {
- let mut path = self.dir.to_owned();
- path.push(format!("{}.md", self.get_id()));
- let blurb = fs::read_to_string(path).unwrap();
- Cow::Owned(blurb)
- }
-}
-
-impl Ord for FsTutor {
- fn cmp(&self, other: &Self) -> Ordering {
- self.get_id().cmp(other.get_id())
- }
-}
-
-impl PartialOrd for FsTutor {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl PartialEq for FsTutor {
- fn eq(&self, other: &Self) -> bool {
- self.get_id() == other.get_id()
- }
-}
-
-trait TutorRepo {
- fn load(&self) -> impl IntoIterator<Item = impl Tutor>;
-}
-
-struct FsTutorRepo {
- dir: PathBuf
-}
-
-impl FsTutorRepo {
- fn with_dir(path: impl Into<PathBuf>) -> Self {
- Self {
- dir: path.into()
- }
- }
-}
-
-
-impl TutorRepo for FsTutorRepo {
- fn load(&self) -> impl IntoIterator<Item = FsTutor> {
- let dirs = fs::read_dir(&self.dir).unwrap();
- dirs.flatten().filter(|d| !d.path().file_stem().unwrap().to_str().unwrap_or_default().starts_with('.')).map(|d| FsTutor { dir: d.path() })
- }
-}
-
-
-#[derive(Template)]
-#[template(path = "about/index.html")]
-struct AboutView<T: Tutor> {
- tutors: Vec<T>,
-}
-impl<T: Tutor + Ord> AboutView<T> {
- fn with_tutors(tutors: impl IntoIterator<Item = T>) -> Self {
- let mut tutors: Vec<T> = tutors.into_iter().collect();
- tutors.sort();
- Self { tutors }
- }
-}
-
-async fn about_handler(State(repo): State<Arc<impl TutorRepo>>) -> Html<String> {
- let view = AboutView::with_tutors(repo.load());
- Html(view.render().unwrap())
-}
-
-#[derive(Template)]
-#[template(path = "index.html")]
-struct IndexTemplate;
-
-async fn index_handler() -> Html<String> {
- Html(IndexTemplate {}.render().unwrap())
-}
-
-#[derive(Template)]
-#[template(path = "policies.html")]
-struct PoliciesTemplate;
-
-async fn policies_handler() -> Html<String> {
- Html(PoliciesTemplate{}.render().unwrap())
-}
-
-#[derive(Template)]
-#[template(path = "brochure/index.html")]
-struct BrochureTemplate;
+use tutors::fs_tutor_repo::FsTutorRepo;
+use std::sync::Arc;
+use tower_http::services::ServeDir;
+use posts::fs_post_repo::FsPostRepo;
-async fn brochure_handler() -> Html<String> {
- Html(BrochureTemplate{}.render().unwrap())
-}
+mod helpers;
+mod posts;
+mod tutors;
+mod views;
+mod handlers;
#[tokio::main]
async fn main() {
@@ -201,12 +16,12 @@ async fn main() {
let tutors = Arc::new(FsTutorRepo::with_dir(format!("/data/ct/{}", "team")));
let app = Router::new()
- .route("/", get(index_handler))
- .route("/posts", get(posts_handler))
+ .route("/", get(handlers::index_handler))
+ .route("/posts", get(handlers::posts_handler))
.with_state(posts)
- .route("/policies", get(policies_handler))
- .route("/brochure", get(brochure_handler))
- .route("/about", get(about_handler))
+ .route("/policies", get(handlers::policies_handler))
+ .route("/brochure", get(handlers::brochure_handler))
+ .route("/about", get(handlers::about_handler))
.with_state(tutors)
.nest_service("/assets", ServeDir::new("/data/ct/assets"))
.nest_service("/team", ServeDir::new("/data/ct/team"))
diff --git a/src/posts.rs b/src/posts.rs
new file mode 100644
index 0000000..7f2c217
--- /dev/null
+++ b/src/posts.rs
@@ -0,0 +1,3 @@
+pub mod abstractions;
+pub mod fs_post;
+pub mod fs_post_repo;
diff --git a/src/posts/abstractions.rs b/src/posts/abstractions.rs
new file mode 100644
index 0000000..96c8ced
--- /dev/null
+++ b/src/posts/abstractions.rs
@@ -0,0 +1,2 @@
+pub mod post;
+pub mod repo;
diff --git a/src/posts/abstractions/post.rs b/src/posts/abstractions/post.rs
new file mode 100644
index 0000000..6d504db
--- /dev/null
+++ b/src/posts/abstractions/post.rs
@@ -0,0 +1,6 @@
+use std::{borrow::Cow, fmt};
+
+pub trait Post: fmt::Debug {
+ fn get_title(&self) -> &str;
+ fn get_article(&self) -> Cow<str>;
+}
diff --git a/src/posts/abstractions/repo.rs b/src/posts/abstractions/repo.rs
new file mode 100644
index 0000000..6fcb385
--- /dev/null
+++ b/src/posts/abstractions/repo.rs
@@ -0,0 +1,5 @@
+use crate::posts::abstractions::post::Post;
+
+pub trait PostRepo {
+ fn load(&self) -> impl IntoIterator<Item = impl Post>;
+}
diff --git a/src/posts/fs_post.rs b/src/posts/fs_post.rs
new file mode 100644
index 0000000..e767803
--- /dev/null
+++ b/src/posts/fs_post.rs
@@ -0,0 +1,24 @@
+use crate::posts::abstractions::post::Post;
+use std::{borrow::Cow, fs, path::PathBuf};
+
+#[derive(Debug)]
+pub struct FsPost {
+ file: PathBuf,
+}
+
+impl FsPost {
+ pub fn with_path(path: PathBuf) -> Self {
+ Self { file: path }
+ }
+}
+
+impl Post for FsPost {
+ fn get_title(&self) -> &str {
+ self.file.file_name().unwrap().to_str().unwrap()
+ }
+
+ fn get_article(&self) -> Cow<str> {
+ let article = fs::read_to_string(&self.file).unwrap();
+ Cow::Owned(article)
+ }
+}
diff --git a/src/posts/fs_post_repo.rs b/src/posts/fs_post_repo.rs
new file mode 100644
index 0000000..eb37a6a
--- /dev/null
+++ b/src/posts/fs_post_repo.rs
@@ -0,0 +1,23 @@
+use crate::posts::abstractions::repo::PostRepo;
+use crate::posts::fs_post::FsPost;
+use std::{fs, path::PathBuf};
+
+pub struct FsPostRepo {
+ dir: PathBuf,
+}
+
+impl FsPostRepo {
+ pub fn with_dir(path: impl Into<PathBuf>) -> Self {
+ Self { dir: path.into() }
+ }
+}
+
+impl PostRepo for FsPostRepo {
+ fn load(&self) -> impl IntoIterator<Item = FsPost> {
+ let files = fs::read_dir(&self.dir).unwrap();
+ files
+ .flatten()
+ .filter(|d| !d.file_name().to_string_lossy().starts_with('.'))
+ .map(|d| FsPost::with_path(d.path()))
+ }
+}
diff --git a/src/tutors.rs b/src/tutors.rs
new file mode 100644
index 0000000..d90ef99
--- /dev/null
+++ b/src/tutors.rs
@@ -0,0 +1,3 @@
+pub mod abstractions;
+pub mod fs_tutor;
+pub mod fs_tutor_repo;
diff --git a/src/tutors/abstractions.rs b/src/tutors/abstractions.rs
new file mode 100644
index 0000000..a93c25d
--- /dev/null
+++ b/src/tutors/abstractions.rs
@@ -0,0 +1,2 @@
+pub mod tutor;
+pub mod tutor_repo;
diff --git a/src/tutors/abstractions/tutor.rs b/src/tutors/abstractions/tutor.rs
new file mode 100644
index 0000000..f36da3d
--- /dev/null
+++ b/src/tutors/abstractions/tutor.rs
@@ -0,0 +1,7 @@
+use std::{borrow::Cow, fmt};
+
+pub trait Tutor: fmt::Debug + Ord {
+ fn get_name(&self) -> &str;
+ fn get_id(&self) -> &str;
+ fn get_blurb(&self) -> Cow<str>;
+}
diff --git a/src/tutors/abstractions/tutor_repo.rs b/src/tutors/abstractions/tutor_repo.rs
new file mode 100644
index 0000000..e017806
--- /dev/null
+++ b/src/tutors/abstractions/tutor_repo.rs
@@ -0,0 +1,5 @@
+use crate::tutors::abstractions::tutor::Tutor;
+
+pub trait TutorRepo {
+ fn load(&self) -> impl IntoIterator<Item = impl Tutor>;
+}
diff --git a/src/tutors/fs_tutor.rs b/src/tutors/fs_tutor.rs
new file mode 100644
index 0000000..dc8a635
--- /dev/null
+++ b/src/tutors/fs_tutor.rs
@@ -0,0 +1,48 @@
+use crate::tutors::abstractions::tutor::Tutor;
+use std::{borrow::Cow, cmp::Ordering, fs, path::PathBuf};
+
+#[derive(Debug, Eq)]
+pub struct FsTutor {
+ dir: PathBuf,
+}
+
+impl FsTutor {
+ pub fn with_dir(path: PathBuf) -> Self {
+ Self { dir: path }
+ }
+}
+
+impl Tutor for FsTutor {
+ fn get_id(&self) -> &str {
+ self.dir.file_name().unwrap().to_str().unwrap()
+ }
+
+ fn get_name(&self) -> &str {
+ self.get_id()
+ }
+
+ fn get_blurb(&self) -> Cow<str> {
+ let mut path = self.dir.to_owned();
+ path.push(format!("{}.md", self.get_id()));
+ let blurb = fs::read_to_string(path).unwrap();
+ Cow::Owned(blurb)
+ }
+}
+
+impl Ord for FsTutor {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.get_id().cmp(other.get_id())
+ }
+}
+
+impl PartialOrd for FsTutor {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl PartialEq for FsTutor {
+ fn eq(&self, other: &Self) -> bool {
+ self.get_id() == other.get_id()
+ }
+}
diff --git a/src/tutors/fs_tutor_repo.rs b/src/tutors/fs_tutor_repo.rs
new file mode 100644
index 0000000..9b9a8d9
--- /dev/null
+++ b/src/tutors/fs_tutor_repo.rs
@@ -0,0 +1,29 @@
+use crate::tutors::abstractions::tutor_repo::TutorRepo;
+use crate::tutors::fs_tutor::FsTutor;
+use std::{fs, path::PathBuf};
+
+pub struct FsTutorRepo {
+ dir: PathBuf,
+}
+
+impl FsTutorRepo {
+ pub fn with_dir(path: impl Into<PathBuf>) -> Self {
+ Self { dir: path.into() }
+ }
+}
+
+impl TutorRepo for FsTutorRepo {
+ fn load(&self) -> impl IntoIterator<Item = FsTutor> {
+ let dirs = fs::read_dir(&self.dir).unwrap();
+ dirs.flatten()
+ .filter(|d| {
+ !d.path()
+ .file_stem()
+ .unwrap()
+ .to_str()
+ .unwrap_or_default()
+ .starts_with('.')
+ })
+ .map(|d| FsTutor::with_dir(d.path()))
+ }
+}
diff --git a/src/views.rs b/src/views.rs
new file mode 100644
index 0000000..b986f56
--- /dev/null
+++ b/src/views.rs
@@ -0,0 +1,5 @@
+pub mod about;
+pub mod brochure;
+pub mod index;
+pub mod policies;
+pub mod posts;
diff --git a/src/views/about.rs b/src/views/about.rs
new file mode 100644
index 0000000..349c9de
--- /dev/null
+++ b/src/views/about.rs
@@ -0,0 +1,17 @@
+use crate::helpers::*;
+use crate::tutors::abstractions::tutor::Tutor;
+use askama::Template;
+
+#[derive(Template)]
+#[template(path = "about/index.html")]
+pub struct AboutView<T: Tutor> {
+ tutors: Vec<T>,
+}
+
+impl<T: Tutor> AboutView<T> {
+ pub fn with_tutors(tutors: impl IntoIterator<Item = T>) -> Self {
+ let mut tutors: Vec<T> = tutors.into_iter().collect();
+ tutors.sort();
+ Self { tutors }
+ }
+}
diff --git a/src/views/brochure.rs b/src/views/brochure.rs
new file mode 100644
index 0000000..0d2f8fc
--- /dev/null
+++ b/src/views/brochure.rs
@@ -0,0 +1,6 @@
+use crate::helpers::*;
+use askama::Template;
+
+#[derive(Template)]
+#[template(path = "brochure/index.html")]
+pub struct BrochureTemplate;
diff --git a/src/views/index.rs b/src/views/index.rs
new file mode 100644
index 0000000..3ced24d
--- /dev/null
+++ b/src/views/index.rs
@@ -0,0 +1,6 @@
+use crate::helpers::*;
+use askama::Template;
+
+#[derive(Template)]
+#[template(path = "index.html")]
+pub struct IndexTemplate;
diff --git a/src/views/policies.rs b/src/views/policies.rs
new file mode 100644
index 0000000..3d9787d
--- /dev/null
+++ b/src/views/policies.rs
@@ -0,0 +1,6 @@
+use crate::helpers::*;
+use askama::Template;
+
+#[derive(Template)]
+#[template(path = "policies.html")]
+pub struct PoliciesTemplate;
diff --git a/src/views/posts.rs b/src/views/posts.rs
new file mode 100644
index 0000000..2ce69f8
--- /dev/null
+++ b/src/views/posts.rs
@@ -0,0 +1,17 @@
+use crate::helpers::*;
+use crate::posts::abstractions::post::Post;
+use askama::Template;
+
+#[derive(Template)]
+#[template(path = "posts.html")]
+pub struct PostsView<P: Post> {
+ posts: Vec<P>,
+}
+
+impl<P: Post> PostsView<P> {
+ pub fn with_posts(posts: impl IntoIterator<Item = P>) -> Self {
+ Self {
+ posts: posts.into_iter().collect(),
+ }
+ }
+}