+
Privacy Policy
diff --git a/notes-api/src/dto.rs b/notes-api/src/dto.rs
index 0e31a23..5dd4200 100644
--- a/notes-api/src/dto.rs
+++ b/notes-api/src/dto.rs
@@ -68,7 +68,7 @@ impl From for TagResponse {
fn from(tag: Tag) -> Self {
Self {
id: tag.id,
- name: tag.name,
+ name: tag.name.into_inner(), // Convert TagName to String
}
}
}
@@ -91,7 +91,7 @@ impl From for NoteResponse {
fn from(note: Note) -> Self {
Self {
id: note.id,
- title: note.title,
+ title: note.title_str().to_string(), // Convert Option to String
content: note.content,
color: note.color,
is_pinned: note.is_pinned,
@@ -160,7 +160,7 @@ impl From for NoteVersionResponse {
Self {
id: version.id,
note_id: version.note_id,
- title: version.title,
+ title: version.title.unwrap_or_default(), // Convert Option to String
content: version.content,
created_at: version.created_at,
}
diff --git a/notes-api/src/main.rs b/notes-api/src/main.rs
index dde665d..e5abb72 100644
--- a/notes-api/src/main.rs
+++ b/notes-api/src/main.rs
@@ -188,7 +188,7 @@ async fn main() -> anyhow::Result<()> {
}
async fn create_dev_user(pool: ¬es_infra::db::DatabasePool) -> anyhow::Result<()> {
- use notes_domain::User;
+ use notes_domain::{Email, User};
use notes_infra::factory::build_user_repository;
use password_auth::generate_hash;
use uuid::Uuid;
@@ -201,10 +201,12 @@ async fn create_dev_user(pool: ¬es_infra::db::DatabasePool) -> anyhow::Result
let dev_user_id = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
if user_repo.find_by_id(dev_user_id).await?.is_none() {
let hash = generate_hash("password");
+ let dev_email = Email::try_from("dev@localhost.com")
+ .map_err(|e| anyhow::anyhow!("Invalid dev email: {}", e))?;
let user = User::with_id(
dev_user_id,
"dev|local",
- "dev@localhost.com",
+ dev_email,
Some(hash),
chrono::Utc::now(),
);
diff --git a/notes-api/src/routes/auth.rs b/notes-api/src/routes/auth.rs
index 22ff697..9418805 100644
--- a/notes-api/src/routes/auth.rs
+++ b/notes-api/src/routes/auth.rs
@@ -4,7 +4,7 @@ use axum::{Json, extract::State, http::StatusCode};
use axum_login::AuthSession;
use validator::Validate;
-use notes_domain::User;
+use notes_domain::{Email, User};
use password_auth::generate_hash;
use crate::auth::{AuthBackend, AuthUser, Credentials};
@@ -43,9 +43,12 @@ pub async fn register(
// Hash password
let password_hash = generate_hash(&payload.password);
- // Create use
- // For local registration, we use email as subject
- let user = User::new_local(&payload.email, &password_hash);
+ // Parse email string to Email newtype
+ let email = Email::try_from(payload.email)
+ .map_err(|e| ApiError::validation(format!("Invalid email: {}", e)))?;
+
+ // Create user - for local registration, we use email as subject
+ let user = User::new_local(email, &password_hash);
state.user_repo.save(&user).await.map_err(ApiError::from)?;
@@ -108,7 +111,7 @@ pub async fn me(
Ok(Json(crate::dto::UserResponse {
id: user.0.id,
- email: user.0.email.clone(),
+ email: user.0.email_str().to_string(), // Convert Email to String
created_at: user.0.created_at,
}))
}
diff --git a/notes-api/src/routes/notes.rs b/notes-api/src/routes/notes.rs
index 8479ebe..f6dc189 100644
--- a/notes-api/src/routes/notes.rs
+++ b/notes-api/src/routes/notes.rs
@@ -10,7 +10,10 @@ use uuid::Uuid;
use validator::Validate;
use axum_login::AuthUser;
-use notes_domain::{CreateNoteRequest as DomainCreateNote, UpdateNoteRequest as DomainUpdateNote};
+use notes_domain::{
+ CreateNoteRequest as DomainCreateNote, NoteTitle, TagName,
+ UpdateNoteRequest as DomainUpdateNote,
+};
use crate::auth::AuthBackend;
use crate::dto::{CreateNoteRequest, ListNotesQuery, NoteResponse, SearchQuery, UpdateNoteRequest};
@@ -71,11 +74,30 @@ pub async fn create_note(
.validate()
.map_err(|e| ApiError::validation(e.to_string()))?;
+ // Parse title into NoteTitle (optional - empty string becomes None)
+ let title: Option = if payload.title.trim().is_empty() {
+ None
+ } else {
+ Some(
+ NoteTitle::try_from(payload.title)
+ .map_err(|e| ApiError::validation(format!("Invalid title: {}", e)))?,
+ )
+ };
+
+ // Parse tags into TagName values
+ let tags: Vec = payload
+ .tags
+ .into_iter()
+ .map(|s| {
+ TagName::try_from(s).map_err(|e| ApiError::validation(format!("Invalid tag: {}", e)))
+ })
+ .collect::, _>>()?;
+
let domain_req = DomainCreateNote {
user_id,
- title: payload.title,
+ title,
content: payload.content,
- tags: payload.tags,
+ tags,
color: payload.color,
is_pinned: payload.is_pinned,
};
@@ -126,15 +148,40 @@ pub async fn update_note(
.validate()
.map_err(|e| ApiError::validation(e.to_string()))?;
+ // Parse optional title - Some(string) -> Some(Some(NoteTitle)) or Some(None) for empty
+ let title: Option