Upload files to "src"
This commit is contained in:
65
src/handlers.rs
Normal file
65
src/handlers.rs
Normal 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
30
src/main.rs
Normal 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
71
src/model.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user