Create /api/v1/accounts/aliases/all API endpoint

This commit is contained in:
silverpill 2023-04-03 20:16:16 +00:00
parent 59e5f12016
commit 13df9e0478
8 changed files with 143 additions and 28 deletions

View file

@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added
- Support calling `/api/v1/accounts/search` with `resolve` parameter.
- Created `/api/v1/accounts/aliases/all` API endpoint.
### Changed

View file

@ -550,23 +550,6 @@ paths:
$ref: '#/components/schemas/Subscription'
404:
description: Profile not found
/api/v1/accounts/{account_id}/aliases:
get:
summary: Get actor's aliases.
parameters:
- $ref: '#/components/parameters/account_id'
responses:
200:
description: Successful operation
content:
application/json:
schema:
description: Profile list
type: array
items:
$ref: '#/components/schemas/Account'
404:
description: Profile not found
/api/v1/accounts/{account_id}/follow:
post:
summary: Follow the given actor.
@ -613,6 +596,37 @@ paths:
$ref: '#/components/schemas/Relationship'
404:
description: Profile not found
/api/v1/accounts/{account_id}/aliases:
get:
summary: Get actor's verified aliases.
parameters:
- $ref: '#/components/parameters/account_id'
responses:
200:
description: Successful operation
content:
application/json:
schema:
description: Profile list
type: array
items:
$ref: '#/components/schemas/Account'
404:
description: Profile not found
/api/v1/accounts/{account_id}/aliases/all:
get:
summary: Get actor's aliases.
parameters:
- $ref: '#/components/parameters/account_id'
responses:
200:
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Aliases'
404:
description: Profile not found
/api/v1/apps:
post:
summary: Create a new application to obtain OAuth2 credentials.
@ -1476,6 +1490,19 @@ components:
type: string
enum:
- update
Aliases:
type: object
properties:
declared:
description: Aliases declared by user.
type: array
items:
$ref: '#/components/schemas/Account'
verified:
description: Cryptographically verified aliases.
type: array
items:
$ref: '#/components/schemas/Account'
Application:
type: object
properties:

View file

