feat: implement merge readiness plan to close gaps between v2 and v1
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 5m8s
test / unit (pull_request) Successful in 16m18s
test / integration (pull_request) Failing after 16m59s
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 5m8s
test / unit (pull_request) Successful in 16m18s
test / integration (pull_request) Failing after 16m59s
- Task 1: Fix feed response hydration by adding `to_thought_response` helper and updating feed handlers to return full `ThoughtResponse`. - Task 2: Wire follower/following REST routes for user feeds. - Task 3: Add user listing and count endpoints, including `GET /users` and `GET /users/count`. - Task 4: Implement popular tags feature with `GET /tags/popular`. - Task 5: Enhance configuration with HOST, CORS_ORIGINS, and optional rate limiting using tower-governor.
This commit is contained in:
@@ -22,7 +22,10 @@ impl PgActivityPubRepository {
|
||||
|
||||
#[async_trait]
|
||||
impl ActivityPubRepository for PgActivityPubRepository {
|
||||
async fn outbox_entries_for_actor(&self, user_id: &UserId) -> Result<Vec<OutboxEntry>, DomainError> {
|
||||
async fn outbox_entries_for_actor(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
) -> Result<Vec<OutboxEntry>, DomainError> {
|
||||
#[derive(sqlx::FromRow)]
|
||||
struct Row {
|
||||
id: uuid::Uuid,
|
||||
@@ -134,7 +137,10 @@ impl ActivityPubRepository for PgActivityPubRepository {
|
||||
.collect())
|
||||
}
|
||||
|
||||
async fn find_remote_actor_id(&self, actor_ap_url: &Url) -> Result<Option<UserId>, DomainError> {
|
||||
async fn find_remote_actor_id(
|
||||
&self,
|
||||
actor_ap_url: &Url,
|
||||
) -> Result<Option<UserId>, DomainError> {
|
||||
sqlx::query_scalar::<_, uuid::Uuid>("SELECT id FROM users WHERE ap_id=$1")
|
||||
.bind(actor_ap_url.as_str())
|
||||
.fetch_optional(&self.pool)
|
||||
@@ -148,7 +154,10 @@ impl ActivityPubRepository for PgActivityPubRepository {
|
||||
return Ok(id);
|
||||
}
|
||||
let new_id = uuid::Uuid::new_v4();
|
||||
let handle = actor_ap_url.path().trim_start_matches('/').replace('/', "_");
|
||||
let handle = actor_ap_url
|
||||
.path()
|
||||
.trim_start_matches('/')
|
||||
.replace('/', "_");
|
||||
sqlx::query(
|
||||
"INSERT INTO users(id,username,email,password_hash,local,ap_id,created_at,updated_at)
|
||||
VALUES($1,$2,$3,'',false,$4,NOW(),NOW()) ON CONFLICT(ap_id) DO NOTHING",
|
||||
@@ -163,7 +172,11 @@ impl ActivityPubRepository for PgActivityPubRepository {
|
||||
// Re-fetch to get whichever id won the race
|
||||
self.find_remote_actor_id(actor_ap_url)
|
||||
.await?
|
||||
.ok_or_else(|| DomainError::Internal("intern_remote_actor: insert succeeded but row not found".into()))
|
||||
.ok_or_else(|| {
|
||||
DomainError::Internal(
|
||||
"intern_remote_actor: insert succeeded but row not found".into(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
async fn accept_note(
|
||||
@@ -195,13 +208,15 @@ impl ActivityPubRepository for PgActivityPubRepository {
|
||||
|
||||
async fn apply_note_update(&self, ap_id: &Url, new_content: &str) -> Result<(), DomainError> {
|
||||
let capped: String = new_content.chars().take(500).collect();
|
||||
sqlx::query("UPDATE thoughts SET content=$2,updated_at=NOW() WHERE ap_id=$1 AND local=false")
|
||||
.bind(ap_id.as_str())
|
||||
.bind(&capped)
|
||||
.execute(&self.pool)
|
||||
.await
|
||||
.map_err(|e| DomainError::Internal(e.to_string()))
|
||||
.map(|_| ())
|
||||
sqlx::query(
|
||||
"UPDATE thoughts SET content=$2,updated_at=NOW() WHERE ap_id=$1 AND local=false",
|
||||
)
|
||||
.bind(ap_id.as_str())
|
||||
.bind(&capped)
|
||||
.execute(&self.pool)
|
||||
.await
|
||||
.map_err(|e| DomainError::Internal(e.to_string()))
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
async fn retract_note(&self, ap_id: &Url) -> Result<(), DomainError> {
|
||||
@@ -253,9 +268,16 @@ mod tests {
|
||||
let actor_url = url::Url::parse("https://remote.example/users/bob").unwrap();
|
||||
let ap_id = url::Url::parse("https://remote.example/notes/1").unwrap();
|
||||
let author = repo.intern_remote_actor(&actor_url).await.unwrap();
|
||||
repo.accept_note(&ap_id, &author, "hello from remote", chrono::Utc::now(), false, None)
|
||||
.await
|
||||
.unwrap();
|
||||
repo.accept_note(
|
||||
&ap_id,
|
||||
&author,
|
||||
"hello from remote",
|
||||
chrono::Utc::now(),
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
repo.retract_note(&ap_id).await.unwrap();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user