This commit is contained in:
2025-12-23 02:15:25 +01:00
commit 39b28c7f3b
120 changed files with 15045 additions and 0 deletions

View File

@@ -0,0 +1,179 @@
//! Note route handlers
use axum::{
Json,
extract::{Path, Query, State},
http::StatusCode,
};
use axum_login::AuthSession;
use uuid::Uuid;
use validator::Validate;
use axum_login::AuthUser;
use notes_domain::{
CreateNoteRequest as DomainCreateNote, NoteService, UpdateNoteRequest as DomainUpdateNote,
};
use crate::auth::AuthBackend;
use crate::dto::{CreateNoteRequest, ListNotesQuery, NoteResponse, SearchQuery, UpdateNoteRequest};
use crate::error::{ApiError, ApiResult};
use crate::state::AppState;
/// List notes with optional filtering
/// GET /api/v1/notes
pub async fn list_notes(
State(state): State<AppState>,
auth: AuthSession<AuthBackend>,
Query(query): Query<ListNotesQuery>,
) -> ApiResult<Json<Vec<NoteResponse>>> {
let user = auth
.user
.ok_or(ApiError::Domain(notes_domain::DomainError::Unauthorized(
"Login required".to_string(),
)))?;
let user_id = user.id();
let service = NoteService::new(state.note_repo, state.tag_repo);
let notes = service.list_notes(user_id, query.into()).await?;
let response: Vec<NoteResponse> = notes.into_iter().map(NoteResponse::from).collect();
Ok(Json(response))
}
/// Create a new note
/// POST /api/v1/notes
pub async fn create_note(
State(state): State<AppState>,
auth: AuthSession<AuthBackend>,
Json(payload): Json<CreateNoteRequest>,
) -> ApiResult<(StatusCode, Json<NoteResponse>)> {
let user = auth
.user
.ok_or(ApiError::Domain(notes_domain::DomainError::Unauthorized(
"Login required".to_string(),
)))?;
let user_id = user.id();
// Validate input
payload
.validate()
.map_err(|e| ApiError::validation(e.to_string()))?;
let service = NoteService::new(state.note_repo, state.tag_repo);
let domain_req = DomainCreateNote {
user_id,
title: payload.title,
content: payload.content,
tags: payload.tags,
color: payload.color,
is_pinned: payload.is_pinned,
};
let note = service.create_note(domain_req).await?;
Ok((StatusCode::CREATED, Json(NoteResponse::from(note))))
}
/// Get a single note by ID
/// GET /api/v1/notes/:id
pub async fn get_note(
State(state): State<AppState>,
auth: AuthSession<AuthBackend>,
Path(id): Path<Uuid>,
) -> ApiResult<Json<NoteResponse>> {
let user = auth
.user
.ok_or(ApiError::Domain(notes_domain::DomainError::Unauthorized(
"Login required".to_string(),
)))?;
let user_id = user.id();
let service = NoteService::new(state.note_repo, state.tag_repo);
let note = service.get_note(id, user_id).await?;
Ok(Json(NoteResponse::from(note)))
}
/// Update a note
/// PATCH /api/v1/notes/:id
pub async fn update_note(
State(state): State<AppState>,
auth: AuthSession<AuthBackend>,
Path(id): Path<Uuid>,
Json(payload): Json<UpdateNoteRequest>,
) -> ApiResult<Json<NoteResponse>> {
let user = auth
.user
.ok_or(ApiError::Domain(notes_domain::DomainError::Unauthorized(
"Login required".to_string(),
)))?;
let user_id = user.id();
// Validate input
payload
.validate()
.map_err(|e| ApiError::validation(e.to_string()))?;
let service = NoteService::new(state.note_repo, state.tag_repo);
let domain_req = DomainUpdateNote {
id,
user_id,
title: payload.title,
content: payload.content,
is_pinned: payload.is_pinned,
is_archived: payload.is_archived,
color: payload.color,
tags: payload.tags,
};
let note = service.update_note(domain_req).await?;
Ok(Json(NoteResponse::from(note)))
}
/// Delete a note
/// DELETE /api/v1/notes/:id
pub async fn delete_note(
State(state): State<AppState>,
auth: AuthSession<AuthBackend>,
Path(id): Path<Uuid>,
) -> ApiResult<StatusCode> {
let user = auth
.user
.ok_or(ApiError::Domain(notes_domain::DomainError::Unauthorized(
"Login required".to_string(),
)))?;
let user_id = user.id();
let service = NoteService::new(state.note_repo, state.tag_repo);
service.delete_note(id, user_id).await?;
Ok(StatusCode::NO_CONTENT)
}
/// Search notes
/// GET /api/v1/search
pub async fn search_notes(
State(state): State<AppState>,
auth: AuthSession<AuthBackend>,
Query(query): Query<SearchQuery>,
) -> ApiResult<Json<Vec<NoteResponse>>> {
let user = auth
.user
.ok_or(ApiError::Domain(notes_domain::DomainError::Unauthorized(
"Login required".to_string(),
)))?;
let user_id = user.id();
let service = NoteService::new(state.note_repo, state.tag_repo);
let notes = service.search_notes(user_id, &query.q).await?;
let response: Vec<NoteResponse> = notes.into_iter().map(NoteResponse::from).collect();
Ok(Json(response))
}