@ -1,9 +1,32 @@
use crate::database::{DatabaseClient, DatabaseError};
use super::queries::search_profiles_by_did_only;
use super::queries::{
get_profile_by_remote_actor_id,
search_profiles_by_did_only,
};
use super::types::DbActorProfile;
pub async fn find_aliases(
pub async fn find_declared_aliases(
db_client: &impl DatabaseClient,
profile: &DbActorProfile,
) -> Result<Vec<DbActorProfile>, DatabaseError> {
let mut results = vec![];
for actor_id in profile.aliases.clone().into_actor_ids() {
let alias = match get_profile_by_remote_actor_id(
db_client,
&actor_id,
).await {
Ok(profile) => profile,
// Ignore unknown profiles
Err(DatabaseError::NotFound(_)) => continue,
Err(other_error) => return Err(other_error),
};
results.push(alias);
};
Ok(results)
}
pub async fn find_verified_aliases(
db_client: &impl DatabaseClient,
profile: &DbActorProfile,
) -> Result<Vec<DbActorProfile>, DatabaseError> {

View file

@ -5,7 +5,7 @@ use mitra_config::Config;
use mitra_models::{
database::{DatabaseClient, DatabaseError},
notifications::queries::create_move_notification,
profiles::helpers::find_aliases,
profiles::helpers::find_verified_aliases,
relationships::queries::{
create_follow_request,
get_followers,
@ -75,8 +75,8 @@ pub async fn handle_move(
let new_actor = new_profile.actor_json.as_ref()
.expect("target should be a remote actor");
// Find aliases by DIDs (signed)
let mut aliases = find_aliases(db_client, &new_profile).await?
// Find aliases by DIDs (verified)
let mut aliases = find_verified_aliases(db_client, &new_profile).await?
.into_iter()
.map(|profile| profile_actor_id(&instance.url(), &profile))
.collect::<Vec<_>>();

View file

@ -3,6 +3,10 @@ use uuid::Uuid;
use mitra_config::Instance;
use mitra_models::{
database::{DatabaseClient, DatabaseError},
profiles::helpers::{
find_declared_aliases,
find_verified_aliases,
},
profiles::types::DbActorProfile,
relationships::queries::{
create_follow_request,
@ -15,7 +19,7 @@ use mitra_models::{
use crate::activitypub::builders::follow::prepare_follow;
use super::types::RelationshipMap;
use super::types::{Account, Aliases, RelationshipMap};
pub async fn follow_or_create_request(
db_client: &mut impl DatabaseClient,
@ -95,6 +99,32 @@ pub async fn get_relationship(
Ok(relationship_map)
}
pub async fn get_aliases(
db_client: &impl DatabaseClient,
base_url: &str,
instance_url: &str,
profile: &DbActorProfile,
) -> Result<Aliases, DatabaseError> {
let declared = find_declared_aliases(db_client, profile).await?
.into_iter()
.map(|profile| Account::from_profile(
base_url,
instance_url,
profile,
))
.collect();
let verified = find_verified_aliases(db_client, profile).await?
.into_iter()
.map(|profile| Account::from_profile(
base_url,
instance_url,
profile,
))
.collect();
let aliases = Aliases { declared, verified };
Ok(aliases)
}
#[cfg(test)]
mod tests {
use serial_test::serial;

View file

@ -546,6 +546,12 @@ impl ApiSubscription {
}
}
#[derive(Serialize)]
pub struct Aliases {
pub declared: Vec<Account>,
pub verified: Vec<Account>,
}
#[cfg(test)]
mod tests {
use mitra_models::profiles::types::ProfileImage;

View file

@ -15,7 +15,7 @@ use mitra_config::{Config, DefaultRole, RegistrationType};
use mitra_models::{
database::{get_database_client, DatabaseError, DbPool},
posts::queries::get_posts_by_author,
profiles::helpers::find_aliases,
profiles::helpers::find_verified_aliases,
profiles::queries::{
get_profile_by_acct,
get_profile_by_id,
@ -100,7 +100,11 @@ use crate::mastodon_api::{
statuses::types::Status,
};
use crate::validators::profiles::clean_profile_update_data;
use super::helpers::{follow_or_create_request, get_relationship};
use super::helpers::{
follow_or_create_request,
get_aliases,
get_relationship,
};
use super::types::{
Account,
AccountCreateData,
@ -832,7 +836,7 @@ async fn get_account_aliases(
) -> Result<HttpResponse, MastodonError> {
let db_client = &**get_database_client(&db_pool).await?;
let profile = get_profile_by_id(db_client, &account_id).await?;
let aliases = find_aliases(db_client, &profile).await?;
let aliases = find_verified_aliases(db_client, &profile).await?;
let base_url = get_request_base_url(connection_info);
let instance_url = config.instance_url();
let accounts: Vec<Account> = aliases.into_iter()
@ -845,6 +849,26 @@ async fn get_account_aliases(
Ok(HttpResponse::Ok().json(accounts))
}
#[get("/{account_id}/aliases/all")]
async fn get_all_account_aliases(
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
account_id: web::Path<Uuid>,
) -> Result<HttpResponse, MastodonError> {
let db_client = &**get_database_client(&db_pool).await?;
let profile = get_profile_by_id(db_client, &account_id).await?;
let base_url = get_request_base_url(connection_info);
let instance_url = config.instance_url();
let aliases = get_aliases(
db_client,
&base_url,
&instance_url,
&profile,
).await?;
Ok(HttpResponse::Ok().json(aliases))
}
pub fn account_api_scope() -> Scope {
web::scope("/api/v1/accounts")
// Routes without account ID
@ -868,4 +892,5 @@ pub fn account_api_scope() -> Scope {
.service(get_account_following)
.service(get_account_subscribers)
.service(get_account_aliases)
.service(get_all_account_aliases)
}

View file

@ -11,7 +11,7 @@ use actix_web_httpauth::extractors::bearer::BearerAuth;
use mitra_config::Config;
use mitra_models::{
database::{get_database_client, DatabaseError, DbPool},
profiles::helpers::find_aliases,
profiles::helpers::find_verified_aliases,
profiles::queries::get_profile_by_remote_actor_id,
users::queries::set_user_password,
};
@ -149,7 +149,10 @@ async fn move_followers(
};
if maybe_from_profile.is_some() {
// Find known aliases of the current user
let mut aliases = find_aliases(db_client, &current_user.profile).await?
let mut aliases = find_verified_aliases(
db_client,
&current_user.profile,
).await?
.into_iter()
.map(|profile| profile_actor_id(&instance.url(), &profile));
if !aliases.any(|actor_id| actor_id == request_data.from_actor_id) {