Creating a LocalImageView, so that front ends have the Person struct. (#4631)

* Creating a LocalImageView, so that front ends have the Person struct.

* Removing local_user from LocalImageView.

* Add uploader check.
This commit is contained in:
Dessalines 2024-04-16 19:20:44 -04:00 committed by GitHub
parent d075acce43
commit 6efab9aab1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 2089 additions and 1662 deletions

View file

@ -6,6 +6,7 @@
"repository": "https://github.com/LemmyNet/lemmy", "repository": "https://github.com/LemmyNet/lemmy",
"author": "Dessalines", "author": "Dessalines",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"packageManager": "pnpm@9.0.1+sha256.46d50ee2afecb42b185ebbd662dc7bdd52ef5be56bf035bb615cab81a75345df",
"scripts": { "scripts": {
"lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src && prettier --check 'src/**/*.ts'", "lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src && prettier --check 'src/**/*.ts'",
"fix": "prettier --write src && eslint --fix src", "fix": "prettier --write src && eslint --fix src",
@ -27,7 +28,7 @@
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-plugin-prettier": "^5.1.3", "eslint-plugin-prettier": "^5.1.3",
"jest": "^29.5.0", "jest": "^29.5.0",
"lemmy-js-client": "0.19.4-alpha.16", "lemmy-js-client": "0.19.4-alpha.18",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"ts-jest": "^29.1.0", "ts-jest": "^29.1.0",
"typescript": "^5.4.4" "typescript": "^5.4.4"

File diff suppressed because it is too large Load diff

View file

@ -71,9 +71,14 @@ test("Upload image and delete it", async () => {
// The deleteUrl is a combination of the endpoint, delete token, and alias // The deleteUrl is a combination of the endpoint, delete token, and alias
let firstImage = listMediaRes.images[0]; let firstImage = listMediaRes.images[0];
let deleteUrl = `${alphaUrl}/pictrs/image/delete/${firstImage.pictrs_delete_token}/${firstImage.pictrs_alias}`; let deleteUrl = `${alphaUrl}/pictrs/image/delete/${firstImage.local_image.pictrs_delete_token}/${firstImage.local_image.pictrs_alias}`;
expect(deleteUrl).toBe(upload.delete_url); expect(deleteUrl).toBe(upload.delete_url);
// Make sure the uploader is correct
expect(firstImage.person.actor_id).toBe(
`http://lemmy-alpha:8541/u/lemmy_alpha`,
);
// delete image // delete image
const delete_form: DeleteImage = { const delete_form: DeleteImage = {
token: upload.files![0].delete_token, token: upload.files![0].delete_token,

View file

@ -887,8 +887,8 @@ export async function deleteAllImages(api: LemmyHttp) {
for (const image of imagesRes.images) { for (const image of imagesRes.images) {
const form: DeleteImage = { const form: DeleteImage = {
token: image.pictrs_delete_token, token: image.local_image.pictrs_delete_token,
filename: image.pictrs_alias, filename: image.local_image.pictrs_alias,
}; };
await api.deleteImage(form); await api.deleteImage(form);
} }

View file

@ -3,8 +3,7 @@ use lemmy_api_common::{
context::LemmyContext, context::LemmyContext,
person::{ListMedia, ListMediaResponse}, person::{ListMedia, ListMediaResponse},
}; };
use lemmy_db_schema::source::images::LocalImage; use lemmy_db_views::structs::{LocalImageView, LocalUserView};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyResult; use lemmy_utils::error::LemmyResult;
#[tracing::instrument(skip(context))] #[tracing::instrument(skip(context))]
@ -15,7 +14,7 @@ pub async fn list_media(
) -> LemmyResult<Json<ListMediaResponse>> { ) -> LemmyResult<Json<ListMediaResponse>> {
let page = data.page; let page = data.page;
let limit = data.limit; let limit = data.limit;
let images = LocalImage::get_all_paged_by_local_user_id( let images = LocalImageView::get_all_paged_by_local_user_id(
&mut context.pool(), &mut context.pool(),
local_user_view.local_user.id, local_user_view.local_user.id,
page, page,

View file

@ -4,8 +4,7 @@ use lemmy_api_common::{
person::{ListMedia, ListMediaResponse}, person::{ListMedia, ListMediaResponse},
utils::is_admin, utils::is_admin,
}; };
use lemmy_db_schema::source::images::LocalImage; use lemmy_db_views::structs::{LocalImageView, LocalUserView};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyResult; use lemmy_utils::error::LemmyResult;
#[tracing::instrument(skip(context))] #[tracing::instrument(skip(context))]
@ -19,6 +18,6 @@ pub async fn list_all_media(
let page = data.page; let page = data.page;
let limit = data.limit; let limit = data.limit;
let images = LocalImage::get_all(&mut context.pool(), page, limit).await?; let images = LocalImageView::get_all(&mut context.pool(), page, limit).await?;
Ok(Json(ListMediaResponse { images })) Ok(Json(ListMediaResponse { images }))
} }

View file

@ -1,13 +1,13 @@
use crate::sensitive::Sensitive; use crate::sensitive::Sensitive;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::{CommentReplyId, CommunityId, LanguageId, PersonId, PersonMentionId}, newtypes::{CommentReplyId, CommunityId, LanguageId, PersonId, PersonMentionId},
source::{images::LocalImage, site::Site}, source::site::Site,
CommentSortType, CommentSortType,
ListingType, ListingType,
PostListingMode, PostListingMode,
SortType, SortType,
}; };
use lemmy_db_views::structs::{CommentView, PostView}; use lemmy_db_views::structs::{CommentView, LocalImageView, PostView};
use lemmy_db_views_actor::structs::{ use lemmy_db_views_actor::structs::{
CommentReplyView, CommentReplyView,
CommunityModeratorView, CommunityModeratorView,
@ -437,5 +437,5 @@ pub struct ListMedia {
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
pub struct ListMediaResponse { pub struct ListMediaResponse {
pub images: Vec<LocalImage>, pub images: Vec<LocalImageView>,
} }

View file

@ -12,7 +12,7 @@ use lemmy_db_schema::{
community::{Community, CommunityModerator, CommunityUpdateForm}, community::{Community, CommunityModerator, CommunityUpdateForm},
community_block::CommunityBlock, community_block::CommunityBlock,
email_verification::{EmailVerification, EmailVerificationForm}, email_verification::{EmailVerification, EmailVerificationForm},
images::{LocalImage, RemoteImage}, images::RemoteImage,
instance::Instance, instance::Instance,
instance_block::InstanceBlock, instance_block::InstanceBlock,
local_site::LocalSite, local_site::LocalSite,
@ -27,7 +27,10 @@ use lemmy_db_schema::{
traits::Crud, traits::Crud,
utils::DbPool, utils::DbPool,
}; };
use lemmy_db_views::{comment_view::CommentQuery, structs::LocalUserView}; use lemmy_db_views::{
comment_view::CommentQuery,
structs::{LocalImageView, LocalUserView},
};
use lemmy_db_views_actor::structs::{ use lemmy_db_views_actor::structs::{
CommunityModeratorView, CommunityModeratorView,
CommunityPersonBanView, CommunityPersonBanView,
@ -662,11 +665,16 @@ pub async fn purge_image_posts_for_person(
async fn delete_local_user_images(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> { async fn delete_local_user_images(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> {
if let Ok(Some(local_user)) = LocalUserView::read_person(&mut context.pool(), person_id).await { if let Ok(Some(local_user)) = LocalUserView::read_person(&mut context.pool(), person_id).await {
let pictrs_uploads = let pictrs_uploads =
LocalImage::get_all_by_local_user_id(&mut context.pool(), local_user.local_user.id).await?; LocalImageView::get_all_by_local_user_id(&mut context.pool(), local_user.local_user.id)
.await?;
// Delete their images // Delete their images
for upload in pictrs_uploads { for upload in pictrs_uploads {
delete_image_from_pictrs(&upload.pictrs_alias, &upload.pictrs_delete_token, context) delete_image_from_pictrs(
&upload.local_image.pictrs_alias,
&upload.local_image.pictrs_delete_token,
context,
)
.await .await
.ok(); .ok();
} }

View file

@ -1,8 +1,8 @@
use crate::{ use crate::{
newtypes::{DbUrl, LocalUserId}, newtypes::DbUrl,
schema::{local_image, remote_image}, schema::{local_image, remote_image},
source::images::{LocalImage, LocalImageForm, RemoteImage, RemoteImageForm}, source::images::{LocalImage, LocalImageForm, RemoteImage, RemoteImageForm},
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, DbPool},
}; };
use diesel::{ use diesel::{
dsl::exists, dsl::exists,
@ -25,55 +25,6 @@ impl LocalImage {
.await .await
} }
pub async fn get_all_paged_by_local_user_id(
pool: &mut DbPool<'_>,
user_id: LocalUserId,
page: Option<i64>,
limit: Option<i64>,
) -> Result<Vec<Self>, Error> {
Self::get_all_helper(pool, Some(user_id), page, limit, false).await
}
pub async fn get_all_by_local_user_id(
pool: &mut DbPool<'_>,
user_id: LocalUserId,
) -> Result<Vec<Self>, Error> {
Self::get_all_helper(pool, Some(user_id), None, None, true).await
}
pub async fn get_all(
pool: &mut DbPool<'_>,
page: Option<i64>,
limit: Option<i64>,
) -> Result<Vec<Self>, Error> {
Self::get_all_helper(pool, None, page, limit, false).await
}
async fn get_all_helper(
pool: &mut DbPool<'_>,
user_id: Option<LocalUserId>,
page: Option<i64>,
limit: Option<i64>,
ignore_page_limits: bool,
) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let mut query = local_image::table
.select(local_image::all_columns)
.order_by(local_image::published.desc())
.into_boxed();
if let Some(user_id) = user_id {
query = query.filter(local_image::local_user_id.eq(user_id))
}
if !ignore_page_limits {
let (limit, offset) = limit_and_offset(page, limit)?;
query = query.limit(limit).offset(offset);
}
query.load::<LocalImage>(conn).await
}
pub async fn delete_by_alias(pool: &mut DbPool<'_>, alias: &str) -> Result<Self, Error> { pub async fn delete_by_alias(pool: &mut DbPool<'_>, alias: &str) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
diesel::delete(local_image::table.filter(local_image::pictrs_alias.eq(alias))) diesel::delete(local_image::table.filter(local_image::pictrs_alias.eq(alias)))

View file

@ -8,6 +8,8 @@ pub mod comment_view;
#[cfg(feature = "full")] #[cfg(feature = "full")]
pub mod custom_emoji_view; pub mod custom_emoji_view;
#[cfg(feature = "full")] #[cfg(feature = "full")]
pub mod local_image_view;
#[cfg(feature = "full")]
pub mod local_user_view; pub mod local_user_view;
#[cfg(feature = "full")] #[cfg(feature = "full")]
pub mod post_report_view; pub mod post_report_view;

View file

@ -0,0 +1,61 @@
use crate::structs::LocalImageView;
use diesel::{result::Error, ExpressionMethods, JoinOnDsl, QueryDsl};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::LocalUserId,
schema::{local_image, local_user, person},
utils::{get_conn, limit_and_offset, DbPool},
};
impl LocalImageView {
async fn get_all_helper(
pool: &mut DbPool<'_>,
user_id: Option<LocalUserId>,
page: Option<i64>,
limit: Option<i64>,
ignore_page_limits: bool,
) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let mut query = local_image::table
.inner_join(local_user::table)
.inner_join(person::table.on(local_user::person_id.eq(person::id)))
.select((local_image::all_columns, person::all_columns))
.order_by(local_image::published.desc())
.into_boxed();
if let Some(user_id) = user_id {
query = query.filter(local_image::local_user_id.eq(user_id))
}
if !ignore_page_limits {
let (limit, offset) = limit_and_offset(page, limit)?;
query = query.limit(limit).offset(offset);
}
query.load::<LocalImageView>(conn).await
}
pub async fn get_all_paged_by_local_user_id(
pool: &mut DbPool<'_>,
user_id: LocalUserId,
page: Option<i64>,
limit: Option<i64>,
) -> Result<Vec<Self>, Error> {
Self::get_all_helper(pool, Some(user_id), page, limit, false).await
}
pub async fn get_all_by_local_user_id(
pool: &mut DbPool<'_>,
user_id: LocalUserId,
) -> Result<Vec<Self>, Error> {
Self::get_all_helper(pool, Some(user_id), None, None, true).await
}
pub async fn get_all(
pool: &mut DbPool<'_>,
page: Option<i64>,
limit: Option<i64>,
) -> Result<Vec<Self>, Error> {
Self::get_all_helper(pool, None, page, limit, false).await
}
}

View file

@ -8,6 +8,7 @@ use lemmy_db_schema::{
community::Community, community::Community,
custom_emoji::CustomEmoji, custom_emoji::CustomEmoji,
custom_emoji_keyword::CustomEmojiKeyword, custom_emoji_keyword::CustomEmojiKeyword,
images::LocalImage,
local_site::LocalSite, local_site::LocalSite,
local_site_rate_limit::LocalSiteRateLimit, local_site_rate_limit::LocalSiteRateLimit,
local_user::LocalUser, local_user::LocalUser,
@ -214,3 +215,13 @@ pub struct VoteView {
pub creator_banned_from_community: bool, pub creator_banned_from_community: bool,
pub score: i16, pub score: i16,
} }
#[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
/// A local image view.
pub struct LocalImageView {
pub local_image: LocalImage,
pub person: Person,
}