Enforce uniqueness of actor ID
This commit is contained in:
parent
0715b7d64f
commit
04e851025b
6 changed files with 43 additions and 2 deletions
|
@ -23,7 +23,7 @@ Matrix chat: [#mitra:halogen.city](https://matrix.to/#/#mitra:halogen.city)
|
|||
## Requirements
|
||||
|
||||
- Rust 1.54+
|
||||
- PostgreSQL 10.2+
|
||||
- PostgreSQL 12+
|
||||
- IPFS node (optional, see [guide](./docs/ipfs.md))
|
||||
- Ethereum node (optional)
|
||||
|
||||
|
|
1
migrations/V0022__actor_profile__add_actor_id.sql
Normal file
1
migrations/V0022__actor_profile__add_actor_id.sql
Normal file
|
@ -0,0 +1 @@
|
|||
ALTER TABLE actor_profile ADD COLUMN actor_id VARCHAR(200) UNIQUE GENERATED ALWAYS AS (actor_json ->> 'id') STORED;
|
|
@ -12,6 +12,7 @@ CREATE TABLE actor_profile (
|
|||
following_count INTEGER NOT NULL CHECK (following_count >= 0) DEFAULT 0,
|
||||
post_count INTEGER NOT NULL CHECK (post_count >= 0) DEFAULT 0,
|
||||
actor_json JSONB,
|
||||
actor_id VARCHAR(200) UNIQUE GENERATED ALWAYS AS (actor_json ->> 'id') STORED,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
|
|
|
@ -572,6 +572,7 @@ mod tests {
|
|||
url: Some(parent_author_actor_url.to_string()),
|
||||
..Default::default()
|
||||
}),
|
||||
actor_id: Some(parent_author_actor_id.to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
let parent = Post {
|
||||
|
|
|
@ -116,7 +116,7 @@ pub async fn get_profile_by_actor_id(
|
|||
"
|
||||
SELECT actor_profile
|
||||
FROM actor_profile
|
||||
WHERE actor_profile.actor_json ->> 'id' = $1
|
||||
WHERE actor_id = $1
|
||||
",
|
||||
&[&actor_id],
|
||||
).await?;
|
||||
|
@ -471,6 +471,7 @@ pub async fn update_post_count(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json::json;
|
||||
use serial_test::serial;
|
||||
use crate::database::test_utils::create_test_database;
|
||||
use crate::models::profiles::queries::create_profile;
|
||||
|
@ -491,6 +492,38 @@ mod tests {
|
|||
assert_eq!(profile.username, "test");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_actor_id_unique() {
|
||||
let db_client = create_test_database().await;
|
||||
let actor_id = "https://example.com/users/test";
|
||||
let create_actor_value = |actor_id| {
|
||||
json!({
|
||||
"id": actor_id,
|
||||
"type": "Person",
|
||||
"preferredUsername": "test",
|
||||
"inbox": "https://test",
|
||||
"outbox": "https://test",
|
||||
"publicKey": {"id": "test", "owner": "test", "publicKeyPem": "test"},
|
||||
})
|
||||
};
|
||||
let profile_data_1 = ProfileCreateData {
|
||||
username: "test-1".to_string(),
|
||||
acct: "test-1@example.com".to_string(),
|
||||
actor_json: Some(create_actor_value(actor_id)),
|
||||
..Default::default()
|
||||
};
|
||||
create_profile(&db_client, profile_data_1).await.unwrap();
|
||||
let profile_data_2 = ProfileCreateData {
|
||||
username: "test-2".to_string(),
|
||||
acct: "test-2@example.com".to_string(),
|
||||
actor_json: Some(create_actor_value(actor_id)),
|
||||
..Default::default()
|
||||
};
|
||||
let error = create_profile(&db_client, profile_data_2).await.err().unwrap();
|
||||
assert_eq!(error.to_string(), "profile");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_delete_profile() {
|
||||
|
|
|
@ -86,6 +86,9 @@ pub struct DbActorProfile {
|
|||
pub post_count: i32,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub actor_json: Option<Actor>,
|
||||
|
||||
// auto-generated database fields
|
||||
pub actor_id: Option<String>,
|
||||
}
|
||||
|
||||
impl DbActorProfile {
|
||||
|
@ -94,6 +97,7 @@ impl DbActorProfile {
|
|||
}
|
||||
|
||||
pub fn actor_id(&self, instance_url: &str) -> String {
|
||||
// TODO: use actor_id field
|
||||
match self.actor_json {
|
||||
Some(ref actor) => actor.id.clone(),
|
||||
None => get_actor_url(instance_url, &self.username),
|
||||
|
@ -137,6 +141,7 @@ impl Default for DbActorProfile {
|
|||
post_count: 0,
|
||||
created_at: Utc::now(),
|
||||
actor_json: None,
|
||||
actor_id: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue