Make media URLs in Mastodon API responses relative to current origin

This commit is contained in:
silverpill 2023-02-21 21:39:42 +00:00
parent c796cddff8
commit e1e9851d5c
18 changed files with 204 additions and 33 deletions

View file

@ -26,6 +26,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fixed actor object JSON-LD validation errors.
- Fixed activity JSON-LD validation errors.
- Make media URLs in Mastodon API responses relative to current origin.
## [1.13.1] - 2023-02-09

View file

@ -14,6 +14,9 @@ pub fn get_hostname(url: &str) -> Result<String, ParseError> {
}
pub fn guess_protocol(hostname: &str) -> &'static str {
if hostname == "localhost" {
return "http";
};
let maybe_ipv4_address = hostname.parse::<Ipv4Addr>();
if let Ok(_ipv4_address) = maybe_ipv4_address {
return "http";

View file

@ -1,6 +1,6 @@
use actix_web::{
body::{BodySize, BoxBody, MessageBody},
dev::ServiceResponse,
dev::{ConnectionInfo, ServiceResponse},
error::{Error, JsonPayloadError},
http::StatusCode,
middleware::{ErrorHandlerResponse, ErrorHandlers},
@ -10,6 +10,8 @@ use actix_web::{
};
use serde_json::json;
use mitra_utils::urls::guess_protocol;
use crate::errors::HttpError;
pub type FormOrJson<T> = Either<Form<T>, Json<T>>;
@ -46,3 +48,15 @@ pub fn json_error_handler(
other_error => other_error.into(),
}
}
pub fn get_request_base_url(connection_info: ConnectionInfo) -> String {
// TODO: HTTP server should set X-Forwarded-Proto header
// let scheme = connection_info.scheme();
let host = connection_info.host();
let scheme = if let Some((hostname, _port)) = host.split_once(':') {
guess_protocol(hostname)
} else {
guess_protocol(host)
};
format!("{}://{}", scheme, host)
}

View file

@ -117,14 +117,15 @@ pub struct Account {
impl Account {
pub fn from_profile(
base_url: &str,
instance_url: &str,
profile: DbActorProfile,
) -> Self {
let profile_url = profile.actor_url(instance_url);
let avatar_url = profile.avatar
.map(|image| get_file_url(instance_url, &image.file_name));
.map(|image| get_file_url(base_url, &image.file_name));
let header_url = profile.banner
.map(|image| get_file_url(instance_url, &image.file_name));
.map(|image| get_file_url(base_url, &image.file_name));
let is_locked = profile.actor_json
.map(|actor| actor.manually_approves_followers)
.unwrap_or(false);
@ -207,6 +208,7 @@ impl Account {
}
pub fn from_user(
base_url: &str,
instance_url: &str,
user: User,
) -> Self {
@ -224,6 +226,7 @@ impl Account {
};
let role = ApiRole::from_db(user.role);
let mut account = Self::from_profile(
base_url,
instance_url,
user.profile,
);
@ -502,10 +505,12 @@ pub struct ApiSubscription {
impl ApiSubscription {
pub fn from_subscription(
base_url: &str,
instance_url: &str,
subscription: Subscription,
) -> Self {
let sender = Account::from_profile(
base_url,
instance_url,
subscription.sender,
);
@ -545,6 +550,7 @@ mod tests {
..Default::default()
};
let account = Account::from_profile(
INSTANCE_URL,
INSTANCE_URL,
profile,
);
@ -570,6 +576,7 @@ mod tests {
..Default::default()
};
let account = Account::from_user(
INSTANCE_URL,
INSTANCE_URL,
user,
);

View file

@ -1,6 +1,12 @@
use actix_web::{
get, patch, post, web,
HttpRequest, HttpResponse, Scope,
dev::ConnectionInfo,
get,
patch,
post,
web,
HttpRequest,
HttpResponse,
Scope,
};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use uuid::Uuid;
@ -33,6 +39,7 @@ use crate::ethereum::{
gate::is_allowed_user,
identity::verify_eip191_identity_proof,
};
use crate::http::get_request_base_url;
use crate::identity::{
claims::create_identity_claim,
did::Did,
@ -110,6 +117,7 @@ use super::types::{
#[post("")]
pub async fn create_account(
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
maybe_blockchain: web::Data<Option<ContractSet>>,
@ -195,6 +203,7 @@ pub async fn create_account(
};
log::warn!("created user {}", user.id);
let account = Account::from_user(
&get_request_base_url(connection_info),
&config.instance_url(),
user,
);
@ -204,12 +213,14 @@ pub async fn create_account(
#[get("/verify_credentials")]
async fn verify_credentials(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
) -> Result<HttpResponse, HttpError> {
let db_client = &**get_database_client(&db_pool).await?;
let user = get_current_user(db_client, auth.token()).await?;
let account = Account::from_user(
&get_request_base_url(connection_info),
&config.instance_url(),
user,
);
@ -219,6 +230,7 @@ async fn verify_credentials(
#[patch("/update_credentials")]
async fn update_credentials(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
account_data: web::Json<AccountUpdateData>,
@ -246,6 +258,7 @@ async fn update_credentials(
).await?.enqueue(db_client).await?;
let account = Account::from_user(
&get_request_base_url(connection_info),
&config.instance_url(),
current_user,
);
@ -278,6 +291,7 @@ async fn get_unsigned_update(
#[post("/send_activity")]
async fn send_signed_activity(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
data: web::Json<SignedActivity>,
@ -323,6 +337,7 @@ async fn send_signed_activity(
outgoing_activity.enqueue(db_client).await?;
let account = Account::from_user(
&get_request_base_url(connection_info),
&config.instance_url(),
current_user,
);
@ -363,6 +378,7 @@ async fn get_identity_claim(
#[post("/identity_proof")]
async fn create_identity_proof(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
proof_data: web::Json<IdentityProofData>,
@ -441,6 +457,7 @@ async fn create_identity_proof(
).await?.enqueue(db_client).await?;
let account = Account::from_user(
&get_request_base_url(connection_info),
&config.instance_url(),
current_user,
);
@ -465,6 +482,7 @@ async fn get_relationships_view(
#[get("/lookup")]
async fn lookup_acct(
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
query_params: web::Query<LookupAcctQueryParams>,
@ -472,6 +490,7 @@ async fn lookup_acct(
let db_client = &**get_database_client(&db_pool).await?;
let profile = get_profile_by_acct(db_client, &query_params.acct).await?;
let account = Account::from_profile(
&get_request_base_url(connection_info),
&config.instance_url(),
profile,
);
@ -480,6 +499,7 @@ async fn lookup_acct(
#[get("/search")]
async fn search_by_acct(
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
query_params: web::Query<SearchAcctQueryParams>,
@ -490,9 +510,11 @@ async fn search_by_acct(
&query_params.q,
query_params.limit.inner(),
).await?;
let base_url = get_request_base_url(connection_info);
let instance_url = config.instance().url();
let accounts: Vec<Account> = profiles.into_iter()
.map(|profile| Account::from_profile(
&base_url,
&instance_url,
profile,
))
@ -502,6 +524,7 @@ async fn search_by_acct(
#[get("/search_did")]
async fn search_by_did(
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
query_params: web::Query<SearchDidQueryParams>,
@ -510,9 +533,11 @@ async fn search_by_did(
let did: Did = query_params.did.parse()
.map_err(|_| ValidationError("invalid DID"))?;
let profiles = search_profiles_by_did(db_client, &did, false).await?;
let base_url = get_request_base_url(connection_info);
let instance_url = config.instance().url();
let accounts: Vec<Account> = profiles.into_iter()
.map(|profile| Account::from_profile(
&base_url,
&instance_url,
profile,
))
@ -522,6 +547,7 @@ async fn search_by_did(
#[get("/{account_id}")]
async fn get_account(
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
account_id: web::Path<Uuid>,
@ -529,6 +555,7 @@ async fn get_account(
let db_client = &**get_database_client(&db_pool).await?;
let profile = get_profile_by_id(db_client, &account_id).await?;
let account = Account::from_profile(
&get_request_base_url(connection_info),
&config.instance_url(),
profile,
);
@ -608,6 +635,7 @@ async fn unfollow_account(
#[get("/{account_id}/statuses")]
async fn get_account_statuses(
auth: Option<BearerAuth>,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
account_id: web::Path<Uuid>,
@ -636,6 +664,7 @@ async fn get_account_statuses(
).await?;
let statuses = build_status_list(
db_client,
&get_request_base_url(connection_info),
&config.instance_url(),
maybe_current_user.as_ref(),
posts,
@ -646,6 +675,7 @@ async fn get_account_statuses(
#[get("/{account_id}/followers")]
async fn get_account_followers(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
account_id: web::Path<Uuid>,
@ -668,9 +698,11 @@ async fn get_account_followers(
).await?;
let max_index = usize::from(query_params.limit.inner().saturating_sub(1));
let maybe_last_id = followers.get(max_index).map(|item| item.relationship_id);
let base_url = get_request_base_url(connection_info);
let instance_url = config.instance().url();
let accounts: Vec<Account> = followers.into_iter()
.map(|item| Account::from_profile(
&base_url,
&instance_url,
item.profile,
))
@ -687,6 +719,7 @@ async fn get_account_followers(
#[get("/{account_id}/following")]
async fn get_account_following(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
account_id: web::Path<Uuid>,
@ -709,9 +742,11 @@ async fn get_account_following(
).await?;
let max_index = usize::from(query_params.limit.inner().saturating_sub(1));
let maybe_last_id = following.get(max_index).map(|item| item.relationship_id);
let base_url = get_request_base_url(connection_info);
let instance_url = config.instance().url();
let accounts: Vec<Account> = following.into_iter()
.map(|item| Account::from_profile(
&base_url,
&instance_url,
item.profile,
))
@ -728,6 +763,7 @@ async fn get_account_following(
#[get("/{account_id}/subscribers")]
async fn get_account_subscribers(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
account_id: web::Path<Uuid>,
@ -741,6 +777,7 @@ async fn get_account_subscribers(
let subscriptions: Vec<ApiSubscription> = vec![];
return Ok(HttpResponse::Ok().json(subscriptions));
};
let base_url = get_request_base_url(connection_info);
let instance_url = config.instance_url();
let subscriptions: Vec<ApiSubscription> = get_incoming_subscriptions(
db_client,
@ -751,6 +788,7 @@ async fn get_account_subscribers(
.await?
.into_iter()
.map(|subscription| ApiSubscription::from_subscription(
&base_url,
&instance_url,
subscription,
))

View file

@ -13,8 +13,8 @@ pub struct CustomEmoji {
}
impl CustomEmoji {
pub fn from_db(instance_url: &str, emoji: DbEmoji) -> Self {
let image_url = get_file_url(instance_url, &emoji.image.file_name);
pub fn from_db(base_url: &str, emoji: DbEmoji) -> Self {
let image_url = get_file_url(base_url, &emoji.image.file_name);
Self {
shortcode: emoji.emoji_name,
url: image_url.clone(),

View file

@ -1,23 +1,28 @@
use actix_web::{get, web, HttpResponse, Scope};
use mitra_config::Config;
use actix_web::{
dev::ConnectionInfo,
get,
web,
HttpResponse,
Scope,
};
use crate::database::{get_database_client, DbPool};
use crate::errors::HttpError;
use crate::http::get_request_base_url;
use crate::models::emojis::queries::get_local_emojis;
use super::types::CustomEmoji;
/// https://docs.joinmastodon.org/methods/custom_emojis/
#[get("")]
async fn custom_emoji_list(
config: web::Data<Config>,
connection_info: ConnectionInfo,
db_pool: web::Data<DbPool>,
) -> Result<HttpResponse, HttpError> {
let db_client = &**get_database_client(&db_pool).await?;
let instance = config.instance();
let base_url = get_request_base_url(connection_info);
let emojis: Vec<CustomEmoji> = get_local_emojis(db_client).await?
.into_iter()
.map(|db_emoji| CustomEmoji::from_db(&instance.url(), db_emoji))
.map(|db_emoji| CustomEmoji::from_db(&base_url, db_emoji))
.collect();
Ok(HttpResponse::Ok().json(emojis))
}

View file

@ -1,11 +1,18 @@
/// https://docs.joinmastodon.org/methods/instance/directory/
use actix_web::{get, web, HttpResponse, Scope};
use actix_web::{
dev::ConnectionInfo,
get,
web,
HttpResponse,
Scope,
};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use mitra_config::Config;
use crate::database::{get_database_client, DbPool};
use crate::errors::HttpError;
use crate::http::get_request_base_url;
use crate::mastodon_api::{
accounts::types::Account,
oauth::auth::get_current_user,
@ -16,6 +23,7 @@ use super::types::DirectoryQueryParams;
#[get("")]
async fn profile_directory(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
query_params: web::Query<DirectoryQueryParams>,
@ -28,10 +36,12 @@ async fn profile_directory(
query_params.offset,
query_params.limit.inner(),
).await?;
let base_url = get_request_base_url(connection_info);
let instance_url = config.instance().url();
let accounts: Vec<Account> = profiles
.into_iter()
.map(|profile| Account::from_profile(
&base_url,
&instance_url,
profile,
))

View file

@ -26,7 +26,7 @@ pub struct Attachment {
}
impl Attachment {
pub fn from_db(instance_url: &str, db_attachment: DbMediaAttachment) -> Self {
pub fn from_db(base_url: &str, db_attachment: DbMediaAttachment) -> Self {
let attachment_type =
AttachmentType::from_media_type(db_attachment.media_type);
let attachment_type_mastodon = match attachment_type {
@ -35,7 +35,7 @@ impl Attachment {
AttachmentType::Video => "video",
};
let attachment_url = get_file_url(
instance_url,
base_url,
&db_attachment.file_name,
);
Self {

View file

@ -35,15 +35,17 @@ pub struct ApiNotification {
impl ApiNotification {
pub fn from_db(
base_url: &str,
instance_url: &str,
notification: Notification,
) -> Self {
let account = Account::from_profile(
base_url,
instance_url,
notification.sender,
);
let status = notification.post.map(|post| {
Status::from_post(instance_url, post)
Status::from_post(base_url, instance_url, post)
});
let event_type_mastodon = match notification.event_type {
EventType::Follow => "follow",

View file

@ -1,6 +1,8 @@
/// https://docs.joinmastodon.org/methods/notifications/
use actix_web::{
get, web,
dev::ConnectionInfo,
get,
web,
HttpRequest, HttpResponse,
Scope as ActixScope,
};
@ -10,6 +12,7 @@ use mitra_config::Config;
use crate::database::{get_database_client, DbPool};
use crate::errors::HttpError;
use crate::http::get_request_base_url;
use crate::mastodon_api::{
oauth::auth::get_current_user,
pagination::get_paginated_response,
@ -20,6 +23,7 @@ use super::types::{ApiNotification, NotificationQueryParams};
#[get("")]
async fn get_notifications_view(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
query_params: web::Query<NotificationQueryParams>,
@ -27,6 +31,8 @@ async fn get_notifications_view(
) -> Result<HttpResponse, HttpError> {
let db_client = &**get_database_client(&db_pool).await?;
let current_user = get_current_user(db_client, auth.token()).await?;
let base_url = get_request_base_url(connection_info);
let instance = config.instance();
let notifications: Vec<ApiNotification> = get_notifications(
db_client,
&current_user.id,
@ -34,13 +40,17 @@ async fn get_notifications_view(
query_params.limit.inner(),
).await?
.into_iter()
.map(|item| ApiNotification::from_db(&config.instance_url(), item))
.map(|item| ApiNotification::from_db(
&base_url,
&instance.url(),
item,
))
.collect();
let max_index = usize::from(query_params.limit.inner().saturating_sub(1));
let maybe_last_id = notifications.get(max_index)
.map(|item| item.id.clone());
let response = get_paginated_response(
&config.instance_url(),
&instance.url(),
request.uri().path(),
notifications,
maybe_last_id,

View file

@ -1,11 +1,18 @@
/// https://docs.joinmastodon.org/methods/search/
use actix_web::{get, web, HttpResponse, Scope};
use actix_web::{
dev::ConnectionInfo,
get,
web,
HttpResponse,
Scope,
};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use mitra_config::Config;
use crate::database::{get_database_client, DbPool};
use crate::errors::HttpError;
use crate::http::get_request_base_url;
use crate::mastodon_api::{
accounts::types::Account,
oauth::auth::get_current_user,
@ -18,6 +25,7 @@ use super::types::{SearchQueryParams, SearchResults};
#[get("")]
async fn search_view(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
query_params: web::Query<SearchQueryParams>,
@ -31,15 +39,18 @@ async fn search_view(
query_params.q.trim(),
query_params.limit.inner(),
).await?;
let base_url = get_request_base_url(connection_info);
let instance_url = config.instance().url();
let accounts: Vec<Account> = profiles.into_iter()
.map(|profile| Account::from_profile(
&base_url,
&instance_url,
profile,
))
.collect();
let statuses = build_status_list(
db_client,
&base_url,
&instance_url,
Some(&current_user),
posts,

View file

@ -1,4 +1,11 @@
use actix_web::{get, post, web, HttpResponse, Scope};
use actix_web::{
dev::ConnectionInfo,
get,
post,
web,
HttpResponse,
Scope,
};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use mitra_config::Config;
@ -12,6 +19,7 @@ use crate::activitypub::{
};
use crate::database::{get_database_client, DatabaseError, DbPool};
use crate::errors::{HttpError, ValidationError};
use crate::http::get_request_base_url;
use crate::mastodon_api::{
accounts::types::Account,
oauth::auth::get_current_user,
@ -37,6 +45,7 @@ use super::types::{
#[post("/change_password")]
async fn change_password_view(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
request_data: web::Json<PasswordChangeRequest>,
@ -47,6 +56,7 @@ async fn change_password_view(
.map_err(|_| HttpError::InternalError)?;
set_user_password(db_client, &current_user.id, password_hash).await?;
let account = Account::from_user(
&get_request_base_url(connection_info),
&config.instance_url(),
current_user,
);
@ -117,6 +127,7 @@ async fn import_follows_view(
#[post("/move_followers")]
async fn move_followers(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
request_data: web::Json<MoveFollowersRequest>,
@ -194,6 +205,7 @@ async fn move_followers(
).enqueue(db_client).await?;
let account = Account::from_user(
&get_request_base_url(connection_info),
&instance.url(),
current_user,
);

View file

@ -75,6 +75,7 @@ pub async fn parse_microsyntaxes(
/// Load related objects and build status for API response
pub async fn build_status(
db_client: &impl DatabaseClient,
base_url: &str,
instance_url: &str,
user: Option<&User>,
mut post: Post,
@ -83,12 +84,13 @@ pub async fn build_status(
if let Some(user) = user {
add_user_actions(db_client, &user.id, vec![&mut post]).await?;
};
let status = Status::from_post(instance_url, post);
let status = Status::from_post(base_url, instance_url, post);
Ok(status)
}
pub async fn build_status_list(
db_client: &impl DatabaseClient,
base_url: &str,
instance_url: &str,
user: Option<&User>,
mut posts: Vec<Post>,
@ -99,7 +101,7 @@ pub async fn build_status_list(
};
let statuses: Vec<Status> = posts
.into_iter()
.map(|post| Status::from_post(instance_url, post))
.map(|post| Status::from_post(base_url, instance_url, post))
.collect();
Ok(statuses)
}

View file

@ -85,12 +85,13 @@ pub struct Status {
impl Status {
pub fn from_post(
base_url: &str,
instance_url: &str,
post: Post,
) -> Self {
let object_id = post.object_id(instance_url);
let attachments: Vec<Attachment> = post.attachments.into_iter()
.map(|item| Attachment::from_db(instance_url, item))
.map(|item| Attachment::from_db(base_url, item))
.collect();
let mentions: Vec<Mention> = post.mentions.into_iter()
.map(|item| Mention::from_profile(instance_url, item))
@ -99,20 +100,21 @@ impl Status {
.map(|tag_name| Tag::from_tag_name(instance_url, tag_name))
.collect();
let emojis: Vec<CustomEmoji> = post.emojis.into_iter()
.map(|emoji| CustomEmoji::from_db(instance_url, emoji))
.map(|emoji| CustomEmoji::from_db(base_url, emoji))
.collect();
let account = Account::from_profile(
base_url,
instance_url,
post.author,
);
let reblog = if let Some(repost_of) = post.repost_of {
let status = Status::from_post(instance_url, *repost_of);
let status = Status::from_post(base_url, instance_url, *repost_of);
Some(Box::new(status))
} else {
None
};
let links = post.linked.into_iter().map(|post| {
Status::from_post(instance_url, post)
Status::from_post(base_url, instance_url, post)
}).collect();
let visibility = match post.visibility {
Visibility::Public => "public",

View file

@ -1,5 +1,13 @@
/// https://docs.joinmastodon.org/methods/statuses/
use actix_web::{delete, get, post, web, HttpResponse, Scope};
use actix_web::{
delete,
dev::ConnectionInfo,
get,
post,
web,
HttpResponse,
Scope,
};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use chrono::Utc;
use uuid::Uuid;
@ -21,7 +29,7 @@ use crate::activitypub::builders::{
use crate::database::{get_database_client, DatabaseError, DbPool};
use crate::errors::{HttpError, ValidationError};
use crate::ethereum::nft::create_mint_signature;
use crate::http::FormOrJson;
use crate::http::{get_request_base_url, FormOrJson};
use crate::ipfs::{
store as ipfs_store,
posts::PostMetadata,
@ -69,6 +77,7 @@ use super::types::{
#[post("")]
async fn create_status(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
status_data: FormOrJson<StatusData>,
@ -190,7 +199,11 @@ async fn create_status(
prepare_create_note(db_client, &instance, &current_user, &post)
.await?.enqueue(db_client).await?;
let status = Status::from_post(&instance.url(), post);
let status = Status::from_post(
&get_request_base_url(connection_info),
&instance.url(),
post,
);
Ok(HttpResponse::Ok().json(status))
}
@ -232,6 +245,7 @@ async fn preview_status(
#[get("/{status_id}")]
async fn get_status(
auth: Option<BearerAuth>,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
status_id: web::Path<Uuid>,
@ -247,6 +261,7 @@ async fn get_status(
};
let status = build_status(
db_client,
&get_request_base_url(connection_info),
&config.instance_url(),
maybe_current_user.as_ref(),
post,
@ -285,6 +300,7 @@ async fn delete_status(
#[get("/{status_id}/context")]
async fn get_context(
auth: Option<BearerAuth>,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
status_id: web::Path<Uuid>,
@ -301,6 +317,7 @@ async fn get_context(
).await?;
let statuses = build_status_list(
db_client,
&get_request_base_url(connection_info),
&config.instance_url(),
maybe_current_user.as_ref(),
posts,
@ -327,6 +344,7 @@ async fn get_context(
async fn get_thread_view(
auth: Option<BearerAuth>,
config: web::Data<Config>,
connection_info: ConnectionInfo,
db_pool: web::Data<DbPool>,
status_id: web::Path<Uuid>,
) -> Result<HttpResponse, HttpError> {
@ -342,6 +360,7 @@ async fn get_thread_view(
).await?;
let statuses = build_status_list(
db_client,
&get_request_base_url(connection_info),
&config.instance_url(),
maybe_current_user.as_ref(),
posts,
@ -352,6 +371,7 @@ async fn get_thread_view(
#[post("/{status_id}/favourite")]
async fn favourite(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
status_id: web::Path<Uuid>,
@ -386,6 +406,7 @@ async fn favourite(
let status = build_status(
db_client,
&get_request_base_url(connection_info),
&config.instance_url(),
Some(&current_user),
post,
@ -396,6 +417,7 @@ async fn favourite(
#[post("/{status_id}/unfavourite")]
async fn unfavourite(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
status_id: web::Path<Uuid>,
@ -427,6 +449,7 @@ async fn unfavourite(
let status = build_status(
db_client,
&get_request_base_url(connection_info),
&config.instance_url(),
Some(&current_user),
post,
@ -437,6 +460,7 @@ async fn unfavourite(
#[post("/{status_id}/reblog")]
async fn reblog(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
status_id: web::Path<Uuid>,
@ -465,6 +489,7 @@ async fn reblog(
let status = build_status(
db_client,
&get_request_base_url(connection_info),
&config.instance_url(),
Some(&current_user),
repost,
@ -475,6 +500,7 @@ async fn reblog(
#[post("/{status_id}/unreblog")]
async fn unreblog(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
status_id: web::Path<Uuid>,
@ -502,6 +528,7 @@ async fn unreblog(
let status = build_status(
db_client,
&get_request_base_url(connection_info),
&config.instance_url(),
Some(&current_user),
post,
@ -512,6 +539,7 @@ async fn unreblog(
#[post("/{status_id}/make_permanent")]
async fn make_permanent(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
status_id: web::Path<Uuid>,
@ -561,6 +589,7 @@ async fn make_permanent(
let status = build_status(
db_client,
&get_request_base_url(connection_info),
&config.instance_url(),
Some(&current_user),
post,
@ -605,6 +634,7 @@ async fn get_signature(
#[post("/{status_id}/token_minted")]
async fn token_minted(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
status_id: web::Path<Uuid>,
@ -625,6 +655,7 @@ async fn token_minted(
let status = build_status(
db_client,
&get_request_base_url(connection_info),
&config.instance_url(),
Some(&current_user),
post,

View file

@ -1,4 +1,11 @@
use actix_web::{get, post, web, HttpResponse, Scope};
use actix_web::{
dev::ConnectionInfo,
get,
post,
web,
HttpResponse,
Scope,
};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use uuid::Uuid;
@ -15,6 +22,7 @@ use crate::ethereum::{
is_registered_recipient,
},
};
use crate::http::get_request_base_url;
use crate::mastodon_api::{
accounts::types::Account,
oauth::auth::get_current_user,
@ -92,6 +100,7 @@ async fn get_subscription_options(
#[post("/options")]
pub async fn register_subscription_option(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
maybe_blockchain: web::Data<Option<ContractSet>>,
@ -166,6 +175,7 @@ pub async fn register_subscription_option(
};
let account = Account::from_user(
&get_request_base_url(connection_info),
&config.instance_url(),
current_user,
);

View file

@ -1,11 +1,18 @@
/// https://docs.joinmastodon.org/methods/timelines/
use actix_web::{get, web, HttpResponse, Scope};
use actix_web::{
dev::ConnectionInfo,
get,
web,
HttpResponse,
Scope,
};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use mitra_config::Config;
use crate::database::{get_database_client, DbPool};
use crate::errors::HttpError;
use crate::http::get_request_base_url;
use crate::mastodon_api::{
oauth::auth::get_current_user,
statuses::helpers::build_status_list,
@ -20,6 +27,7 @@ use super::types::TimelineQueryParams;
#[get("/home")]
async fn home_timeline(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
query_params: web::Query<TimelineQueryParams>,
@ -34,6 +42,7 @@ async fn home_timeline(
).await?;
let statuses = build_status_list(
db_client,
&get_request_base_url(connection_info),
&config.instance_url(),
Some(&current_user),
posts,
@ -45,6 +54,7 @@ async fn home_timeline(
#[get("/public")]
async fn public_timeline(
auth: BearerAuth,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
query_params: web::Query<TimelineQueryParams>,
@ -59,6 +69,7 @@ async fn public_timeline(
).await?;
let statuses = build_status_list(
db_client,
&get_request_base_url(connection_info),
&config.instance_url(),
Some(&current_user),
posts,
@ -69,6 +80,7 @@ async fn public_timeline(
#[get("/tag/{hashtag}")]
async fn hashtag_timeline(
auth: Option<BearerAuth>,
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
hashtag: web::Path<String>,
@ -88,6 +100,7 @@ async fn hashtag_timeline(
).await?;
let statuses = build_status_list(
db_client,
&get_request_base_url(connection_info),
&config.instance_url(),
maybe_current_user.as_ref(),
posts,