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

148
notes-api/src/dto.rs Normal file
View File

@@ -0,0 +1,148 @@
//! Request and Response DTOs for notes API
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use validator::Validate;
use notes_domain::{Note, NoteFilter, Tag};
/// Request to create a new note
#[derive(Debug, Deserialize, Validate)]
pub struct CreateNoteRequest {
#[validate(length(min = 1, max = 200, message = "Title must be 1-200 characters"))]
pub title: String,
#[serde(default)]
pub content: String,
#[serde(default)]
#[validate(length(max = 10, message = "Maximum 10 tags allowed"))]
pub tags: Vec<String>,
pub color: Option<String>,
#[serde(default)]
pub is_pinned: bool,
}
/// Request to update an existing note (all fields optional)
#[derive(Debug, Deserialize, Validate)]
pub struct UpdateNoteRequest {
#[validate(length(min = 1, max = 200, message = "Title must be 1-200 characters"))]
pub title: Option<String>,
pub content: Option<String>,
#[validate(length(max = 10, message = "Maximum 10 tags allowed"))]
pub tags: Option<Vec<String>>,
pub color: Option<String>,
pub is_pinned: Option<bool>,
pub is_archived: Option<bool>,
}
/// Query parameters for listing notes
#[derive(Debug, Deserialize, Default)]
pub struct ListNotesQuery {
pub pinned: Option<bool>,
pub archived: Option<bool>,
pub tag: Option<Uuid>,
}
impl From<ListNotesQuery> for NoteFilter {
fn from(query: ListNotesQuery) -> Self {
let mut filter = NoteFilter::new();
filter.is_pinned = query.pinned;
filter.is_archived = query.archived;
filter.tag_id = query.tag;
filter
}
}
/// Query parameters for search
#[derive(Debug, Deserialize)]
pub struct SearchQuery {
pub q: String,
}
/// Tag response DTO
#[derive(Debug, Serialize)]
pub struct TagResponse {
pub id: Uuid,
pub name: String,
}
impl From<Tag> for TagResponse {
fn from(tag: Tag) -> Self {
Self {
id: tag.id,
name: tag.name,
}
}
}
/// Note response DTO
#[derive(Debug, Serialize)]
pub struct NoteResponse {
pub id: Uuid,
pub title: String,
pub content: String,
pub color: String,
pub is_pinned: bool,
pub is_archived: bool,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub tags: Vec<TagResponse>,
}
impl From<Note> for NoteResponse {
fn from(note: Note) -> Self {
Self {
id: note.id,
title: note.title,
content: note.content,
color: note.color,
is_pinned: note.is_pinned,
is_archived: note.is_archived,
created_at: note.created_at,
updated_at: note.updated_at,
tags: note.tags.into_iter().map(TagResponse::from).collect(),
}
}
}
/// Request to create a new tag
#[derive(Debug, Deserialize, Validate)]
pub struct CreateTagRequest {
#[validate(length(min = 1, max = 50, message = "Tag name must be 1-50 characters"))]
pub name: String,
}
/// Login request
#[derive(Debug, Deserialize, Validate)]
pub struct LoginRequest {
#[validate(email(message = "Invalid email format"))]
pub email: String,
#[validate(length(min = 6, message = "Password must be at least 6 characters"))]
pub password: String,
}
/// Register request
#[derive(Debug, Deserialize, Validate)]
pub struct RegisterRequest {
#[validate(email(message = "Invalid email format"))]
pub email: String,
#[validate(length(min = 6, message = "Password must be at least 6 characters"))]
pub password: String,
}
/// User response DTO
#[derive(Debug, Serialize)]
pub struct UserResponse {
pub id: Uuid,
pub email: String,
pub created_at: DateTime<Utc>,
}