Upload files to "src"

This commit is contained in:
mhn
2025-12-05 11:20:09 +00:00
parent 272587eeda
commit ea0b9ee927
3 changed files with 166 additions and 0 deletions

65
src/handlers.rs Normal file
View File

@@ -0,0 +1,65 @@
use axum::{
extract::{Path, State},
http::StatusCode,
response::Json,
};
use uuid::Uuid;
use chrono::Utc;
use crate::model::{Entry, AppState};
pub async fn list_entries(State(state): State<AppState>) -> Json<Vec<Entry>> {
let entries = state.entries.lock().unwrap();
let mut sorted = entries.clone();
// Sort: Pinned/Daily first, then by date
sorted.sort_by(|a, b| b.created_at.cmp(&a.created_at));
Json(sorted)
}
pub async fn create_entry(
State(state): State<AppState>,
Json(mut payload): Json<Entry>,
) -> Json<Entry> {
if payload.id == Uuid::nil() { payload.id = Uuid::new_v4(); }
payload.created_at = Utc::now();
payload.status = "Active".to_string();
{
let mut entries = state.entries.lock().unwrap();
entries.push(payload.clone());
}
state.save();
Json(payload)
}
pub async fn update_entry(
Path(id): Path<Uuid>,
State(state): State<AppState>,
Json(payload): Json<Entry>,
) -> StatusCode {
let mut entries = state.entries.lock().unwrap();
if let Some(entry) = entries.iter_mut().find(|e| e.id == id) {
entry.title = payload.title;
entry.description = payload.description;
entry.tags = payload.tags;
entry.frequency = payload.frequency;
entry.details = payload.details;
entry.event_date = payload.event_date;
entry.updated_at = Some(Utc::now());
drop(entries);
state.save();
StatusCode::OK
} else {
StatusCode::NOT_FOUND
}
}
pub async fn delete_entry(
Path(id): Path<Uuid>,
State(state): State<AppState>,
) -> StatusCode {
let mut entries = state.entries.lock().unwrap();
entries.retain(|e| e.id != id);
drop(entries);
state.save();
StatusCode::NO_CONTENT
}

30
src/main.rs Normal file
View File

@@ -0,0 +1,30 @@
mod handlers;
mod model;
use axum::{
routing::{get, put, delete}, // post is implied in route chaining
Router,
};
use std::net::SocketAddr;
use tower_http::{services::ServeDir, trace::TraceLayer};
use model::AppState;
#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();
let state = AppState::new("data.json");
let app = Router::new()
.route("/api/entries", get(handlers::list_entries).post(handlers::create_entry))
.route("/api/entries/:id", put(handlers::update_entry).delete(handlers::delete_entry))
.nest_service("/", ServeDir::new("static"))
.with_state(state)
.layer(TraceLayer::new_for_http());
let addr = SocketAddr::from(([127, 0, 0, 1], 3030));
println!("Life Manager running at http://{}", addr);
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}

71
src/model.rs Normal file
View File

@@ -0,0 +1,71 @@
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
use uuid::Uuid;
use serde_json::Value;
use chrono::{DateTime, Utc};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Entry {
#[serde(default = "Uuid::new_v4")]
pub id: Uuid,
pub template_type: String,
pub title: String,
#[serde(default)]
pub description: String,
#[serde(default)]
pub tags: Vec<String>,
pub frequency: Option<String>,
#[serde(default = "default_status")]
pub status: String,
// NEW FIELD: Holds specific appointment times
#[serde(default)]
pub event_date: Option<DateTime<Utc>>,
pub details: Value,
#[serde(default = "Utc::now")]
pub created_at: DateTime<Utc>,
pub updated_at: Option<DateTime<Utc>>,
}
// Helper function for the default value
fn default_status() -> String {
"Active".to_string()
}
#[derive(Clone)]
pub struct AppState {
pub entries: Arc<Mutex<Vec<Entry>>>,
pub file_path: String,
}
impl AppState {
pub fn new(file_path: &str) -> Self {
// Try to read file, otherwise create empty list
let entries = match std::fs::read_to_string(file_path) {
Ok(content) => serde_json::from_str(&content).unwrap_or_default(),
Err(_) => Vec::new(),
};
Self {
entries: Arc::new(Mutex::new(entries)),
file_path: file_path.to_string(),
}
}
pub fn save(&self) {
let entries = self.entries.lock().unwrap();
let content = serde_json::to_string_pretty(&*entries).unwrap();
// Added error printing so you can see if file permissions are wrong
if let Err(e) = std::fs::write(&self.file_path, content) {
eprintln!("CRITICAL ERROR: Could not save data.json: {}", e);
} else {
println!("Database saved to {}", self.file_path);
}
}
}