mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-27 11:51:08 +00:00
Moving alt_text to attachment name.
This commit is contained in:
parent
c5a98c5a3f
commit
c24542c7c1
10 changed files with 1123 additions and 2222 deletions
|
@ -19,16 +19,16 @@
|
||||||
"api-test-image": "jest -i image.spec.ts"
|
"api-test-image": "jest -i image.spec.ts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.5.11",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/node": "^20.10.4",
|
"@types/node": "^20.11.22",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
"@typescript-eslint/eslint-plugin": "^7.1.0",
|
||||||
"@typescript-eslint/parser": "^6.14.0",
|
"@typescript-eslint/parser": "^7.1.0",
|
||||||
"download-file-sync": "^1.0.4",
|
"download-file-sync": "^1.0.4",
|
||||||
"eslint": "^8.55.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-prettier": "^5.0.1",
|
"eslint-plugin-prettier": "^5.0.1",
|
||||||
"jest": "^29.5.0",
|
"jest": "^29.5.0",
|
||||||
"lemmy-js-client": "0.19.3-alpha.2",
|
"lemmy-js-client": "0.19.4-alpha.6",
|
||||||
"prettier": "^3.1.1",
|
"prettier": "^3.2.5",
|
||||||
"ts-jest": "^29.1.0",
|
"ts-jest": "^29.1.0",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -203,4 +203,7 @@ test("No image proxying if setting is disabled", async () => {
|
||||||
gammaPost.post!.post.url?.startsWith("http://127.0.0.1:8551/pictrs/image/"),
|
gammaPost.post!.post.url?.startsWith("http://127.0.0.1:8551/pictrs/image/"),
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
expect(gammaPost.post!.post.body).toBe("![](http://example.com/image2.png)");
|
expect(gammaPost.post!.post.body).toBe("![](http://example.com/image2.png)");
|
||||||
|
|
||||||
|
// Make sure the alt text got federated
|
||||||
|
expect(post.post_view.post.alt_text).toBe(gammaPost.post!.post.alt_text);
|
||||||
});
|
});
|
||||||
|
|
|
@ -200,11 +200,13 @@ export async function createPost(
|
||||||
body = randomString(10),
|
body = randomString(10),
|
||||||
// use example.com for consistent title and embed description
|
// use example.com for consistent title and embed description
|
||||||
name: string = randomString(5),
|
name: string = randomString(5),
|
||||||
|
alt_text = randomString(10),
|
||||||
): Promise<PostResponse> {
|
): Promise<PostResponse> {
|
||||||
let form: CreatePost = {
|
let form: CreatePost = {
|
||||||
name,
|
name,
|
||||||
url,
|
url,
|
||||||
body,
|
body,
|
||||||
|
alt_text,
|
||||||
community_id,
|
community_id,
|
||||||
};
|
};
|
||||||
return api.createPost(form);
|
return api.createPost(form);
|
||||||
|
|
|
@ -35,7 +35,13 @@ use lemmy_utils::{
|
||||||
spawn_try_task,
|
spawn_try_task,
|
||||||
utils::{
|
utils::{
|
||||||
slurs::check_slurs,
|
slurs::check_slurs,
|
||||||
validation::{check_url_scheme, clean_url_params, is_valid_body_field, is_valid_post_title},
|
validation::{
|
||||||
|
check_url_scheme,
|
||||||
|
clean_url_params,
|
||||||
|
is_valid_alt_text_field,
|
||||||
|
is_valid_body_field,
|
||||||
|
is_valid_post_title,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use tracing::Instrument;
|
use tracing::Instrument;
|
||||||
|
@ -56,7 +62,7 @@ pub async fn create_post(
|
||||||
check_slurs(&data.name, &slur_regex)?;
|
check_slurs(&data.name, &slur_regex)?;
|
||||||
|
|
||||||
let body = process_markdown_opt(&data.body, &slur_regex, &context).await?;
|
let body = process_markdown_opt(&data.body, &slur_regex, &context).await?;
|
||||||
let alt_text = process_markdown_opt(&data.alt_text, &slur_regex, &context).await?;
|
let alt_text = &data.alt_text;
|
||||||
|
|
||||||
let data_url = data.url.as_ref();
|
let data_url = data.url.as_ref();
|
||||||
let url = data_url.map(clean_url_params); // TODO no good way to handle a "clear"
|
let url = data_url.map(clean_url_params); // TODO no good way to handle a "clear"
|
||||||
|
@ -64,7 +70,7 @@ pub async fn create_post(
|
||||||
|
|
||||||
is_valid_post_title(&data.name)?;
|
is_valid_post_title(&data.name)?;
|
||||||
is_valid_body_field(&body, true)?;
|
is_valid_body_field(&body, true)?;
|
||||||
is_valid_body_field(&alt_text, false)?;
|
is_valid_alt_text_field(alt_text)?;
|
||||||
check_url_scheme(&url)?;
|
check_url_scheme(&url)?;
|
||||||
check_url_scheme(&custom_thumbnail)?;
|
check_url_scheme(&custom_thumbnail)?;
|
||||||
|
|
||||||
|
@ -128,7 +134,7 @@ pub async fn create_post(
|
||||||
.name(data.name.trim().to_string())
|
.name(data.name.trim().to_string())
|
||||||
.url(url)
|
.url(url)
|
||||||
.body(body)
|
.body(body)
|
||||||
.alt_text(alt_text)
|
.alt_text(alt_text.clone())
|
||||||
.community_id(data.community_id)
|
.community_id(data.community_id)
|
||||||
.creator_id(local_user_view.person.id)
|
.creator_id(local_user_view.person.id)
|
||||||
.nsfw(data.nsfw)
|
.nsfw(data.nsfw)
|
||||||
|
|
|
@ -27,7 +27,13 @@ use lemmy_utils::{
|
||||||
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
utils::{
|
utils::{
|
||||||
slurs::check_slurs_opt,
|
slurs::check_slurs_opt,
|
||||||
validation::{check_url_scheme, clean_url_params, is_valid_body_field, is_valid_post_title},
|
validation::{
|
||||||
|
check_url_scheme,
|
||||||
|
clean_url_params,
|
||||||
|
is_valid_alt_text_field,
|
||||||
|
is_valid_body_field,
|
||||||
|
is_valid_post_title,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -48,14 +54,14 @@ pub async fn update_post(
|
||||||
let slur_regex = local_site_to_slur_regex(&local_site);
|
let slur_regex = local_site_to_slur_regex(&local_site);
|
||||||
check_slurs_opt(&data.name, &slur_regex)?;
|
check_slurs_opt(&data.name, &slur_regex)?;
|
||||||
let body = process_markdown_opt(&data.body, &slur_regex, &context).await?;
|
let body = process_markdown_opt(&data.body, &slur_regex, &context).await?;
|
||||||
let alt_text = process_markdown_opt(&data.alt_text, &slur_regex, &context).await?;
|
let alt_text = &data.alt_text;
|
||||||
|
|
||||||
if let Some(name) = &data.name {
|
if let Some(name) = &data.name {
|
||||||
is_valid_post_title(name)?;
|
is_valid_post_title(name)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_valid_body_field(&body, true)?;
|
is_valid_body_field(&body, true)?;
|
||||||
is_valid_body_field(&alt_text, false)?;
|
is_valid_alt_text_field(alt_text)?;
|
||||||
check_url_scheme(&url)?;
|
check_url_scheme(&url)?;
|
||||||
check_url_scheme(&custom_thumbnail)?;
|
check_url_scheme(&custom_thumbnail)?;
|
||||||
|
|
||||||
|
@ -118,7 +124,7 @@ pub async fn update_post(
|
||||||
name: data.name.clone(),
|
name: data.name.clone(),
|
||||||
url,
|
url,
|
||||||
body: diesel_option_overwrite(body),
|
body: diesel_option_overwrite(body),
|
||||||
alt_text: diesel_option_overwrite(alt_text),
|
alt_text: diesel_option_overwrite(alt_text.clone()),
|
||||||
nsfw: data.nsfw,
|
nsfw: data.nsfw,
|
||||||
embed_title,
|
embed_title,
|
||||||
embed_description,
|
embed_description,
|
||||||
|
|
|
@ -115,7 +115,13 @@ impl Object for ApubPost {
|
||||||
let attachment = self
|
let attachment = self
|
||||||
.url
|
.url
|
||||||
.clone()
|
.clone()
|
||||||
.map(|url| Attachment::new(url.into(), self.url_content_type.clone()))
|
.map(|url| {
|
||||||
|
Attachment::new(
|
||||||
|
url.into(),
|
||||||
|
self.url_content_type.clone(),
|
||||||
|
self.alt_text.clone(),
|
||||||
|
)
|
||||||
|
})
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -127,7 +133,6 @@ impl Object for ApubPost {
|
||||||
cc: vec![],
|
cc: vec![],
|
||||||
name: Some(self.name.clone()),
|
name: Some(self.name.clone()),
|
||||||
content: self.body.as_ref().map(|b| markdown_to_html(b)),
|
content: self.body.as_ref().map(|b| markdown_to_html(b)),
|
||||||
alt_text: self.alt_text.as_ref().map(|b| markdown_to_html(b)),
|
|
||||||
media_type: Some(MediaTypeMarkdownOrHtml::Html),
|
media_type: Some(MediaTypeMarkdownOrHtml::Html),
|
||||||
source: self.body.clone().map(Source::new),
|
source: self.body.clone().map(Source::new),
|
||||||
attachment,
|
attachment,
|
||||||
|
@ -204,10 +209,12 @@ impl Object for ApubPost {
|
||||||
// read existing, local post if any (for generating mod log)
|
// read existing, local post if any (for generating mod log)
|
||||||
let old_post = page.id.dereference_local(context).await;
|
let old_post = page.id.dereference_local(context).await;
|
||||||
|
|
||||||
|
let first_attachment = page.attachment.first();
|
||||||
|
|
||||||
let form = if !page.is_mod_action(context).await? {
|
let form = if !page.is_mod_action(context).await? {
|
||||||
let first_attachment = page.attachment.into_iter().map(Attachment::url).next();
|
let first_attachment_url = first_attachment.cloned().map(Attachment::url);
|
||||||
let url = if first_attachment.is_some() {
|
let url = if first_attachment.is_some() {
|
||||||
first_attachment
|
first_attachment_url
|
||||||
} else if page.kind == PageType::Video {
|
} else if page.kind == PageType::Video {
|
||||||
// we cant display videos directly, so insert a link to external video page
|
// we cant display videos directly, so insert a link to external video page
|
||||||
Some(page.id.inner().clone())
|
Some(page.id.inner().clone())
|
||||||
|
@ -216,6 +223,7 @@ impl Object for ApubPost {
|
||||||
};
|
};
|
||||||
check_url_scheme(&url)?;
|
check_url_scheme(&url)?;
|
||||||
|
|
||||||
|
let alt_text = first_attachment.cloned().and_then(Attachment::alt_text);
|
||||||
let local_site = LocalSite::read(&mut context.pool()).await.ok();
|
let local_site = LocalSite::read(&mut context.pool()).await.ok();
|
||||||
let allow_sensitive = local_site_opt_to_sensitive(&local_site);
|
let allow_sensitive = local_site_opt_to_sensitive(&local_site);
|
||||||
let page_is_sensitive = page.sensitive.unwrap_or(false);
|
let page_is_sensitive = page.sensitive.unwrap_or(false);
|
||||||
|
@ -235,7 +243,6 @@ impl Object for ApubPost {
|
||||||
|
|
||||||
let body = read_from_string_or_source_opt(&page.content, &page.media_type, &page.source);
|
let body = read_from_string_or_source_opt(&page.content, &page.media_type, &page.source);
|
||||||
let body = process_markdown_opt(&body, slur_regex, context).await?;
|
let body = process_markdown_opt(&body, slur_regex, context).await?;
|
||||||
let alt_text = process_markdown_opt(&page.alt_text, slur_regex, context).await?;
|
|
||||||
let language_id =
|
let language_id =
|
||||||
LanguageTag::to_language_id_single(page.language, &mut context.pool()).await?;
|
LanguageTag::to_language_id_single(page.language, &mut context.pool()).await?;
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,6 @@ pub struct Page {
|
||||||
#[serde(deserialize_with = "deserialize_one_or_many", default)]
|
#[serde(deserialize_with = "deserialize_one_or_many", default)]
|
||||||
pub(crate) cc: Vec<Url>,
|
pub(crate) cc: Vec<Url>,
|
||||||
pub(crate) content: Option<String>,
|
pub(crate) content: Option<String>,
|
||||||
pub(crate) alt_text: Option<String>,
|
|
||||||
pub(crate) media_type: Option<MediaTypeMarkdownOrHtml>,
|
pub(crate) media_type: Option<MediaTypeMarkdownOrHtml>,
|
||||||
#[serde(deserialize_with = "deserialize_skip_error", default)]
|
#[serde(deserialize_with = "deserialize_skip_error", default)]
|
||||||
pub(crate) source: Option<Source>,
|
pub(crate) source: Option<Source>,
|
||||||
|
@ -75,6 +74,8 @@ pub(crate) struct Link {
|
||||||
href: Url,
|
href: Url,
|
||||||
media_type: Option<String>,
|
media_type: Option<String>,
|
||||||
r#type: LinkType,
|
r#type: LinkType,
|
||||||
|
/// Used for alt_text
|
||||||
|
name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
@ -83,6 +84,8 @@ pub(crate) struct Image {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
kind: ImageType,
|
kind: ImageType,
|
||||||
url: Url,
|
url: Url,
|
||||||
|
/// Used for alt_text
|
||||||
|
name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
@ -91,6 +94,8 @@ pub(crate) struct Document {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
kind: DocumentType,
|
kind: DocumentType,
|
||||||
url: Url,
|
url: Url,
|
||||||
|
/// Used for alt_text
|
||||||
|
name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
@ -112,6 +117,17 @@ impl Attachment {
|
||||||
Attachment::Document(d) => d.url,
|
Attachment::Document(d) => d.url,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn alt_text(self) -> Option<String> {
|
||||||
|
match self {
|
||||||
|
// url as sent by Lemmy (new)
|
||||||
|
Attachment::Link(l) => l.name,
|
||||||
|
// image sent by lotide
|
||||||
|
Attachment::Image(i) => i.name,
|
||||||
|
// sent by mobilizon
|
||||||
|
Attachment::Document(d) => d.name,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
@ -169,18 +185,20 @@ impl Page {
|
||||||
|
|
||||||
impl Attachment {
|
impl Attachment {
|
||||||
/// Creates new attachment for a given link and mime type.
|
/// Creates new attachment for a given link and mime type.
|
||||||
pub(crate) fn new(url: Url, media_type: Option<String>) -> Attachment {
|
pub(crate) fn new(url: Url, media_type: Option<String>, name: Option<String>) -> Attachment {
|
||||||
let is_image = media_type.clone().unwrap_or_default().starts_with("image");
|
let is_image = media_type.clone().unwrap_or_default().starts_with("image");
|
||||||
if is_image {
|
if is_image {
|
||||||
Attachment::Image(Image {
|
Attachment::Image(Image {
|
||||||
kind: Default::default(),
|
kind: Default::default(),
|
||||||
url,
|
url,
|
||||||
|
name,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Attachment::Link(Link {
|
Attachment::Link(Link {
|
||||||
href: url,
|
href: url,
|
||||||
media_type,
|
media_type,
|
||||||
r#type: Default::default(),
|
r#type: Default::default(),
|
||||||
|
name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,7 @@ pub enum LemmyErrorType {
|
||||||
InvalidPostTitle,
|
InvalidPostTitle,
|
||||||
InvalidBodyField,
|
InvalidBodyField,
|
||||||
BioLengthOverflow,
|
BioLengthOverflow,
|
||||||
|
AltTextLengthOverflow,
|
||||||
MissingTotpToken,
|
MissingTotpToken,
|
||||||
MissingTotpSecret,
|
MissingTotpSecret,
|
||||||
IncorrectTotpToken,
|
IncorrectTotpToken,
|
||||||
|
|
|
@ -19,6 +19,7 @@ const ALLOWED_POST_URL_SCHEMES: [&str; 3] = ["http", "https", "magnet"];
|
||||||
const BODY_MAX_LENGTH: usize = 10000;
|
const BODY_MAX_LENGTH: usize = 10000;
|
||||||
const POST_BODY_MAX_LENGTH: usize = 50000;
|
const POST_BODY_MAX_LENGTH: usize = 50000;
|
||||||
const BIO_MAX_LENGTH: usize = 300;
|
const BIO_MAX_LENGTH: usize = 300;
|
||||||
|
const ALT_TEXT_MAX_LENGTH: usize = 300;
|
||||||
const SITE_NAME_MAX_LENGTH: usize = 20;
|
const SITE_NAME_MAX_LENGTH: usize = 20;
|
||||||
const SITE_NAME_MIN_LENGTH: usize = 1;
|
const SITE_NAME_MIN_LENGTH: usize = 1;
|
||||||
const SITE_DESCRIPTION_MAX_LENGTH: usize = 150;
|
const SITE_DESCRIPTION_MAX_LENGTH: usize = 150;
|
||||||
|
@ -172,6 +173,18 @@ pub fn is_valid_bio_field(bio: &str) -> LemmyResult<()> {
|
||||||
max_length_check(bio, BIO_MAX_LENGTH, LemmyErrorType::BioLengthOverflow)
|
max_length_check(bio, BIO_MAX_LENGTH, LemmyErrorType::BioLengthOverflow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_valid_alt_text_field(alt_text: &Option<String>) -> LemmyResult<()> {
|
||||||
|
if let Some(alt_text) = alt_text {
|
||||||
|
max_length_check(
|
||||||
|
alt_text,
|
||||||
|
ALT_TEXT_MAX_LENGTH,
|
||||||
|
LemmyErrorType::AltTextLengthOverflow,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks the site name length, the limit as defined in the DB.
|
/// Checks the site name length, the limit as defined in the DB.
|
||||||
pub fn site_name_length_check(name: &str) -> LemmyResult<()> {
|
pub fn site_name_length_check(name: &str) -> LemmyResult<()> {
|
||||||
min_length_check(name, SITE_NAME_MIN_LENGTH, LemmyErrorType::SiteNameRequired)?;
|
min_length_check(name, SITE_NAME_MIN_LENGTH, LemmyErrorType::SiteNameRequired)?;
|
||||||
|
|
Loading…
Reference in a new issue