Save submitted identity proofs to database
This commit is contained in:
parent
fd6b71073a
commit
8deea0c867
12 changed files with 140 additions and 19 deletions
|
@ -664,6 +664,16 @@ components:
|
||||||
description: The location of the user's profile page.
|
description: The location of the user's profile page.
|
||||||
type: string
|
type: string
|
||||||
example: https://example.com/@user
|
example: https://example.com/@user
|
||||||
|
identity_proofs:
|
||||||
|
description: Identity proofs.
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Field'
|
||||||
|
fields:
|
||||||
|
description: Additional metadata attached to a profile as name-value pairs.
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Field'
|
||||||
wallet_address:
|
wallet_address:
|
||||||
description: Ethereum wallet address.
|
description: Ethereum wallet address.
|
||||||
type: string
|
type: string
|
||||||
|
@ -685,6 +695,19 @@ components:
|
||||||
url:
|
url:
|
||||||
description: The location of the original full-size attachment.
|
description: The location of the original full-size attachment.
|
||||||
type: string
|
type: string
|
||||||
|
Field:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: The key of a given field's key-value pair.
|
||||||
|
type: string
|
||||||
|
value:
|
||||||
|
description: The value associated with the name key.
|
||||||
|
type: string
|
||||||
|
verified_at:
|
||||||
|
description: Timestamp of when the server verified the field value.
|
||||||
|
type: string
|
||||||
|
format: dateTime
|
||||||
Instance:
|
Instance:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
1
migrations/V0023__actor_profile__add_identity_proofs.sql
Normal file
1
migrations/V0023__actor_profile__add_identity_proofs.sql
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE actor_profile ADD COLUMN identity_proofs JSONB NOT NULL DEFAULT '[]';
|
|
@ -7,6 +7,7 @@ CREATE TABLE actor_profile (
|
||||||
bio_source TEXT,
|
bio_source TEXT,
|
||||||
avatar_file_name VARCHAR(100),
|
avatar_file_name VARCHAR(100),
|
||||||
banner_file_name VARCHAR(100),
|
banner_file_name VARCHAR(100),
|
||||||
|
identity_proofs JSONB NOT NULL DEFAULT '[]',
|
||||||
extra_fields JSONB NOT NULL DEFAULT '[]',
|
extra_fields 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,
|
||||||
|
|
|
@ -159,6 +159,7 @@ pub async fn fetch_profile_by_actor_id(
|
||||||
bio: actor.summary.clone(),
|
bio: actor.summary.clone(),
|
||||||
avatar,
|
avatar,
|
||||||
banner,
|
banner,
|
||||||
|
identity_proofs: vec![],
|
||||||
extra_fields,
|
extra_fields,
|
||||||
actor_json: Some(actor),
|
actor_json: Some(actor),
|
||||||
};
|
};
|
||||||
|
|
|
@ -720,6 +720,7 @@ pub async fn receive_activity(
|
||||||
bio_source: actor.summary.clone(),
|
bio_source: actor.summary.clone(),
|
||||||
avatar,
|
avatar,
|
||||||
banner,
|
banner,
|
||||||
|
identity_proofs: vec![],
|
||||||
extra_fields,
|
extra_fields,
|
||||||
actor_json: Some(actor),
|
actor_json: Some(actor),
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,9 +5,11 @@ use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::errors::ValidationError;
|
use crate::errors::ValidationError;
|
||||||
|
use crate::models::profiles::currencies::get_identity_proof_field_name;
|
||||||
use crate::models::profiles::types::{
|
use crate::models::profiles::types::{
|
||||||
DbActorProfile,
|
DbActorProfile,
|
||||||
ExtraField,
|
ExtraField,
|
||||||
|
IdentityProof,
|
||||||
ProfileUpdateData,
|
ProfileUpdateData,
|
||||||
};
|
};
|
||||||
use crate::models::profiles::validators::validate_username;
|
use crate::models::profiles::validators::validate_username;
|
||||||
|
@ -17,10 +19,12 @@ use crate::models::users::types::{
|
||||||
};
|
};
|
||||||
use crate::utils::files::{FileError, save_validated_b64_file, get_file_url};
|
use crate::utils::files::{FileError, save_validated_b64_file, get_file_url};
|
||||||
|
|
||||||
|
/// https://docs.joinmastodon.org/entities/field/
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct AccountField {
|
pub struct AccountField {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub value: String,
|
pub value: String,
|
||||||
|
verified_at: Option<DateTime<Utc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://docs.joinmastodon.org/entities/source/
|
/// https://docs.joinmastodon.org/entities/source/
|
||||||
|
@ -42,6 +46,7 @@ pub struct Account {
|
||||||
pub note: Option<String>,
|
pub note: Option<String>,
|
||||||
pub avatar: Option<String>,
|
pub avatar: Option<String>,
|
||||||
pub header: Option<String>,
|
pub header: Option<String>,
|
||||||
|
pub identity_proofs: Vec<AccountField>,
|
||||||
pub fields: Vec<AccountField>,
|
pub fields: Vec<AccountField>,
|
||||||
pub followers_count: i32,
|
pub followers_count: i32,
|
||||||
pub following_count: i32,
|
pub following_count: i32,
|
||||||
|
@ -59,9 +64,30 @@ impl Account {
|
||||||
.map(|name| get_file_url(instance_url, name));
|
.map(|name| get_file_url(instance_url, name));
|
||||||
let header_url = profile.banner_file_name.as_ref()
|
let header_url = profile.banner_file_name.as_ref()
|
||||||
.map(|name| get_file_url(instance_url, name));
|
.map(|name| get_file_url(instance_url, name));
|
||||||
let fields = profile.extra_fields.into_inner().into_iter()
|
|
||||||
.map(|field| AccountField { name: field.name, value: field.value })
|
let mut identity_proofs = vec![];
|
||||||
.collect();
|
for proof in profile.identity_proofs.into_inner() {
|
||||||
|
// Skip proof if it doesn't map to field name
|
||||||
|
if let Some(field_name) = get_identity_proof_field_name(&proof.proof_type) {
|
||||||
|
let field = AccountField {
|
||||||
|
name: field_name,
|
||||||
|
value: proof.issuer.address,
|
||||||
|
// Use current time because DID proofs are always valid
|
||||||
|
verified_at: Some(Utc::now()),
|
||||||
|
};
|
||||||
|
identity_proofs.push(field);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
let mut extra_fields = vec![];
|
||||||
|
for extra_field in profile.extra_fields.into_inner() {
|
||||||
|
let field = AccountField {
|
||||||
|
name: extra_field.name,
|
||||||
|
value: extra_field.value,
|
||||||
|
verified_at: None,
|
||||||
|
};
|
||||||
|
extra_fields.push(field);
|
||||||
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
id: profile.id,
|
id: profile.id,
|
||||||
username: profile.username,
|
username: profile.username,
|
||||||
|
@ -72,7 +98,8 @@ impl Account {
|
||||||
note: profile.bio,
|
note: profile.bio,
|
||||||
avatar: avatar_url,
|
avatar: avatar_url,
|
||||||
header: header_url,
|
header: header_url,
|
||||||
fields,
|
identity_proofs,
|
||||||
|
fields: extra_fields,
|
||||||
followers_count: profile.follower_count,
|
followers_count: profile.follower_count,
|
||||||
following_count: profile.following_count,
|
following_count: profile.following_count,
|
||||||
statuses_count: profile.post_count,
|
statuses_count: profile.post_count,
|
||||||
|
@ -87,6 +114,7 @@ impl Account {
|
||||||
.map(|field| AccountField {
|
.map(|field| AccountField {
|
||||||
name: field.name,
|
name: field.name,
|
||||||
value: field.value_source.unwrap_or(field.value),
|
value: field.value_source.unwrap_or(field.value),
|
||||||
|
verified_at: None,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let source = Source {
|
let source = Source {
|
||||||
|
@ -163,6 +191,7 @@ impl AccountUpdateData {
|
||||||
self,
|
self,
|
||||||
current_avatar: &Option<String>,
|
current_avatar: &Option<String>,
|
||||||
current_banner: &Option<String>,
|
current_banner: &Option<String>,
|
||||||
|
current_identity_proofs: &[IdentityProof],
|
||||||
media_dir: &Path,
|
media_dir: &Path,
|
||||||
) -> Result<ProfileUpdateData, FileError> {
|
) -> Result<ProfileUpdateData, FileError> {
|
||||||
let avatar = process_b64_image_field_value(
|
let avatar = process_b64_image_field_value(
|
||||||
|
@ -171,6 +200,7 @@ impl AccountUpdateData {
|
||||||
let banner = process_b64_image_field_value(
|
let banner = process_b64_image_field_value(
|
||||||
self.header, current_banner.clone(), media_dir,
|
self.header, current_banner.clone(), media_dir,
|
||||||
)?;
|
)?;
|
||||||
|
let identity_proofs = current_identity_proofs.to_vec();
|
||||||
let extra_fields = self.fields_attributes.unwrap_or(vec![]);
|
let extra_fields = self.fields_attributes.unwrap_or(vec![]);
|
||||||
let profile_data = ProfileUpdateData {
|
let profile_data = ProfileUpdateData {
|
||||||
display_name: self.display_name,
|
display_name: self.display_name,
|
||||||
|
@ -178,8 +208,9 @@ impl AccountUpdateData {
|
||||||
bio_source: self.note_source,
|
bio_source: self.note_source,
|
||||||
avatar,
|
avatar,
|
||||||
banner,
|
banner,
|
||||||
|
identity_proofs,
|
||||||
extra_fields,
|
extra_fields,
|
||||||
actor_json: None,
|
actor_json: None, // always None for local profiles
|
||||||
};
|
};
|
||||||
Ok(profile_data)
|
Ok(profile_data)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ use crate::errors::{DatabaseError, HttpError, ValidationError};
|
||||||
use crate::ethereum::eip4361::verify_eip4361_signature;
|
use crate::ethereum::eip4361::verify_eip4361_signature;
|
||||||
use crate::ethereum::gate::is_allowed_user;
|
use crate::ethereum::gate::is_allowed_user;
|
||||||
use crate::ethereum::identity::{
|
use crate::ethereum::identity::{
|
||||||
|
ETHEREUM_EIP191_PROOF,
|
||||||
DidPkh,
|
DidPkh,
|
||||||
create_identity_claim,
|
create_identity_claim,
|
||||||
verify_identity_proof,
|
verify_identity_proof,
|
||||||
|
@ -32,6 +33,7 @@ use crate::models::profiles::queries::{
|
||||||
get_wallet_address,
|
get_wallet_address,
|
||||||
update_profile,
|
update_profile,
|
||||||
};
|
};
|
||||||
|
use crate::models::profiles::types::{IdentityProof, ProfileUpdateData};
|
||||||
use crate::models::relationships::queries::{
|
use crate::models::relationships::queries::{
|
||||||
create_follow_request,
|
create_follow_request,
|
||||||
follow,
|
follow,
|
||||||
|
@ -184,6 +186,7 @@ async fn update_credentials(
|
||||||
.into_profile_data(
|
.into_profile_data(
|
||||||
¤t_user.profile.avatar_file_name,
|
¤t_user.profile.avatar_file_name,
|
||||||
¤t_user.profile.banner_file_name,
|
¤t_user.profile.banner_file_name,
|
||||||
|
¤t_user.profile.identity_proofs.into_inner(),
|
||||||
&config.media_dir(),
|
&config.media_dir(),
|
||||||
)
|
)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
|
@ -246,7 +249,7 @@ async fn create_identity_proof(
|
||||||
proof_data: web::Json<IdentityProofData>,
|
proof_data: web::Json<IdentityProofData>,
|
||||||
) -> Result<HttpResponse, HttpError> {
|
) -> Result<HttpResponse, HttpError> {
|
||||||
let db_client = &**get_database_client(&db_pool).await?;
|
let db_client = &**get_database_client(&db_pool).await?;
|
||||||
let current_user = get_current_user(db_client, auth.token()).await?;
|
let mut current_user = get_current_user(db_client, auth.token()).await?;
|
||||||
let actor_id = current_user.profile.actor_id(&config.instance_url());
|
let actor_id = current_user.profile.actor_id(&config.instance_url());
|
||||||
let wallet_address = current_user.wallet_address.as_ref()
|
let wallet_address = current_user.wallet_address.as_ref()
|
||||||
.ok_or(HttpError::PermissionError)?;
|
.ok_or(HttpError::PermissionError)?;
|
||||||
|
@ -256,6 +259,29 @@ async fn create_identity_proof(
|
||||||
&did,
|
&did,
|
||||||
&proof_data.signature,
|
&proof_data.signature,
|
||||||
)?;
|
)?;
|
||||||
|
let proof = IdentityProof {
|
||||||
|
issuer: did,
|
||||||
|
proof_type: ETHEREUM_EIP191_PROOF.to_string(),
|
||||||
|
value: proof_data.signature.clone(),
|
||||||
|
};
|
||||||
|
let mut profile_data = ProfileUpdateData::from(¤t_user.profile);
|
||||||
|
match profile_data.identity_proofs.iter_mut()
|
||||||
|
.find(|item| item.issuer == proof.issuer) {
|
||||||
|
Some(mut item) => {
|
||||||
|
// Replace
|
||||||
|
item.proof_type = proof.proof_type;
|
||||||
|
item.value = proof.value;
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
// Add new proof
|
||||||
|
profile_data.identity_proofs.push(proof);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
current_user.profile = update_profile(
|
||||||
|
db_client,
|
||||||
|
¤t_user.id,
|
||||||
|
profile_data,
|
||||||
|
).await?;
|
||||||
let account = Account::from_user(current_user, &config.instance_url());
|
let account = Account::from_user(current_user, &config.instance_url());
|
||||||
Ok(HttpResponse::Ok().json(account))
|
Ok(HttpResponse::Ok().json(account))
|
||||||
}
|
}
|
||||||
|
|
13
src/models/profiles/currencies.rs
Normal file
13
src/models/profiles/currencies.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
use crate::ethereum::identity::ETHEREUM_EIP191_PROOF;
|
||||||
|
|
||||||
|
pub fn get_currency_field_name(currency_code: &str) -> String {
|
||||||
|
format!("${}", currency_code.to_uppercase())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_identity_proof_field_name(proof_type: &str) -> Option<String> {
|
||||||
|
let field_name = match proof_type {
|
||||||
|
ETHEREUM_EIP191_PROOF => "$ETH".to_string(),
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
Some(field_name)
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod currencies;
|
||||||
pub mod queries;
|
pub mod queries;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod validators;
|
pub mod validators;
|
||||||
|
|
|
@ -10,10 +10,11 @@ use crate::models::cleanup::{
|
||||||
};
|
};
|
||||||
use crate::models::relationships::types::RelationshipType;
|
use crate::models::relationships::types::RelationshipType;
|
||||||
use crate::utils::id::new_uuid;
|
use crate::utils::id::new_uuid;
|
||||||
|
use super::currencies::get_currency_field_name;
|
||||||
use super::types::{
|
use super::types::{
|
||||||
get_currency_field_name,
|
|
||||||
ExtraFields,
|
|
||||||
DbActorProfile,
|
DbActorProfile,
|
||||||
|
ExtraFields,
|
||||||
|
IdentityProofs,
|
||||||
ProfileCreateData,
|
ProfileCreateData,
|
||||||
ProfileUpdateData,
|
ProfileUpdateData,
|
||||||
};
|
};
|
||||||
|
@ -24,15 +25,15 @@ pub async fn create_profile(
|
||||||
profile_data: ProfileCreateData,
|
profile_data: ProfileCreateData,
|
||||||
) -> Result<DbActorProfile, DatabaseError> {
|
) -> Result<DbActorProfile, DatabaseError> {
|
||||||
let profile_id = new_uuid();
|
let profile_id = new_uuid();
|
||||||
let extra_fields = ExtraFields(profile_data.extra_fields.clone());
|
|
||||||
let row = db_client.query_one(
|
let row = db_client.query_one(
|
||||||
"
|
"
|
||||||
INSERT INTO actor_profile (
|
INSERT INTO actor_profile (
|
||||||
id, username, display_name, acct, bio, bio_source,
|
id, username, display_name, acct, bio, bio_source,
|
||||||
avatar_file_name, banner_file_name, extra_fields,
|
avatar_file_name, banner_file_name,
|
||||||
|
identity_proofs, extra_fields,
|
||||||
actor_json
|
actor_json
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||||
RETURNING actor_profile
|
RETURNING actor_profile
|
||||||
",
|
",
|
||||||
&[
|
&[
|
||||||
|
@ -44,7 +45,8 @@ pub async fn create_profile(
|
||||||
&profile_data.bio,
|
&profile_data.bio,
|
||||||
&profile_data.avatar,
|
&profile_data.avatar,
|
||||||
&profile_data.banner,
|
&profile_data.banner,
|
||||||
&extra_fields,
|
&IdentityProofs(profile_data.identity_proofs),
|
||||||
|
&ExtraFields(profile_data.extra_fields),
|
||||||
&profile_data.actor_json,
|
&profile_data.actor_json,
|
||||||
],
|
],
|
||||||
).await.map_err(catch_unique_violation("profile"))?;
|
).await.map_err(catch_unique_violation("profile"))?;
|
||||||
|
@ -66,9 +68,10 @@ pub async fn update_profile(
|
||||||
bio_source = $3,
|
bio_source = $3,
|
||||||
avatar_file_name = $4,
|
avatar_file_name = $4,
|
||||||
banner_file_name = $5,
|
banner_file_name = $5,
|
||||||
extra_fields = $6,
|
identity_proofs = $6,
|
||||||
actor_json = $7
|
extra_fields = $7,
|
||||||
WHERE id = $8
|
actor_json = $8
|
||||||
|
WHERE id = $9
|
||||||
RETURNING actor_profile
|
RETURNING actor_profile
|
||||||
",
|
",
|
||||||
&[
|
&[
|
||||||
|
@ -77,6 +80,7 @@ pub async fn update_profile(
|
||||||
&data.bio_source,
|
&data.bio_source,
|
||||||
&data.avatar,
|
&data.avatar,
|
||||||
&data.banner,
|
&data.banner,
|
||||||
|
&IdentityProofs(data.identity_proofs),
|
||||||
&ExtraFields(data.extra_fields),
|
&ExtraFields(data.extra_fields),
|
||||||
&data.actor_json,
|
&data.actor_json,
|
||||||
&profile_id,
|
&profile_id,
|
||||||
|
@ -490,6 +494,8 @@ mod tests {
|
||||||
let db_client = create_test_database().await;
|
let db_client = create_test_database().await;
|
||||||
let profile = create_profile(&db_client, profile_data).await.unwrap();
|
let profile = create_profile(&db_client, profile_data).await.unwrap();
|
||||||
assert_eq!(profile.username, "test");
|
assert_eq!(profile.username, "test");
|
||||||
|
assert_eq!(profile.identity_proofs.into_inner().len(), 0);
|
||||||
|
assert_eq!(profile.extra_fields.into_inner().len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -52,10 +52,6 @@ impl ExtraFields {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_currency_field_name(currency_code: &str) -> String {
|
|
||||||
format!("${}", currency_code.to_uppercase())
|
|
||||||
}
|
|
||||||
|
|
||||||
json_from_sql!(ExtraFields);
|
json_from_sql!(ExtraFields);
|
||||||
json_to_sql!(ExtraFields);
|
json_to_sql!(ExtraFields);
|
||||||
|
|
||||||
|
@ -73,6 +69,7 @@ pub struct DbActorProfile {
|
||||||
pub bio_source: Option<String>, // plaintext or markdown
|
pub bio_source: Option<String>, // plaintext or markdown
|
||||||
pub avatar_file_name: Option<String>,
|
pub avatar_file_name: Option<String>,
|
||||||
pub banner_file_name: Option<String>,
|
pub banner_file_name: Option<String>,
|
||||||
|
pub identity_proofs: IdentityProofs,
|
||||||
pub extra_fields: ExtraFields,
|
pub extra_fields: ExtraFields,
|
||||||
pub follower_count: i32,
|
pub follower_count: i32,
|
||||||
pub following_count: i32,
|
pub following_count: i32,
|
||||||
|
@ -128,6 +125,7 @@ impl Default for DbActorProfile {
|
||||||
bio_source: None,
|
bio_source: None,
|
||||||
avatar_file_name: None,
|
avatar_file_name: None,
|
||||||
banner_file_name: None,
|
banner_file_name: None,
|
||||||
|
identity_proofs: IdentityProofs(vec![]),
|
||||||
extra_fields: ExtraFields(vec![]),
|
extra_fields: ExtraFields(vec![]),
|
||||||
follower_count: 0,
|
follower_count: 0,
|
||||||
following_count: 0,
|
following_count: 0,
|
||||||
|
@ -147,6 +145,7 @@ pub struct ProfileCreateData {
|
||||||
pub bio: Option<String>,
|
pub bio: Option<String>,
|
||||||
pub avatar: Option<String>,
|
pub avatar: Option<String>,
|
||||||
pub banner: Option<String>,
|
pub banner: Option<String>,
|
||||||
|
pub identity_proofs: Vec<IdentityProof>,
|
||||||
pub extra_fields: Vec<ExtraField>,
|
pub extra_fields: Vec<ExtraField>,
|
||||||
pub actor_json: Option<Actor>,
|
pub actor_json: Option<Actor>,
|
||||||
}
|
}
|
||||||
|
@ -172,6 +171,7 @@ pub struct ProfileUpdateData {
|
||||||
pub bio_source: Option<String>,
|
pub bio_source: Option<String>,
|
||||||
pub avatar: Option<String>,
|
pub avatar: Option<String>,
|
||||||
pub banner: Option<String>,
|
pub banner: Option<String>,
|
||||||
|
pub identity_proofs: Vec<IdentityProof>,
|
||||||
pub extra_fields: Vec<ExtraField>,
|
pub extra_fields: Vec<ExtraField>,
|
||||||
pub actor_json: Option<Actor>,
|
pub actor_json: Option<Actor>,
|
||||||
}
|
}
|
||||||
|
@ -192,6 +192,22 @@ impl ProfileUpdateData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&DbActorProfile> for ProfileUpdateData {
|
||||||
|
fn from(profile: &DbActorProfile) -> Self {
|
||||||
|
let profile = profile.clone();
|
||||||
|
Self {
|
||||||
|
display_name: profile.display_name,
|
||||||
|
bio: profile.bio,
|
||||||
|
bio_source: profile.bio_source,
|
||||||
|
avatar: profile.avatar_file_name,
|
||||||
|
banner: profile.banner_file_name,
|
||||||
|
identity_proofs: profile.identity_proofs.into_inner(),
|
||||||
|
extra_fields: profile.extra_fields.into_inner(),
|
||||||
|
actor_json: profile.actor_json,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::activitypub::actor::Actor;
|
use crate::activitypub::actor::Actor;
|
||||||
|
|
|
@ -80,6 +80,7 @@ pub async fn create_user(
|
||||||
bio: None,
|
bio: None,
|
||||||
avatar: None,
|
avatar: None,
|
||||||
banner: None,
|
banner: None,
|
||||||
|
identity_proofs: vec![],
|
||||||
extra_fields: vec![],
|
extra_fields: vec![],
|
||||||
actor_json: None,
|
actor_json: None,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue