Initial shared instances backend (#3800)

* Create base shared instance migration and initial routes

* Fix build

* Add version uploads

* Add permissions field for shared instance users

* Actually use permissions field

* Add "public" flag to shared instances that allow GETing them without authorization

* Add the ability to get and list shared instance versions

* Add the ability to delete shared instance versions

* Fix build after merge

* Secured file hosting (#3784)

* Remove Backblaze-specific file-hosting backend

* Added S3_USES_PATH_STYLE_BUCKETS

* Remove unused file_id parameter from delete_file_version

* Add support for separate public and private buckets in labrinth::file_hosting

* Rename delete_file_version to delete_file

* Add (untested) get_url_for_private_file

* Remove url field from shared instance routes

* Remove url field from shared instance routes

* Use private bucket for shared instance versions

* Make S3 environment variables fully separate between public and private buckets

* Change file host expiry for shared instances to 180 seconds

* Fix lint

* Merge shared instance migrations into a single migration

* Replace shared instance owners with Ghost instead of deleting the instance
This commit is contained in:
Josiah Glosson
2025-06-19 14:46:12 -05:00
committed by GitHub
parent d4864deac5
commit cc34e69524
61 changed files with 2161 additions and 491 deletions

View File

@@ -1,7 +1,7 @@
use crate::database;
use crate::database::models::image_item;
use crate::database::redis::RedisPool;
use crate::file_hosting::FileHost;
use crate::file_hosting::{FileHost, FileHostPublicity};
use crate::models::images::ImageContext;
use crate::routes::ApiError;
use color_thief::ColorFormat;
@@ -38,11 +38,14 @@ pub struct UploadImageResult {
pub raw_url: String,
pub raw_url_path: String,
pub publicity: FileHostPublicity,
pub color: Option<u32>,
}
pub async fn upload_image_optimized(
upload_folder: &str,
publicity: FileHostPublicity,
bytes: bytes::Bytes,
file_extension: &str,
target_width: Option<u32>,
@@ -80,6 +83,7 @@ pub async fn upload_image_optimized(
target_width.unwrap_or(0),
processed_image_ext
),
publicity,
processed_image,
)
.await?,
@@ -92,6 +96,7 @@ pub async fn upload_image_optimized(
.upload_file(
content_type,
&format!("{upload_folder}/{hash}.{file_extension}"),
publicity,
bytes,
)
.await?;
@@ -107,6 +112,9 @@ pub async fn upload_image_optimized(
raw_url: url,
raw_url_path: upload_data.file_name,
publicity,
color,
})
}
@@ -165,6 +173,7 @@ fn convert_to_webp(img: &DynamicImage) -> Result<Vec<u8>, ImageError> {
pub async fn delete_old_images(
image_url: Option<String>,
raw_image_url: Option<String>,
publicity: FileHostPublicity,
file_host: &dyn FileHost,
) -> Result<(), ApiError> {
let cdn_url = dotenvy::var("CDN_URL")?;
@@ -173,7 +182,7 @@ pub async fn delete_old_images(
let name = image_url.split(&cdn_url_start).nth(1);
if let Some(icon_path) = name {
file_host.delete_file_version("", icon_path).await?;
file_host.delete_file(icon_path, publicity).await?;
}
}
@@ -181,7 +190,7 @@ pub async fn delete_old_images(
let name = raw_image_url.split(&cdn_url_start).nth(1);
if let Some(icon_path) = name {
file_host.delete_file_version("", icon_path).await?;
file_host.delete_file(icon_path, publicity).await?;
}
}