Add "aliases" column to actor profile table

It is used to store unverified aliases,
and potentially can be used for verified aliases too.
This commit is contained in:
silverpill 2023-03-16 22:33:33 +00:00
parent c80bfccd6a
commit b56e11e81d
8 changed files with 65 additions and 5 deletions

View file

@ -0,0 +1 @@
ALTER TABLE actor_profile ADD COLUMN aliases JSONB NOT NULL DEFAULT '[]';

View file

@ -30,6 +30,7 @@ CREATE TABLE actor_profile (
identity_proofs JSONB NOT NULL DEFAULT '[]', identity_proofs JSONB NOT NULL DEFAULT '[]',
payment_options JSONB NOT NULL DEFAULT '[]', payment_options JSONB NOT NULL DEFAULT '[]',
extra_fields JSONB NOT NULL DEFAULT '[]', extra_fields JSONB NOT NULL DEFAULT '[]',
aliases JSONB NOT NULL DEFAULT '[]',
follower_count INTEGER NOT NULL CHECK (follower_count >= 0) DEFAULT 0, follower_count INTEGER NOT NULL CHECK (follower_count >= 0) DEFAULT 0,
following_count INTEGER NOT NULL CHECK (following_count >= 0) DEFAULT 0, following_count INTEGER NOT NULL CHECK (following_count >= 0) DEFAULT 0,
subscriber_count INTEGER NOT NULL CHECK (subscriber_count >= 0) DEFAULT 0, subscriber_count INTEGER NOT NULL CHECK (subscriber_count >= 0) DEFAULT 0,

View file

@ -8,7 +8,7 @@ use crate::activitypub::{
actors::types::Actor, actors::types::Actor,
fetcher::fetchers::fetch_file, fetcher::fetchers::fetch_file,
handlers::create::handle_emoji, handlers::create::handle_emoji,
receiver::HandlerError, receiver::{parse_array, HandlerError},
vocabulary::{EMOJI, HASHTAG}, vocabulary::{EMOJI, HASHTAG},
}; };
use crate::database::DatabaseClient; use crate::database::DatabaseClient;
@ -83,6 +83,21 @@ async fn fetch_actor_images(
(maybe_avatar, maybe_banner) (maybe_avatar, maybe_banner)
} }
fn parse_aliases(actor: &Actor) -> Vec<String> {
// Aliases reported by server (not signed)
actor.also_known_as.as_ref()
.and_then(|value| {
match parse_array(value) {
Ok(array) => Some(array),
Err(_) => {
log::warn!("invalid alias list: {}", value);
None
},
}
})
.unwrap_or_default()
}
async fn parse_tags( async fn parse_tags(
db_client: &impl DatabaseClient, db_client: &impl DatabaseClient,
instance: &Instance, instance: &Instance,
@ -136,6 +151,7 @@ pub async fn create_remote_profile(
).await; ).await;
let (identity_proofs, payment_options, extra_fields) = let (identity_proofs, payment_options, extra_fields) =
actor.parse_attachments(); actor.parse_attachments();
let aliases = parse_aliases(&actor);
let emojis = parse_tags( let emojis = parse_tags(
db_client, db_client,
instance, instance,
@ -153,6 +169,7 @@ pub async fn create_remote_profile(
identity_proofs, identity_proofs,
payment_options, payment_options,
extra_fields, extra_fields,
aliases,
emojis, emojis,
actor_json: Some(actor), actor_json: Some(actor),
}; };
@ -193,6 +210,7 @@ pub async fn update_remote_profile(
).await; ).await;
let (identity_proofs, payment_options, extra_fields) = let (identity_proofs, payment_options, extra_fields) =
actor.parse_attachments(); actor.parse_attachments();
let aliases = parse_aliases(&actor);
let emojis = parse_tags( let emojis = parse_tags(
db_client, db_client,
instance, instance,
@ -209,6 +227,7 @@ pub async fn update_remote_profile(
identity_proofs, identity_proofs,
payment_options, payment_options,
extra_fields, extra_fields,
aliases,
emojis, emojis,
actor_json: Some(actor), actor_json: Some(actor),
}; };

View file

@ -74,12 +74,13 @@ pub async fn handle_move(
let new_actor = new_profile.actor_json.as_ref() let new_actor = new_profile.actor_json.as_ref()
.expect("target should be a remote actor"); .expect("target should be a remote actor");
// Find aliases by DIDs // Find aliases by DIDs (signed)
let mut aliases = find_aliases(db_client, &new_profile).await? let mut aliases = find_aliases(db_client, &new_profile).await?
.into_iter() .into_iter()
.map(|profile| profile.actor_id(&instance.url())) .map(|profile| profile.actor_id(&instance.url()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// Read aliases from alsoKnownAs property // Read aliases from alsoKnownAs property
// TODO: use new_profile.aliases.into_actor_ids()
if let Some(ref value) = new_actor.also_known_as { if let Some(ref value) = new_actor.also_known_as {
let also_known_as = parse_array(value) let also_known_as = parse_array(value)
.map_err(|_| ValidationError("invalid alias list"))?; .map_err(|_| ValidationError("invalid alias list"))?;

View file

@ -372,6 +372,7 @@ impl AccountUpdateData {
identity_proofs, identity_proofs,
payment_options, payment_options,
extra_fields, extra_fields,
aliases: vec![],
emojis: vec![], emojis: vec![],
actor_json: None, // always None for local profiles actor_json: None, // always None for local profiles
}; };

View file

@ -25,6 +25,7 @@ use crate::models::{
relationships::types::RelationshipType, relationships::types::RelationshipType,
}; };
use super::types::{ use super::types::{
Aliases,
DbActorProfile, DbActorProfile,
ExtraFields, ExtraFields,
IdentityProofs, IdentityProofs,
@ -145,9 +146,10 @@ pub async fn create_profile(
identity_proofs, identity_proofs,
payment_options, payment_options,
extra_fields, extra_fields,
aliases,
actor_json actor_json
) )
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
RETURNING actor_profile RETURNING actor_profile
", ",
&[ &[
@ -163,6 +165,7 @@ pub async fn create_profile(
&IdentityProofs(profile_data.identity_proofs), &IdentityProofs(profile_data.identity_proofs),
&PaymentOptions(profile_data.payment_options), &PaymentOptions(profile_data.payment_options),
&ExtraFields(profile_data.extra_fields), &ExtraFields(profile_data.extra_fields),
&Aliases::new(profile_data.aliases),
&profile_data.actor_json, &profile_data.actor_json,
], ],
).await.map_err(catch_unique_violation("profile"))?; ).await.map_err(catch_unique_violation("profile"))?;
@ -198,9 +201,10 @@ pub async fn update_profile(
identity_proofs = $7, identity_proofs = $7,
payment_options = $8, payment_options = $8,
extra_fields = $9, extra_fields = $9,
actor_json = $10, aliases = $10,
actor_json = $11,
updated_at = CURRENT_TIMESTAMP updated_at = CURRENT_TIMESTAMP
WHERE id = $11 WHERE id = $12
RETURNING actor_profile RETURNING actor_profile
", ",
&[ &[
@ -213,6 +217,7 @@ pub async fn update_profile(
&IdentityProofs(profile_data.identity_proofs), &IdentityProofs(profile_data.identity_proofs),
&PaymentOptions(profile_data.payment_options), &PaymentOptions(profile_data.payment_options),
&ExtraFields(profile_data.extra_fields), &ExtraFields(profile_data.extra_fields),
&Aliases::new(profile_data.aliases),
&profile_data.actor_json, &profile_data.actor_json,
&profile_id, &profile_id,
], ],

View file

@ -307,6 +307,32 @@ impl ExtraFields {
json_from_sql!(ExtraFields); json_from_sql!(ExtraFields);
json_to_sql!(ExtraFields); json_to_sql!(ExtraFields);
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Alias {
pub id: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Aliases(Vec<Alias>);
impl Aliases {
pub fn new(actor_ids: Vec<String>) -> Self {
// Not signed
let aliases = actor_ids.into_iter()
.map(|actor_id| Alias { id: actor_id })
.collect();
Self(aliases)
}
pub fn into_actor_ids(self) -> Vec<String> {
let Self(aliases) = self;
aliases.into_iter().map(|alias| alias.id).collect()
}
}
json_from_sql!(Aliases);
json_to_sql!(Aliases);
#[derive(Clone, Deserialize)] #[derive(Clone, Deserialize)]
pub struct ProfileEmojis(Vec<DbEmoji>); pub struct ProfileEmojis(Vec<DbEmoji>);
@ -337,6 +363,7 @@ pub struct DbActorProfile {
pub identity_proofs: IdentityProofs, pub identity_proofs: IdentityProofs,
pub payment_options: PaymentOptions, pub payment_options: PaymentOptions,
pub extra_fields: ExtraFields, pub extra_fields: ExtraFields,
pub aliases: Aliases,
pub follower_count: i32, pub follower_count: i32,
pub following_count: i32, pub following_count: i32,
pub subscriber_count: i32, pub subscriber_count: i32,
@ -426,6 +453,7 @@ impl Default for DbActorProfile {
identity_proofs: IdentityProofs(vec![]), identity_proofs: IdentityProofs(vec![]),
payment_options: PaymentOptions(vec![]), payment_options: PaymentOptions(vec![]),
extra_fields: ExtraFields(vec![]), extra_fields: ExtraFields(vec![]),
aliases: Aliases(vec![]),
follower_count: 0, follower_count: 0,
following_count: 0, following_count: 0,
subscriber_count: 0, subscriber_count: 0,
@ -452,6 +480,7 @@ pub struct ProfileCreateData {
pub identity_proofs: Vec<IdentityProof>, pub identity_proofs: Vec<IdentityProof>,
pub payment_options: Vec<PaymentOption>, pub payment_options: Vec<PaymentOption>,
pub extra_fields: Vec<ExtraField>, pub extra_fields: Vec<ExtraField>,
pub aliases: Vec<String>,
pub emojis: Vec<Uuid>, pub emojis: Vec<Uuid>,
pub actor_json: Option<Actor>, pub actor_json: Option<Actor>,
} }
@ -485,6 +514,7 @@ pub struct ProfileUpdateData {
pub identity_proofs: Vec<IdentityProof>, pub identity_proofs: Vec<IdentityProof>,
pub payment_options: Vec<PaymentOption>, pub payment_options: Vec<PaymentOption>,
pub extra_fields: Vec<ExtraField>, pub extra_fields: Vec<ExtraField>,
pub aliases: Vec<String>,
pub emojis: Vec<Uuid>, pub emojis: Vec<Uuid>,
pub actor_json: Option<Actor>, pub actor_json: Option<Actor>,
} }
@ -534,6 +564,7 @@ impl From<&DbActorProfile> for ProfileUpdateData {
identity_proofs: profile.identity_proofs.into_inner(), identity_proofs: profile.identity_proofs.into_inner(),
payment_options: profile.payment_options.into_inner(), payment_options: profile.payment_options.into_inner(),
extra_fields: profile.extra_fields.into_inner(), extra_fields: profile.extra_fields.into_inner(),
aliases: profile.aliases.into_actor_ids(),
emojis: profile.emojis.into_inner().into_iter() emojis: profile.emojis.into_inner().into_iter()
.map(|emoji| emoji.id) .map(|emoji| emoji.id)
.collect(), .collect(),

View file

@ -118,6 +118,7 @@ pub async fn create_user(
identity_proofs: vec![], identity_proofs: vec![],
payment_options: vec![], payment_options: vec![],
extra_fields: vec![], extra_fields: vec![],
aliases: vec![],
emojis: vec![], emojis: vec![],
actor_json: None, actor_json: None,
}; };