perform markdown image processing in api/apub receivers

This commit is contained in:
Felix Ableitner 2023-10-24 13:27:58 +02:00
parent 540560b555
commit aaf3833d12
20 changed files with 151 additions and 100 deletions

View file

@ -2,7 +2,7 @@ use actix_web::web::{Data, Json};
use lemmy_api_common::{
context::LemmyContext,
person::SaveUserSettings,
utils::send_verification_email,
utils::{local_site_to_slur_regex, process_markdown_opt, send_verification_email},
SuccessResponse,
};
use lemmy_db_schema::{
@ -28,9 +28,12 @@ pub async fn save_user_settings(
) -> Result<Json<SuccessResponse>, LemmyError> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let bio =
process_markdown_opt(&data.bio, &local_site_to_slur_regex(&site_view.local_site)).await?;
let avatar = diesel_option_overwrite_to_url(&data.avatar)?;
let banner = diesel_option_overwrite_to_url(&data.banner)?;
let bio = diesel_option_overwrite(data.bio.clone());
let bio = diesel_option_overwrite(bio);
let display_name = diesel_option_overwrite(data.display_name.clone());
let matrix_user_id = diesel_option_overwrite(data.matrix_user_id.clone());
let email_deref = data.email.as_deref().map(str::to_lowercase);

View file

@ -37,7 +37,10 @@ use lemmy_utils::{
location_info,
rate_limit::{ActionType, BucketConfig},
settings::structs::Settings,
utils::slurs::build_slur_regex,
utils::{
markdown::markdown_rewrite_image_links,
slurs::{build_slur_regex, remove_slurs},
},
};
use regex::Regex;
use rosetta_i18n::{Language, LanguageId};
@ -786,6 +789,22 @@ fn limit_expire_time(expires: DateTime<Utc>) -> LemmyResult<Option<DateTime<Utc>
}
}
pub async fn process_markdown(text: &str, slur_regex: &Option<Regex>) -> LemmyResult<String> {
let text = remove_slurs(text, slur_regex);
let text = markdown_rewrite_image_links(text);
Ok(text)
}
pub async fn process_markdown_opt(
text: &Option<String>,
slur_regex: &Option<Regex>,
) -> LemmyResult<Option<String>> {
match text {
Some(t) => process_markdown(&t, slur_regex).await.map(Some),
None => Ok(None),
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]

View file

@ -11,6 +11,7 @@ use lemmy_api_common::{
generate_local_apub_endpoint,
get_post,
local_site_to_slur_regex,
process_markdown,
EndpointType,
},
};
@ -28,11 +29,7 @@ use lemmy_db_schema::{
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::{
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
utils::{
mention::scrape_text_for_mentions,
slurs::remove_slurs,
validation::is_valid_body_field,
},
utils::{mention::scrape_text_for_mentions, validation::is_valid_body_field},
};
const MAX_COMMENT_DEPTH_LIMIT: usize = 100;
@ -45,10 +42,7 @@ pub async fn create_comment(
) -> Result<Json<CommentResponse>, LemmyError> {
let local_site = LocalSite::read(&mut context.pool()).await?;
let content = remove_slurs(
&data.content.clone(),
&local_site_to_slur_regex(&local_site),
);
let content = process_markdown(&data.content, &local_site_to_slur_regex(&local_site)).await?;
is_valid_body_field(&Some(content.clone()), false)?;
// Check for a community ban

View file

@ -5,7 +5,7 @@ use lemmy_api_common::{
comment::{CommentResponse, EditComment},
context::LemmyContext,
send_activity::{ActivityChannel, SendActivityData},
utils::{check_community_user_action, local_site_to_slur_regex},
utils::{check_community_user_action, local_site_to_slur_regex, process_markdown_opt},
};
use lemmy_db_schema::{
source::{
@ -19,11 +19,7 @@ use lemmy_db_schema::{
use lemmy_db_views::structs::{CommentView, LocalUserView};
use lemmy_utils::{
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
utils::{
mention::scrape_text_for_mentions,
slurs::remove_slurs,
validation::is_valid_body_field,
},
utils::{mention::scrape_text_for_mentions, validation::is_valid_body_field},
};
#[tracing::instrument(skip(context))]
@ -57,11 +53,7 @@ pub async fn update_comment(
)
.await?;
// Update the Content
let content = data
.content
.as_ref()
.map(|c| remove_slurs(c, &local_site_to_slur_regex(&local_site)));
let content = process_markdown_opt(&data.content, &local_site_to_slur_regex(&local_site)).await?;
is_valid_body_field(&content, false)?;
let comment_id = data.comment_id;

View file

@ -11,6 +11,7 @@ use lemmy_api_common::{
generate_shared_inbox_url,
is_admin,
local_site_to_slur_regex,
process_markdown_opt,
EndpointType,
},
};
@ -33,7 +34,7 @@ use lemmy_db_views::structs::{LocalUserView, SiteView};
use lemmy_utils::{
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
utils::{
slurs::{check_slurs, check_slurs_opt},
slurs::check_slurs,
validation::{is_valid_actor_name, is_valid_body_field},
},
};
@ -58,7 +59,7 @@ pub async fn create_community(
let slur_regex = local_site_to_slur_regex(&local_site);
check_slurs(&data.name, &slur_regex)?;
check_slurs(&data.title, &slur_regex)?;
check_slurs_opt(&data.description, &slur_regex)?;
let description = process_markdown_opt(&data.description, &slur_regex).await?;
is_valid_actor_name(&data.name, local_site.actor_name_max_length as usize)?;
is_valid_body_field(&data.description, false)?;
@ -81,7 +82,7 @@ pub async fn create_community(
let community_form = CommunityInsertForm::builder()
.name(data.name.clone())
.title(data.title.clone())
.description(data.description.clone())
.description(description)
.icon(icon)
.banner(banner)
.nsfw(data.nsfw)

View file

@ -5,7 +5,7 @@ use lemmy_api_common::{
community::{CommunityResponse, EditCommunity},
context::LemmyContext,
send_activity::{ActivityChannel, SendActivityData},
utils::{check_community_mod_action, local_site_to_slur_regex},
utils::{check_community_mod_action, local_site_to_slur_regex, process_markdown_opt},
};
use lemmy_db_schema::{
source::{
@ -32,12 +32,12 @@ pub async fn update_community(
let slur_regex = local_site_to_slur_regex(&local_site);
check_slurs_opt(&data.title, &slur_regex)?;
check_slurs_opt(&data.description, &slur_regex)?;
let description = process_markdown_opt(&data.description, &slur_regex).await?;
is_valid_body_field(&data.description, false)?;
let icon = diesel_option_overwrite_to_url(&data.icon)?;
let banner = diesel_option_overwrite_to_url(&data.banner)?;
let description = diesel_option_overwrite(data.description.clone());
let description = diesel_option_overwrite(description);
// Verify its a mod (only mods can edit it)
check_community_mod_action(

View file

@ -12,6 +12,7 @@ use lemmy_api_common::{
honeypot_check,
local_site_to_slur_regex,
mark_post_as_read,
process_markdown_opt,
EndpointType,
},
};
@ -31,7 +32,7 @@ use lemmy_utils::{
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
spawn_try_task,
utils::{
slurs::{check_slurs, check_slurs_opt},
slurs::check_slurs,
validation::{check_url_scheme, clean_url_params, is_valid_body_field, is_valid_post_title},
},
};
@ -49,14 +50,14 @@ pub async fn create_post(
let slur_regex = local_site_to_slur_regex(&local_site);
check_slurs(&data.name, &slur_regex)?;
check_slurs_opt(&data.body, &slur_regex)?;
let body = process_markdown_opt(&data.body, &slur_regex).await?;
honeypot_check(&data.honeypot)?;
let data_url = data.url.as_ref();
let url = data_url.map(clean_url_params).map(Into::into); // TODO no good way to handle a "clear"
is_valid_post_title(&data.name)?;
is_valid_body_field(&data.body, true)?;
is_valid_body_field(&body, true)?;
check_url_scheme(&data.url)?;
check_community_user_action(
@ -113,7 +114,7 @@ pub async fn create_post(
let post_form = PostInsertForm::builder()
.name(data.name.trim().to_string())
.url(url)
.body(data.body.clone())
.body(body)
.community_id(data.community_id)
.creator_id(local_user_view.person.id)
.nsfw(data.nsfw)

View file

@ -6,7 +6,7 @@ use lemmy_api_common::{
post::{EditPost, PostResponse},
request::fetch_site_data,
send_activity::{ActivityChannel, SendActivityData},
utils::{check_community_user_action, local_site_to_slur_regex},
utils::{check_community_user_action, local_site_to_slur_regex, process_markdown_opt},
};
use lemmy_db_schema::{
source::{
@ -43,13 +43,13 @@ pub async fn update_post(
let slur_regex = local_site_to_slur_regex(&local_site);
check_slurs_opt(&data.name, &slur_regex)?;
check_slurs_opt(&data.body, &slur_regex)?;
let body = process_markdown_opt(&data.body, &slur_regex).await?;
if let Some(name) = &data.name {
is_valid_post_title(name)?;
}
is_valid_body_field(&data.body, true)?;
is_valid_body_field(&body, true)?;
check_url_scheme(&data.url)?;
let post_id = data.post_id;
@ -86,7 +86,7 @@ pub async fn update_post(
let post_form = PostUpdateForm {
name: data.name.clone(),
url,
body: diesel_option_overwrite(data.body.clone()),
body: diesel_option_overwrite(body),
nsfw: data.nsfw,
embed_title,
embed_description,

View file

@ -9,6 +9,7 @@ use lemmy_api_common::{
generate_local_apub_endpoint,
get_interface_language,
local_site_to_slur_regex,
process_markdown,
send_email_to_user,
EndpointType,
},
@ -23,7 +24,7 @@ use lemmy_db_schema::{
use lemmy_db_views::structs::{LocalUserView, PrivateMessageView};
use lemmy_utils::{
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
utils::{markdown::markdown_to_html, slurs::remove_slurs, validation::is_valid_body_field},
utils::{markdown::markdown_to_html, validation::is_valid_body_field},
};
#[tracing::instrument(skip(context))]
@ -34,7 +35,7 @@ pub async fn create_private_message(
) -> Result<Json<PrivateMessageResponse>, LemmyError> {
let local_site = LocalSite::read(&mut context.pool()).await?;
let content = remove_slurs(&data.content, &local_site_to_slur_regex(&local_site));
let content = process_markdown(&data.content, &local_site_to_slur_regex(&local_site)).await?;
is_valid_body_field(&Some(content.clone()), false)?;
check_person_block(

View file

@ -4,7 +4,7 @@ use lemmy_api_common::{
context::LemmyContext,
private_message::{EditPrivateMessage, PrivateMessageResponse},
send_activity::{ActivityChannel, SendActivityData},
utils::local_site_to_slur_regex,
utils::{local_site_to_slur_regex, process_markdown},
};
use lemmy_db_schema::{
source::{
@ -17,7 +17,7 @@ use lemmy_db_schema::{
use lemmy_db_views::structs::{LocalUserView, PrivateMessageView};
use lemmy_utils::{
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
utils::{slurs::remove_slurs, validation::is_valid_body_field},
utils::validation::is_valid_body_field,
};
#[tracing::instrument(skip(context))]
@ -36,7 +36,7 @@ pub async fn update_private_message(
}
// Doing the update
let content = remove_slurs(&data.content, &local_site_to_slur_regex(&local_site));
let content = process_markdown(&data.content, &local_site_to_slur_regex(&local_site)).await?;
is_valid_body_field(&Some(content.clone()), false)?;
let private_message_id = data.private_message_id;

View file

@ -4,7 +4,13 @@ use actix_web::web::{Data, Json};
use lemmy_api_common::{
context::LemmyContext,
site::{CreateSite, SiteResponse},
utils::{generate_site_inbox_url, is_admin, local_site_rate_limit_to_rate_limit_config},
utils::{
generate_site_inbox_url,
is_admin,
local_site_rate_limit_to_rate_limit_config,
local_site_to_slur_regex,
process_markdown_opt,
},
};
use lemmy_db_schema::{
newtypes::DbUrl,
@ -50,9 +56,11 @@ pub async fn create_site(
let inbox_url = Some(generate_site_inbox_url(&actor_id)?);
let keypair = generate_actor_keypair()?;
let sidebar = process_markdown_opt(&data.sidebar, &local_site_to_slur_regex(&local_site)).await?;
let site_form = SiteUpdateForm {
name: Some(data.name.clone()),
sidebar: diesel_option_overwrite(data.sidebar.clone()),
sidebar: diesel_option_overwrite(sidebar),
description: diesel_option_overwrite(data.description.clone()),
icon: diesel_option_overwrite_to_url(&data.icon)?,
banner: diesel_option_overwrite_to_url(&data.banner)?,

View file

@ -3,7 +3,12 @@ use actix_web::web::{Data, Json};
use lemmy_api_common::{
context::LemmyContext,
site::{EditSite, SiteResponse},
utils::{is_admin, local_site_rate_limit_to_rate_limit_config},
utils::{
is_admin,
local_site_rate_limit_to_rate_limit_config,
local_site_to_slur_regex,
process_markdown_opt,
},
};
use lemmy_db_schema::{
source::{
@ -54,9 +59,11 @@ pub async fn update_site(
SiteLanguage::update(&mut context.pool(), discussion_languages.clone(), &site).await?;
}
let sidebar = process_markdown_opt(&data.sidebar, &local_site_to_slur_regex(&local_site)).await?;
let site_form = SiteUpdateForm {
name: data.name.clone(),
sidebar: diesel_option_overwrite(data.sidebar.clone()),
sidebar: diesel_option_overwrite(sidebar),
description: diesel_option_overwrite(data.description.clone()),
icon: diesel_option_overwrite_to_url(&data.icon)?,
banner: diesel_option_overwrite_to_url(&data.banner)?,

View file

@ -16,7 +16,10 @@ use activitypub_federation::{
traits::Object,
};
use chrono::{DateTime, Utc};
use lemmy_api_common::{context::LemmyContext, utils::local_site_opt_to_slur_regex};
use lemmy_api_common::{
context::LemmyContext,
utils::{local_site_opt_to_slur_regex, process_markdown},
};
use lemmy_db_schema::{
source::{
comment::{Comment, CommentInsertForm, CommentUpdateForm},
@ -29,7 +32,7 @@ use lemmy_db_schema::{
};
use lemmy_utils::{
error::{LemmyError, LemmyErrorType},
utils::{markdown::markdown_to_html, slurs::remove_slurs},
utils::markdown::markdown_to_html,
};
use std::ops::Deref;
use url::Url;
@ -158,7 +161,7 @@ impl Object for ApubComment {
let local_site = LocalSite::read(&mut context.pool()).await.ok();
let slur_regex = &local_site_opt_to_slur_regex(&local_site);
let content = remove_slurs(&content, slur_regex);
let content = process_markdown(&content, slur_regex).await?;
let language_id =
LanguageTag::to_language_id_single(note.language, &mut context.pool()).await?;

View file

@ -2,7 +2,7 @@ use crate::{
activities::GetActorType,
check_apub_id_valid,
local_site_data_cached,
objects::instance::fetch_instance_actor_for_object,
objects::{instance::fetch_instance_actor_for_object, read_from_string_or_source_opt},
protocol::{
objects::{group::Group, Endpoints, LanguageTag},
ImageObject,
@ -17,15 +17,23 @@ use activitypub_federation::{
use chrono::{DateTime, Utc};
use lemmy_api_common::{
context::LemmyContext,
utils::{generate_featured_url, generate_moderators_url, generate_outbox_url},
utils::{
generate_featured_url,
generate_moderators_url,
generate_outbox_url,
local_site_opt_to_slur_regex,
process_markdown_opt,
},
};
use lemmy_db_schema::{
source::{
activity::ActorType,
actor_language::CommunityLanguage,
community::{Community, CommunityUpdateForm},
community::{Community, CommunityInsertForm, CommunityUpdateForm},
local_site::LocalSite,
},
traits::{ApubActor, Crud},
utils::naive_now,
};
use lemmy_db_views_actor::structs::CommunityFollowerView;
use lemmy_utils::{error::LemmyError, utils::markdown::markdown_to_html};
@ -131,7 +139,36 @@ impl Object for ApubCommunity {
) -> Result<ApubCommunity, LemmyError> {
let instance_id = fetch_instance_actor_for_object(&group.id, context).await?;
let form = Group::into_insert_form(group.clone(), instance_id);
let local_site = LocalSite::read(&mut context.pool()).await.ok();
let slur_regex = &local_site_opt_to_slur_regex(&local_site);
let description = read_from_string_or_source_opt(&group.summary, &None, &group.source);
let description = process_markdown_opt(&description, slur_regex).await?;
let form = CommunityInsertForm {
name: group.preferred_username.clone(),
title: group.name.unwrap_or(group.preferred_username.clone()),
description,
removed: None,
published: group.published,
updated: group.updated,
deleted: Some(false),
nsfw: Some(group.sensitive.unwrap_or(false)),
actor_id: Some(group.id.into()),
local: Some(false),
private_key: None,
hidden: None,
public_key: group.public_key.public_key_pem,
last_refreshed_at: Some(naive_now()),
icon: group.icon.map(|i| i.url.into()),
banner: group.image.map(|i| i.url.into()),
followers_url: Some(group.followers.clone().into()),
inbox_url: Some(group.inbox.into()),
shared_inbox_url: group.endpoints.map(|e| e.shared_inbox.into()),
moderators_url: group.attributed_to.clone().map(Into::into),
posting_restricted_to_mods: group.posting_restricted_to_mods,
instance_id,
featured_url: group.featured.map(Into::into),
};
let languages =
LanguageTag::to_language_id_multiple(group.language, &mut context.pool()).await?;

View file

@ -17,13 +17,17 @@ use activitypub_federation::{
traits::{Actor, Object},
};
use chrono::{DateTime, Utc};
use lemmy_api_common::{context::LemmyContext, utils::local_site_opt_to_slur_regex};
use lemmy_api_common::{
context::LemmyContext,
utils::{local_site_opt_to_slur_regex, process_markdown_opt},
};
use lemmy_db_schema::{
newtypes::InstanceId,
source::{
activity::ActorType,
actor_language::SiteLanguage,
instance::Instance as DbInstance,
local_site::LocalSite,
site::{Site, SiteInsertForm},
},
traits::Crud,
@ -130,7 +134,10 @@ impl Object for ApubSite {
let domain = apub.id.inner().domain().expect("group id has domain");
let instance = DbInstance::read_or_create(&mut data.pool(), domain.to_string()).await?;
let local_site = LocalSite::read(&mut data.pool()).await.ok();
let slur_regex = &local_site_opt_to_slur_regex(&local_site);
let sidebar = read_from_string_or_source_opt(&apub.content, &None, &apub.source);
let sidebar = process_markdown_opt(&sidebar, slur_regex).await?;
let site_form = SiteInsertForm {
name: apub.name.clone(),

View file

@ -20,11 +20,12 @@ use activitypub_federation::{
use chrono::{DateTime, Utc};
use lemmy_api_common::{
context::LemmyContext,
utils::{generate_outbox_url, local_site_opt_to_slur_regex},
utils::{generate_outbox_url, local_site_opt_to_slur_regex, process_markdown_opt},
};
use lemmy_db_schema::{
source::{
activity::ActorType,
local_site::LocalSite,
person::{Person as DbPerson, PersonInsertForm, PersonUpdateForm},
},
traits::{ApubActor, Crud},
@ -144,7 +145,10 @@ impl Object for ApubPerson {
) -> Result<ApubPerson, LemmyError> {
let instance_id = fetch_instance_actor_for_object(&person.id, context).await?;
let local_site = LocalSite::read(&mut context.pool()).await.ok();
let slur_regex = &local_site_opt_to_slur_regex(&local_site);
let bio = read_from_string_or_source_opt(&person.summary, &None, &person.source);
let bio = process_markdown_opt(&bio, slur_regex).await?;
// Some Mastodon users have `name: ""` (empty string), need to convert that to `None`
// https://github.com/mastodon/mastodon/issues/25233

View file

@ -25,7 +25,12 @@ use html2text::{from_read_with_decorator, render::text_renderer::TrivialDecorato
use lemmy_api_common::{
context::LemmyContext,
request::fetch_site_data,
utils::{is_mod_or_admin, local_site_opt_to_sensitive, local_site_opt_to_slur_regex},
utils::{
is_mod_or_admin,
local_site_opt_to_sensitive,
local_site_opt_to_slur_regex,
process_markdown_opt,
},
};
use lemmy_db_schema::{
self,
@ -40,11 +45,7 @@ use lemmy_db_schema::{
};
use lemmy_utils::{
error::LemmyError,
utils::{
markdown::markdown_to_html,
slurs::{check_slurs_opt, remove_slurs},
validation::check_url_scheme,
},
utils::{markdown::markdown_to_html, slurs::check_slurs_opt, validation::check_url_scheme},
};
use std::ops::Deref;
use stringreader::StringReader;
@ -235,8 +236,8 @@ impl Object for ApubPost {
.unwrap_or_default();
let slur_regex = &local_site_opt_to_slur_regex(&local_site);
let body = read_from_string_or_source_opt(&page.content, &page.media_type, &page.source)
.map(|s| remove_slurs(&s, slur_regex));
let body = read_from_string_or_source_opt(&page.content, &page.media_type, &page.source);
let body = process_markdown_opt(&body, slur_regex).await?;
let language_id =
LanguageTag::to_language_id_single(page.language, &mut context.pool()).await?;

View file

@ -12,9 +12,13 @@ use activitypub_federation::{
traits::Object,
};
use chrono::{DateTime, Utc};
use lemmy_api_common::{context::LemmyContext, utils::check_person_block};
use lemmy_api_common::{
context::LemmyContext,
utils::{check_person_block, local_site_opt_to_slur_regex, process_markdown},
};
use lemmy_db_schema::{
source::{
local_site::LocalSite,
person::Person,
private_message::{PrivateMessage, PrivateMessageInsertForm},
},
@ -121,7 +125,10 @@ impl Object for ApubPrivateMessage {
let recipient = note.to[0].dereference(context).await?;
check_person_block(creator.id, recipient.id, &mut context.pool()).await?;
let local_site = LocalSite::read(&mut context.pool()).await.ok();
let slur_regex = &local_site_opt_to_slur_regex(&local_site);
let content = read_from_string_or_source(&note.content, &None, &note.source);
let content = process_markdown(&content, slur_regex).await?;
let form = PrivateMessageInsertForm {
creator_id: creator.id,

View file

@ -25,11 +25,7 @@ use activitypub_federation::{
};
use chrono::{DateTime, Utc};
use lemmy_api_common::{context::LemmyContext, utils::local_site_opt_to_slur_regex};
use lemmy_db_schema::{
newtypes::InstanceId,
source::community::{CommunityInsertForm, CommunityUpdateForm},
utils::naive_now,
};
use lemmy_db_schema::{source::community::CommunityUpdateForm, utils::naive_now};
use lemmy_utils::{
error::LemmyError,
utils::slurs::{check_slurs, check_slurs_opt},
@ -94,36 +90,6 @@ impl Group {
Ok(())
}
pub(crate) fn into_insert_form(self, instance_id: InstanceId) -> CommunityInsertForm {
let description = read_from_string_or_source_opt(&self.summary, &None, &self.source);
CommunityInsertForm {
name: self.preferred_username.clone(),
title: self.name.unwrap_or(self.preferred_username.clone()),
description,
removed: None,
published: self.published,
updated: self.updated,
deleted: Some(false),
nsfw: Some(self.sensitive.unwrap_or(false)),
actor_id: Some(self.id.into()),
local: Some(false),
private_key: None,
hidden: None,
public_key: self.public_key.public_key_pem,
last_refreshed_at: Some(naive_now()),
icon: self.icon.map(|i| i.url.into()),
banner: self.image.map(|i| i.url.into()),
followers_url: Some(self.followers.into()),
inbox_url: Some(self.inbox.into()),
shared_inbox_url: self.endpoints.map(|e| e.shared_inbox.into()),
moderators_url: self.attributed_to.map(Into::into),
posting_restricted_to_mods: self.posting_restricted_to_mods,
instance_id,
featured_url: self.featured.map(Into::into),
}
}
pub(crate) fn into_update_form(self) -> CommunityUpdateForm {
CommunityUpdateForm {
title: Some(self.name.unwrap_or(self.preferred_username)),

View file

@ -60,7 +60,7 @@ pub fn markdown_rewrite_image_links(mut src: String) -> String {
let proxied = format!(
"{}/api/v3/image_proxy?url={}",
SETTINGS.get_protocol_and_hostname(),
encode(&url)
encode(url)
);
src.replace_range(start..end, &proxied);
}