Refactor handlers and OpenAPI documentation for improved readability and consistency
Some checks failed
lint / lint (push) Has been cancelled
test / unit (push) Has been cancelled
test / integration (push) Has been cancelled
lint / lint (pull_request) Failing after 6m49s
test / unit (pull_request) Successful in 16m24s
test / integration (pull_request) Failing after 17m7s
Some checks failed
lint / lint (push) Has been cancelled
test / unit (push) Has been cancelled
test / integration (push) Has been cancelled
lint / lint (pull_request) Failing after 6m49s
test / unit (pull_request) Successful in 16m24s
test / integration (pull_request) Failing after 17m7s
- Reorganized imports in health, notifications, social, thoughts, and users handlers for clarity. - Updated function signatures in handlers to improve readability by aligning parameters. - Enhanced JSON response formatting in notifications and thoughts handlers. - Improved error handling in user-related functions. - Refactored OpenAPI documentation to maintain consistent formatting and structure. - Cleaned up unnecessary code and comments across various files. - Ensured consistent use of `Arc` for shared state in AppState and WorkerHandlers.
This commit is contained in:
@@ -21,7 +21,9 @@ pub struct CreateThoughtInput {
|
||||
pub content_warning: Option<String>,
|
||||
pub sensitive: bool,
|
||||
}
|
||||
pub struct CreateThoughtOutput { pub thought: Thought }
|
||||
pub struct CreateThoughtOutput {
|
||||
pub thought: Thought,
|
||||
}
|
||||
|
||||
pub async fn create_thought(
|
||||
thoughts: &dyn ThoughtRepository,
|
||||
@@ -30,18 +32,28 @@ pub async fn create_thought(
|
||||
input: CreateThoughtInput,
|
||||
) -> Result<CreateThoughtOutput, DomainError> {
|
||||
let content = Content::new_local(input.content)?;
|
||||
let visibility = input.visibility.as_deref().map(Visibility::from_str).unwrap_or(Visibility::Public);
|
||||
let visibility = input
|
||||
.visibility
|
||||
.as_deref()
|
||||
.map(Visibility::from_str)
|
||||
.unwrap_or(Visibility::Public);
|
||||
let thought = Thought::new_local(
|
||||
ThoughtId::new(), input.user_id,
|
||||
content, input.in_reply_to_id.clone(),
|
||||
visibility, input.content_warning, input.sensitive,
|
||||
ThoughtId::new(),
|
||||
input.user_id,
|
||||
content,
|
||||
input.in_reply_to_id.clone(),
|
||||
visibility,
|
||||
input.content_warning,
|
||||
input.sensitive,
|
||||
);
|
||||
thoughts.save(&thought).await?;
|
||||
events.publish(&DomainEvent::ThoughtCreated {
|
||||
thought_id: thought.id.clone(),
|
||||
user_id: thought.user_id.clone(),
|
||||
in_reply_to_id: input.in_reply_to_id,
|
||||
}).await?;
|
||||
events
|
||||
.publish(&DomainEvent::ThoughtCreated {
|
||||
thought_id: thought.id.clone(),
|
||||
user_id: thought.user_id.clone(),
|
||||
in_reply_to_id: input.in_reply_to_id,
|
||||
})
|
||||
.await?;
|
||||
Ok(CreateThoughtOutput { thought })
|
||||
}
|
||||
|
||||
@@ -51,10 +63,18 @@ pub async fn delete_thought(
|
||||
id: &ThoughtId,
|
||||
user_id: &UserId,
|
||||
) -> Result<(), DomainError> {
|
||||
let thought = thoughts.find_by_id(id).await?.ok_or(DomainError::NotFound)?;
|
||||
let thought = thoughts
|
||||
.find_by_id(id)
|
||||
.await?
|
||||
.ok_or(DomainError::NotFound)?;
|
||||
require_owner(&thought, user_id)?;
|
||||
thoughts.delete(id, user_id).await?;
|
||||
events.publish(&DomainEvent::ThoughtDeleted { thought_id: id.clone(), user_id: user_id.clone() }).await?;
|
||||
events
|
||||
.publish(&DomainEvent::ThoughtDeleted {
|
||||
thought_id: id.clone(),
|
||||
user_id: user_id.clone(),
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -65,19 +85,33 @@ pub async fn edit_thought(
|
||||
user_id: &UserId,
|
||||
new_content: String,
|
||||
) -> Result<(), DomainError> {
|
||||
let thought = thoughts.find_by_id(id).await?.ok_or(DomainError::NotFound)?;
|
||||
let thought = thoughts
|
||||
.find_by_id(id)
|
||||
.await?
|
||||
.ok_or(DomainError::NotFound)?;
|
||||
require_owner(&thought, user_id)?;
|
||||
let content = Content::new_local(new_content)?;
|
||||
thoughts.update_content(id, &content).await?;
|
||||
events.publish(&DomainEvent::ThoughtUpdated { thought_id: id.clone(), user_id: user_id.clone() }).await?;
|
||||
events
|
||||
.publish(&DomainEvent::ThoughtUpdated {
|
||||
thought_id: id.clone(),
|
||||
user_id: user_id.clone(),
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_thought(thoughts: &dyn ThoughtRepository, id: &ThoughtId) -> Result<Thought, DomainError> {
|
||||
pub async fn get_thought(
|
||||
thoughts: &dyn ThoughtRepository,
|
||||
id: &ThoughtId,
|
||||
) -> Result<Thought, DomainError> {
|
||||
thoughts.find_by_id(id).await?.ok_or(DomainError::NotFound)
|
||||
}
|
||||
|
||||
pub async fn get_thread(thoughts: &dyn ThoughtRepository, id: &ThoughtId) -> Result<Vec<Thought>, DomainError> {
|
||||
pub async fn get_thread(
|
||||
thoughts: &dyn ThoughtRepository,
|
||||
id: &ThoughtId,
|
||||
) -> Result<Vec<Thought>, DomainError> {
|
||||
thoughts.get_thread(id).await
|
||||
}
|
||||
|
||||
@@ -91,18 +125,33 @@ mod tests {
|
||||
};
|
||||
|
||||
fn user() -> User {
|
||||
User::new_local(UserId::new(), Username::new("alice").unwrap(), Email::new("alice@ex.com").unwrap(), PasswordHash("h".into()))
|
||||
User::new_local(
|
||||
UserId::new(),
|
||||
Username::new("alice").unwrap(),
|
||||
Email::new("alice@ex.com").unwrap(),
|
||||
PasswordHash("h".into()),
|
||||
)
|
||||
}
|
||||
|
||||
fn input(uid: UserId) -> CreateThoughtInput {
|
||||
CreateThoughtInput { user_id: uid, content: "hello".into(), in_reply_to_id: None, visibility: None, content_warning: None, sensitive: false }
|
||||
CreateThoughtInput {
|
||||
user_id: uid,
|
||||
content: "hello".into(),
|
||||
in_reply_to_id: None,
|
||||
visibility: None,
|
||||
content_warning: None,
|
||||
sensitive: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn create_thought_saves_and_emits_event() {
|
||||
let store = TestStore::default();
|
||||
let u = user(); store.users.lock().unwrap().push(u.clone());
|
||||
let out = create_thought(&store, &store, &store, input(u.id.clone())).await.unwrap();
|
||||
let u = user();
|
||||
store.users.lock().unwrap().push(u.clone());
|
||||
let out = create_thought(&store, &store, &store, input(u.id.clone()))
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(out.thought.content.as_str(), "hello");
|
||||
assert_eq!(store.events.lock().unwrap().len(), 1);
|
||||
}
|
||||
@@ -110,9 +159,14 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn delete_own_thought_succeeds() {
|
||||
let store = TestStore::default();
|
||||
let u = user(); store.users.lock().unwrap().push(u.clone());
|
||||
let out = create_thought(&store, &store, &NoOpEventPublisher, input(u.id.clone())).await.unwrap();
|
||||
delete_thought(&store, &NoOpEventPublisher, &out.thought.id, &u.id).await.unwrap();
|
||||
let u = user();
|
||||
store.users.lock().unwrap().push(u.clone());
|
||||
let out = create_thought(&store, &store, &NoOpEventPublisher, input(u.id.clone()))
|
||||
.await
|
||||
.unwrap();
|
||||
delete_thought(&store, &NoOpEventPublisher, &out.thought.id, &u.id)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(store.thoughts.lock().unwrap().is_empty());
|
||||
}
|
||||
|
||||
@@ -120,10 +174,23 @@ mod tests {
|
||||
async fn delete_other_thought_returns_not_found() {
|
||||
let store = TestStore::default();
|
||||
let alice = user();
|
||||
let bob = User::new_local(UserId::new(), Username::new("bob").unwrap(), Email::new("bob@ex.com").unwrap(), PasswordHash("h".into()));
|
||||
store.users.lock().unwrap().extend([alice.clone(), bob.clone()]);
|
||||
let out = create_thought(&store, &store, &NoOpEventPublisher, input(alice.id.clone())).await.unwrap();
|
||||
let err = delete_thought(&store, &NoOpEventPublisher, &out.thought.id, &bob.id).await.unwrap_err();
|
||||
let bob = User::new_local(
|
||||
UserId::new(),
|
||||
Username::new("bob").unwrap(),
|
||||
Email::new("bob@ex.com").unwrap(),
|
||||
PasswordHash("h".into()),
|
||||
);
|
||||
store
|
||||
.users
|
||||
.lock()
|
||||
.unwrap()
|
||||
.extend([alice.clone(), bob.clone()]);
|
||||
let out = create_thought(&store, &store, &NoOpEventPublisher, input(alice.id.clone()))
|
||||
.await
|
||||
.unwrap();
|
||||
let err = delete_thought(&store, &NoOpEventPublisher, &out.thought.id, &bob.id)
|
||||
.await
|
||||
.unwrap_err();
|
||||
assert!(matches!(err, DomainError::NotFound));
|
||||
}
|
||||
|
||||
@@ -132,16 +199,29 @@ mod tests {
|
||||
let store = TestStore::default();
|
||||
let alice = user();
|
||||
store.users.lock().unwrap().push(alice.clone());
|
||||
let out = create_thought(&store, &store, &store, input(alice.id.clone())).await.unwrap();
|
||||
let out = create_thought(&store, &store, &store, input(alice.id.clone()))
|
||||
.await
|
||||
.unwrap();
|
||||
let tid = out.thought.id.clone();
|
||||
|
||||
edit_thought(&store, &store, &tid, &alice.id, "updated".to_string()).await.unwrap();
|
||||
edit_thought(&store, &store, &tid, &alice.id, "updated".to_string())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let saved = store.thoughts.lock().unwrap().iter().find(|t| t.id == tid).unwrap().clone();
|
||||
let saved = store
|
||||
.thoughts
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|t| t.id == tid)
|
||||
.unwrap()
|
||||
.clone();
|
||||
assert_eq!(saved.content.as_str(), "updated");
|
||||
|
||||
let events = store.events.lock().unwrap();
|
||||
assert!(events.iter().any(|e| matches!(e, DomainEvent::ThoughtUpdated { thought_id, .. } if thought_id == &tid)));
|
||||
assert!(events.iter().any(
|
||||
|e| matches!(e, DomainEvent::ThoughtUpdated { thought_id, .. } if thought_id == &tid)
|
||||
));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -149,19 +229,32 @@ mod tests {
|
||||
let store = TestStore::default();
|
||||
let alice = user();
|
||||
store.users.lock().unwrap().push(alice.clone());
|
||||
let original = create_thought(&store, &store, &NoOpEventPublisher, input(alice.id.clone())).await.unwrap().thought;
|
||||
let original = create_thought(&store, &store, &NoOpEventPublisher, input(alice.id.clone()))
|
||||
.await
|
||||
.unwrap()
|
||||
.thought;
|
||||
|
||||
create_thought(&store, &store, &NoOpEventPublisher, CreateThoughtInput {
|
||||
user_id: alice.id.clone(),
|
||||
content: "reply".into(),
|
||||
in_reply_to_id: Some(original.id.clone()),
|
||||
visibility: None,
|
||||
content_warning: None,
|
||||
sensitive: false,
|
||||
}).await.unwrap();
|
||||
create_thought(
|
||||
&store,
|
||||
&store,
|
||||
&NoOpEventPublisher,
|
||||
CreateThoughtInput {
|
||||
user_id: alice.id.clone(),
|
||||
content: "reply".into(),
|
||||
in_reply_to_id: Some(original.id.clone()),
|
||||
visibility: None,
|
||||
content_warning: None,
|
||||
sensitive: false,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let thoughts = store.thoughts.lock().unwrap();
|
||||
let reply = thoughts.iter().find(|t| t.content.as_str() == "reply").unwrap();
|
||||
let reply = thoughts
|
||||
.iter()
|
||||
.find(|t| t.content.as_str() == "reply")
|
||||
.unwrap();
|
||||
assert_eq!(reply.in_reply_to_id, Some(original.id.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user