mirror of
https://git.alemi.dev/guestbook.rs.git
synced 2024-12-19 02:54:52 +01:00
feat: richer guest page rows
This commit is contained in:
parent
e21be6b917
commit
4943339964
4 changed files with 34 additions and 23 deletions
13
src/model.rs
13
src/model.rs
|
@ -1,7 +1,18 @@
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
pub struct Suggestion {
|
pub struct GuestBookPage {
|
||||||
|
pub author: Option<String>,
|
||||||
|
pub contact: Option<String>,
|
||||||
|
pub body: String,
|
||||||
|
pub date: DateTime<Utc>,
|
||||||
|
pub avatar: String,
|
||||||
|
pub url: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
|
pub struct Insertion {
|
||||||
pub author: Option<String>,
|
pub author: Option<String>,
|
||||||
pub contact: Option<String>,
|
pub contact: Option<String>,
|
||||||
pub body: String,
|
pub body: String,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::model::Suggestion;
|
use crate::model::GuestBookPage;
|
||||||
|
|
||||||
use super::NotificationProcessor;
|
use super::NotificationProcessor;
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@ use super::NotificationProcessor;
|
||||||
pub struct ConsoleTracingNotifier {}
|
pub struct ConsoleTracingNotifier {}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl NotificationProcessor<Suggestion> for ConsoleTracingNotifier {
|
impl NotificationProcessor<GuestBookPage> for ConsoleTracingNotifier {
|
||||||
async fn process(&self, suggestion: &Suggestion) {
|
async fn process(&self, suggestion: &GuestBookPage) {
|
||||||
tracing::info!(" >> {:?}", suggestion);
|
tracing::info!(" >> {:?}", suggestion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@ impl NotificationProcessor<Suggestion> for ConsoleTracingNotifier {
|
||||||
pub struct ConsolePrettyNotifier {}
|
pub struct ConsolePrettyNotifier {}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl NotificationProcessor<Suggestion> for ConsolePrettyNotifier {
|
impl NotificationProcessor<GuestBookPage> for ConsolePrettyNotifier {
|
||||||
async fn process(&self, suggestion: &Suggestion) {
|
async fn process(&self, suggestion: &GuestBookPage) {
|
||||||
println!("{} -- {} <{}>", suggestion.body, suggestion.author.as_deref().unwrap_or("anon"), suggestion.contact.as_deref().unwrap_or(""));
|
println!("{} -- {} <{}>", suggestion.body, suggestion.author.as_deref().unwrap_or("anon"), suggestion.contact.as_deref().unwrap_or(""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||||
use axum::{http::StatusCode, Json, Form, Router, routing::{put, post, get}, extract::{State, Query}, response::IntoResponse};
|
use axum::{http::StatusCode, Json, Form, Router, routing::{put, post, get}, extract::{State, Query}, response::IntoResponse};
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
use crate::{notifications::NotificationProcessor, model::{Suggestion, Acknowledgement, PageOptions}, storage::StorageStrategy};
|
use crate::{notifications::NotificationProcessor, model::{GuestBookPage, Acknowledgement, PageOptions, Insertion}, storage::StorageStrategy};
|
||||||
|
|
||||||
pub fn create_router_with_app_routes(state: Context) -> Router {
|
pub fn create_router_with_app_routes(state: Context) -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
|
@ -16,21 +16,21 @@ pub fn create_router_with_app_routes(state: Context) -> Router {
|
||||||
type SafeContext = Arc<RwLock<Context>>;
|
type SafeContext = Arc<RwLock<Context>>;
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
providers: Vec<Box<dyn NotificationProcessor<Suggestion>>>,
|
providers: Vec<Box<dyn NotificationProcessor<GuestBookPage>>>,
|
||||||
storage: Box<dyn StorageStrategy<Suggestion>>,
|
storage: Box<dyn StorageStrategy<GuestBookPage>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub fn new(storage: Box<dyn StorageStrategy<Suggestion>>) -> Self {
|
pub fn new(storage: Box<dyn StorageStrategy<GuestBookPage>>) -> Self {
|
||||||
Context { providers: Vec::new(), storage }
|
Context { providers: Vec::new(), storage }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register(mut self, notifier: Box<dyn NotificationProcessor<Suggestion>>) -> Self {
|
pub fn register(mut self, notifier: Box<dyn NotificationProcessor<GuestBookPage>>) -> Self {
|
||||||
self.providers.push(notifier);
|
self.providers.push(notifier);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process(&self, x: &Suggestion) {
|
async fn process(&self, x: &GuestBookPage) {
|
||||||
for p in self.providers.iter() {
|
for p in self.providers.iter() {
|
||||||
p.process(x).await;
|
p.process(x).await;
|
||||||
}
|
}
|
||||||
|
@ -39,18 +39,18 @@ impl Context {
|
||||||
|
|
||||||
async fn send_suggestion(payload: Suggestion, state: SafeContext) -> impl IntoResponse {
|
async fn send_suggestion(payload: Suggestion, state: SafeContext) -> impl IntoResponse {
|
||||||
let mut lock = state.write().await;
|
let mut lock = state.write().await;
|
||||||
lock.process(&payload).await;
|
lock.process(&page).await;
|
||||||
match lock.storage.archive(payload).await {
|
match lock.storage.archive(page).await {
|
||||||
Ok(()) => (StatusCode::OK, Json(Acknowledgement::Sent("".into()))),
|
Ok(()) => (StatusCode::OK, Json(Acknowledgement::Sent("".into()))),
|
||||||
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, Json(Acknowledgement::Refused(e.to_string()))),
|
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, Json(Acknowledgement::Refused(e.to_string()))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_suggestion_json(State(state): State<SafeContext>, Json(payload): Json<Suggestion>) -> impl IntoResponse { send_suggestion(payload, state).await }
|
async fn send_suggestion_json(State(state): State<SafeContext>, Json(payload): Json<Insertion>) -> impl IntoResponse { send_suggestion(payload, state).await }
|
||||||
async fn send_suggestion_form(State(state): State<SafeContext>, Form(payload): Form<Suggestion>) -> impl IntoResponse { send_suggestion(payload, state).await }
|
async fn send_suggestion_form(State(state): State<SafeContext>, Form(payload): Form<Insertion>) -> impl IntoResponse { send_suggestion(payload, state).await }
|
||||||
|
|
||||||
|
|
||||||
async fn get_suggestion(State(state): State<SafeContext>, Query(page): Query<PageOptions>) -> Result<Json<Vec<Suggestion>>, String> {
|
async fn get_suggestion(State(state): State<SafeContext>, Query(page): Query<PageOptions>) -> Result<Json<Vec<GuestBookPage>>, String> {
|
||||||
let offset = page.offset.unwrap_or(0);
|
let offset = page.offset.unwrap_or(0);
|
||||||
let limit = std::cmp::min(page.limit.unwrap_or(20), 20);
|
let limit = std::cmp::min(page.limit.unwrap_or(20), 20);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::model::Suggestion;
|
use crate::model::GuestBookPage;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
@ -30,19 +30,19 @@ impl JsonFileStorageStrategy {
|
||||||
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl StorageStrategy<Suggestion> for JsonFileStorageStrategy {
|
impl StorageStrategy<GuestBookPage> for JsonFileStorageStrategy {
|
||||||
async fn archive(&mut self, payload: Suggestion) -> Result<(), StorageStrategyError> {
|
async fn archive(&mut self, payload: GuestBookPage) -> Result<(), StorageStrategyError> {
|
||||||
let file_content = std::fs::read_to_string(&self.path)?;
|
let file_content = std::fs::read_to_string(&self.path)?;
|
||||||
let mut current_content : Vec<Suggestion> = serde_json::from_str(&file_content)?;
|
let mut current_content : Vec<GuestBookPage> = serde_json::from_str(&file_content)?;
|
||||||
current_content.push(payload);
|
current_content.push(payload);
|
||||||
let updated_content = serde_json::to_string(¤t_content)?;
|
let updated_content = serde_json::to_string(¤t_content)?;
|
||||||
std::fs::write(&self.path, updated_content)?;
|
std::fs::write(&self.path, updated_content)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn extract(&self, offset: usize, window: usize) -> Result<Vec<Suggestion>, StorageStrategyError> {
|
async fn extract(&self, offset: usize, window: usize) -> Result<Vec<GuestBookPage>, StorageStrategyError> {
|
||||||
let file_content = std::fs::read_to_string(&self.path)?;
|
let file_content = std::fs::read_to_string(&self.path)?;
|
||||||
let current_content : Vec<Suggestion> = serde_json::from_str(&file_content)?;
|
let current_content : Vec<GuestBookPage> = serde_json::from_str(&file_content)?;
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
for sugg in current_content.iter().rev().skip(offset) {
|
for sugg in current_content.iter().rev().skip(offset) {
|
||||||
out.push(sugg.clone());
|
out.push(sugg.clone());
|
||||||
|
|
Loading…
Reference in a new issue