Added image compression
Build and Publish / Build and Publish Docker Image (push) Successful in 1m59s
Build and Publish / Build and Publish Docker Image (push) Successful in 1m59s
This commit is contained in:
Generated
+124
@@ -332,12 +332,24 @@ version = "3.20.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
|
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytemuck"
|
||||||
|
version = "1.25.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder-lite"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.11.1"
|
version = "1.11.1"
|
||||||
@@ -630,6 +642,15 @@ version = "2.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853"
|
checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-queue"
|
name = "crossbeam-queue"
|
||||||
version = "0.3.12"
|
version = "0.3.12"
|
||||||
@@ -893,12 +914,31 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fdeflate"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
|
||||||
|
dependencies = [
|
||||||
|
"simd-adler32",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "find-msvc-tools"
|
name = "find-msvc-tools"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flume"
|
name = "flume"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@@ -1434,6 +1474,32 @@ dependencies = [
|
|||||||
"icu_properties",
|
"icu_properties",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "image"
|
||||||
|
version = "0.25.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"byteorder-lite",
|
||||||
|
"image-webp",
|
||||||
|
"moxcms",
|
||||||
|
"num-traits",
|
||||||
|
"png",
|
||||||
|
"zune-core",
|
||||||
|
"zune-jpeg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "image-webp"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder-lite",
|
||||||
|
"quick-error",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.14.0"
|
version = "2.14.0"
|
||||||
@@ -1637,6 +1703,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler2",
|
"adler2",
|
||||||
|
"simd-adler32",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1650,6 +1717,16 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "moxcms"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
"pxfm",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "multer"
|
name = "multer"
|
||||||
version = "3.1.0"
|
version = "3.1.0"
|
||||||
@@ -1915,6 +1992,19 @@ version = "0.2.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "png"
|
||||||
|
version = "0.18.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"crc32fast",
|
||||||
|
"fdeflate",
|
||||||
|
"flate2",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "potential_utf"
|
name = "potential_utf"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -1967,6 +2057,18 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pxfm"
|
||||||
|
version = "0.1.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-error"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quinn"
|
name = "quinn"
|
||||||
version = "0.11.9"
|
version = "0.11.9"
|
||||||
@@ -2455,6 +2557,12 @@ dependencies = [
|
|||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simd-adler32"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@@ -3366,6 +3474,7 @@ dependencies = [
|
|||||||
"chrono-tz",
|
"chrono-tz",
|
||||||
"cot",
|
"cot",
|
||||||
"futures",
|
"futures",
|
||||||
|
"image",
|
||||||
"multer",
|
"multer",
|
||||||
"password-auth",
|
"password-auth",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
@@ -3916,3 +4025,18 @@ name = "zmij"
|
|||||||
version = "1.0.21"
|
version = "1.0.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zune-core"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zune-jpeg"
|
||||||
|
version = "0.5.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
|
||||||
|
dependencies = [
|
||||||
|
"zune-core",
|
||||||
|
]
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "web-petting"
|
name = "web-petting"
|
||||||
version = "0.1.12"
|
version = "0.1.13"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@@ -14,6 +14,7 @@ reqwest = { version = "0.12", default-features = false, features = ["rustls-tls"
|
|||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
multer = "3"
|
multer = "3"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
|
image = { version = "0.25", default-features = false, features = ["jpeg", "png", "webp"] }
|
||||||
tokio = { version = "1", features = ["fs"] }
|
tokio = { version = "1", features = ["fs"] }
|
||||||
uuid = { version = "1", features = ["v4"] }
|
uuid = { version = "1", features = ["v4"] }
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
|
|||||||
+97
-37
@@ -6,7 +6,12 @@ use cot::request::extractors::Path;
|
|||||||
use cot::response::{IntoResponse, Redirect, Response};
|
use cot::response::{IntoResponse, Redirect, Response};
|
||||||
use cot::router::{Route, Router};
|
use cot::router::{Route, Router};
|
||||||
use cot::session::Session;
|
use cot::session::Session;
|
||||||
|
use image::ImageFormat;
|
||||||
|
use image::ImageReader;
|
||||||
|
use image::codecs::jpeg::JpegEncoder;
|
||||||
|
use image::imageops::FilterType;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
use crate::i18n::{Lang, Translations};
|
use crate::i18n::{Lang, Translations};
|
||||||
use crate::models::{Client, Lead, Media, Setting, Testimonial, User, Visit};
|
use crate::models::{Client, Lead, Media, Setting, Testimonial, User, Visit};
|
||||||
@@ -14,6 +19,8 @@ use crate::telegram;
|
|||||||
|
|
||||||
const SESSION_USER_ID: &str = "user_id";
|
const SESSION_USER_ID: &str = "user_id";
|
||||||
const SESSION_USER_NAME: &str = "user_name";
|
const SESSION_USER_NAME: &str = "user_name";
|
||||||
|
const MAX_UPLOADED_IMAGE_DIMENSION: u32 = 1920;
|
||||||
|
const UPLOADED_IMAGE_JPEG_QUALITY: u8 = 82;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Helpers
|
// Helpers
|
||||||
@@ -91,12 +98,64 @@ fn has_query_flag(request: &Request, flag: &str) -> bool {
|
|||||||
fn get_query_param(request: &Request, key: &str) -> Option<String> {
|
fn get_query_param(request: &Request, key: &str) -> Option<String> {
|
||||||
let prefix = format!("{}=", key);
|
let prefix = format!("{}=", key);
|
||||||
request.uri().query().and_then(|q| {
|
request.uri().query().and_then(|q| {
|
||||||
q.split('&').find_map(|p| {
|
q.split('&')
|
||||||
p.strip_prefix(&prefix).map(|v| v.to_string())
|
.find_map(|p| p.strip_prefix(&prefix).map(|v| v.to_string()))
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn image_format_from_ext(ext: &str) -> Option<ImageFormat> {
|
||||||
|
match ext {
|
||||||
|
"jpg" | "jpeg" => Some(ImageFormat::Jpeg),
|
||||||
|
"png" => Some(ImageFormat::Png),
|
||||||
|
"webp" => Some(ImageFormat::WebP),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transcode_uploaded_image(data: &[u8], ext: &str) -> cot::Result<Option<Vec<u8>>> {
|
||||||
|
let Some(format) = image_format_from_ext(ext) else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
let image = ImageReader::with_format(Cursor::new(data), format)
|
||||||
|
.decode()
|
||||||
|
.map_err(|e| cot::Error::internal(e.to_string()))?;
|
||||||
|
let resized = image.resize(
|
||||||
|
MAX_UPLOADED_IMAGE_DIMENSION,
|
||||||
|
MAX_UPLOADED_IMAGE_DIMENSION,
|
||||||
|
FilterType::Lanczos3,
|
||||||
|
);
|
||||||
|
let rgb = resized.to_rgb8();
|
||||||
|
let mut encoded = Vec::new();
|
||||||
|
let mut encoder = JpegEncoder::new_with_quality(&mut encoded, UPLOADED_IMAGE_JPEG_QUALITY);
|
||||||
|
encoder
|
||||||
|
.encode_image(&rgb)
|
||||||
|
.map_err(|e| cot::Error::internal(e.to_string()))?;
|
||||||
|
|
||||||
|
Ok(Some(encoded))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn save_uploaded_image(
|
||||||
|
upload_dir: &str,
|
||||||
|
file_id: uuid::Uuid,
|
||||||
|
ext: &str,
|
||||||
|
data: &[u8],
|
||||||
|
) -> cot::Result<String> {
|
||||||
|
if let Some(encoded) = transcode_uploaded_image(data, ext)? {
|
||||||
|
let path = format!("{}/{}.jpg", upload_dir, file_id);
|
||||||
|
tokio::fs::write(&path, &encoded)
|
||||||
|
.await
|
||||||
|
.map_err(|e| cot::Error::internal(e.to_string()))?;
|
||||||
|
Ok(path)
|
||||||
|
} else {
|
||||||
|
let path = format!("{}/{}.{}", upload_dir, file_id, ext);
|
||||||
|
tokio::fs::write(&path, data)
|
||||||
|
.await
|
||||||
|
.map_err(|e| cot::Error::internal(e.to_string()))?;
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Soft pastel palette for client calendar colors.
|
/// Soft pastel palette for client calendar colors.
|
||||||
const CLIENT_COLORS: &[&str] = &[
|
const CLIENT_COLORS: &[&str] = &[
|
||||||
"#7c6ed4", "#5b9bd5", "#4caf93", "#e0915e", "#d46c8e", "#8e6bbf", "#5cb8a5", "#c77c4f",
|
"#7c6ed4", "#5b9bd5", "#4caf93", "#e0915e", "#d46c8e", "#8e6bbf", "#5cb8a5", "#c77c4f",
|
||||||
@@ -588,24 +647,27 @@ async fn oidc_start(request: Request, db: Database) -> cot::Result<Response> {
|
|||||||
let site_domain = oidc_setting(&db, "site_domain").await?;
|
let site_domain = oidc_setting(&db, "site_domain").await?;
|
||||||
|
|
||||||
if issuer_url.trim().is_empty() || client_id.trim().is_empty() {
|
if issuer_url.trim().is_empty() || client_id.trim().is_empty() {
|
||||||
return Redirect::new(format!("/admin/login?lang={}&error=sso_provider", lang.code()))
|
return Redirect::new(format!(
|
||||||
.into_response();
|
"/admin/login?lang={}&error=sso_provider",
|
||||||
|
lang.code()
|
||||||
|
))
|
||||||
|
.into_response();
|
||||||
}
|
}
|
||||||
|
|
||||||
let authorization_endpoint = match oidc_discover(&issuer_url, "authorization_endpoint").await {
|
let authorization_endpoint = match oidc_discover(&issuer_url, "authorization_endpoint").await {
|
||||||
Some(ep) => ep,
|
Some(ep) => ep,
|
||||||
None => {
|
None => {
|
||||||
return Redirect::new(format!("/admin/login?lang={}&error=sso_provider", lang.code()))
|
return Redirect::new(format!(
|
||||||
.into_response();
|
"/admin/login?lang={}&error=sso_provider",
|
||||||
|
lang.code()
|
||||||
|
))
|
||||||
|
.into_response();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = rand_token();
|
let state = rand_token();
|
||||||
|
|
||||||
let redirect_uri = format!(
|
let redirect_uri = format!("{}/admin/oidc/callback", site_domain.trim_end_matches('/'));
|
||||||
"{}/admin/oidc/callback",
|
|
||||||
site_domain.trim_end_matches('/')
|
|
||||||
);
|
|
||||||
|
|
||||||
let redirect_url = format!(
|
let redirect_url = format!(
|
||||||
"{}?response_type=code&client_id={}&redirect_uri={}&scope=openid+profile&state={}",
|
"{}?response_type=code&client_id={}&redirect_uri={}&scope=openid+profile&state={}",
|
||||||
@@ -678,10 +740,7 @@ async fn oidc_callback(request: Request, session: Session, db: Database) -> cot:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let redirect_uri = format!(
|
let redirect_uri = format!("{}/admin/oidc/callback", site_domain.trim_end_matches('/'));
|
||||||
"{}/admin/oidc/callback",
|
|
||||||
site_domain.trim_end_matches('/')
|
|
||||||
);
|
|
||||||
|
|
||||||
// Exchange code for tokens
|
// Exchange code for tokens
|
||||||
let token_resp = reqwest::Client::new()
|
let token_resp = reqwest::Client::new()
|
||||||
@@ -743,7 +802,11 @@ async fn oidc_callback(request: Request, session: Session, db: Database) -> cot:
|
|||||||
// Check group membership
|
// Check group membership
|
||||||
let allowed_groups = oidc_setting(&db, "oidc_allowed_groups").await?;
|
let allowed_groups = oidc_setting(&db, "oidc_allowed_groups").await?;
|
||||||
if !allowed_groups.trim().is_empty() {
|
if !allowed_groups.trim().is_empty() {
|
||||||
let required: Vec<&str> = allowed_groups.split(',').map(|s| s.trim()).filter(|s| !s.is_empty()).collect();
|
let required: Vec<&str> = allowed_groups
|
||||||
|
.split(',')
|
||||||
|
.map(|s| s.trim())
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.collect();
|
||||||
let user_groups: Vec<String> = claims
|
let user_groups: Vec<String> = claims
|
||||||
.get("groups")
|
.get("groups")
|
||||||
.and_then(|v| v.as_array())
|
.and_then(|v| v.as_array())
|
||||||
@@ -755,9 +818,9 @@ async fn oidc_callback(request: Request, session: Session, db: Database) -> cot:
|
|||||||
})
|
})
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let has_group = required.iter().any(|r| {
|
let has_group = required
|
||||||
user_groups.iter().any(|ug| ug.eq_ignore_ascii_case(r))
|
.iter()
|
||||||
});
|
.any(|r| user_groups.iter().any(|ug| ug.eq_ignore_ascii_case(r)));
|
||||||
|
|
||||||
if !has_group {
|
if !has_group {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
@@ -811,16 +874,16 @@ async fn oidc_callback(request: Request, session: Session, db: Database) -> cot:
|
|||||||
return Redirect::new(fail("sso_disabled")).into_response();
|
return Redirect::new(fail("sso_disabled")).into_response();
|
||||||
}
|
}
|
||||||
|
|
||||||
let display = user
|
let session_name = user
|
||||||
.display_name
|
.display_name
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.filter(|s| !s.is_empty())
|
.filter(|s| !s.is_empty())
|
||||||
.unwrap_or(&user.login)
|
.unwrap_or(&user.login)
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
tracing::info!(target: "oidc", username = %user.login, display = %display, "SSO login: session established");
|
tracing::info!(target: "oidc", username = %user.login, display_name = %session_name, "SSO login: session established");
|
||||||
session.insert(SESSION_USER_ID, user.id.unwrap()).await?;
|
session.insert(SESSION_USER_ID, user.id.unwrap()).await?;
|
||||||
session.insert(SESSION_USER_NAME, display).await?;
|
session.insert(SESSION_USER_NAME, session_name).await?;
|
||||||
|
|
||||||
// Clear the oidc_state cookie
|
// Clear the oidc_state cookie
|
||||||
let clear_cookie = "oidc_state=; Path=/admin/oidc; HttpOnly; Secure; SameSite=Lax; Max-Age=0";
|
let clear_cookie = "oidc_state=; Path=/admin/oidc; HttpOnly; Secure; SameSite=Lax; Max-Age=0";
|
||||||
@@ -868,9 +931,7 @@ async fn admin_index(request: Request, session: Session, db: Database) -> cot::R
|
|||||||
|
|
||||||
let mut all_feedbacks: Vec<RecentFeedback> = all_visits
|
let mut all_feedbacks: Vec<RecentFeedback> = all_visits
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|v| {
|
.filter(|v| v.user_id.primary_key().unwrap() == user_id && v.client_feedback.is_some())
|
||||||
v.user_id.primary_key().unwrap() == user_id && v.client_feedback.is_some()
|
|
||||||
})
|
|
||||||
.map(|v| {
|
.map(|v| {
|
||||||
let cid: i64 = v.client_id.primary_key().unwrap();
|
let cid: i64 = v.client_id.primary_key().unwrap();
|
||||||
let client_name = clients
|
let client_name = clients
|
||||||
@@ -2008,7 +2069,6 @@ async fn media_upload_submit(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let file_id = uuid::Uuid::new_v4();
|
let file_id = uuid::Uuid::new_v4();
|
||||||
let file_path = format!("{}/{}.{}", upload_dir, file_id, ext);
|
|
||||||
|
|
||||||
let data = field
|
let data = field
|
||||||
.bytes()
|
.bytes()
|
||||||
@@ -2017,9 +2077,15 @@ async fn media_upload_submit(
|
|||||||
if data.is_empty() {
|
if data.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tokio::fs::write(&file_path, &data)
|
let file_path = if file_type == "photo" {
|
||||||
.await
|
save_uploaded_image(&upload_dir, file_id, &ext, &data).await?
|
||||||
.map_err(|e| cot::Error::internal(e.to_string()))?;
|
} else {
|
||||||
|
let path = format!("{}/{}.{}", upload_dir, file_id, ext);
|
||||||
|
tokio::fs::write(&path, &data)
|
||||||
|
.await
|
||||||
|
.map_err(|e| cot::Error::internal(e.to_string()))?;
|
||||||
|
path
|
||||||
|
};
|
||||||
|
|
||||||
saved_files.push((file_path, file_type.to_string()));
|
saved_files.push((file_path, file_type.to_string()));
|
||||||
}
|
}
|
||||||
@@ -2229,10 +2295,7 @@ async fn testimonial_add(
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| cot::Error::internal(e.to_string()))?;
|
.map_err(|e| cot::Error::internal(e.to_string()))?;
|
||||||
let file_id = uuid::Uuid::new_v4();
|
let file_id = uuid::Uuid::new_v4();
|
||||||
let path = format!("{}/{}.{}", upload_dir, file_id, ext);
|
let path = save_uploaded_image(upload_dir, file_id, &ext, &data).await?;
|
||||||
tokio::fs::write(&path, &data)
|
|
||||||
.await
|
|
||||||
.map_err(|e| cot::Error::internal(e.to_string()))?;
|
|
||||||
image_path = Some(path);
|
image_path = Some(path);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -2380,10 +2443,7 @@ async fn testimonial_edit(
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| cot::Error::internal(e.to_string()))?;
|
.map_err(|e| cot::Error::internal(e.to_string()))?;
|
||||||
let file_id = uuid::Uuid::new_v4();
|
let file_id = uuid::Uuid::new_v4();
|
||||||
let path = format!("{}/{}.{}", upload_dir, file_id, ext);
|
let path = save_uploaded_image(upload_dir, file_id, &ext, &data).await?;
|
||||||
tokio::fs::write(&path, &data)
|
|
||||||
.await
|
|
||||||
.map_err(|e| cot::Error::internal(e.to_string()))?;
|
|
||||||
new_image_path = Some(path);
|
new_image_path = Some(path);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|||||||
Reference in New Issue
Block a user