v0.2.15
RustBox CI / rustbox (push) Canceled after 0s

This commit is contained in:
Mateusz Gruszczyński committed 2026-11-02 23:13:21 +01:00
1 parent fb9eab87eb
commit d91212d24c
40 files changed
+585 -380

No files matched your search

+8 -2
View File
@@ -55,6 +55,7 @@ pub struct DisplayPreferences {
pub spellcheck_enabled: bool,
pub interface_skin: String,
pub preset_scale_unlocked: bool,
pub adaptive_email_colors: bool,
pub updated_at: String,
}
@@ -113,6 +114,7 @@ pub struct UpdateDisplayPreferences {
pub spellcheck_enabled: Option<bool>,
pub interface_skin: Option<String>,
pub preset_scale_unlocked: Option<bool>,
pub adaptive_email_colors: Option<bool>,
}
fn deserialize_animation_mode_field<'de, D>(
@@ -179,6 +181,7 @@ fn defaults() -> DisplayPreferences {
spellcheck_enabled: true,
interface_skin: "default".into(),
preset_scale_unlocked: false,
adaptive_email_colors: false,
updated_at: String::new(),
}
}
@@ -238,7 +241,8 @@ pub fn get_preferences(conn: &Connection) -> Result<DisplayPreferences, String>
spellcheck_enabled: row.get::<_, i32>(49)? != 0,
interface_skin: row.get(50)?,
preset_scale_unlocked: row.get::<_, i32>(51)? != 0,
updated_at: row.get(52)?,
adaptive_email_colors: row.get::<_, i32>(52)? != 0,
updated_at: row.get(53)?,
})
});
match result {
@@ -539,6 +543,7 @@ pub fn update_preferences(
set_bool!(spellcheck_enabled, "spellcheck_enabled");
set_text!(interface_skin, "interface_skin");
set_bool!(preset_scale_unlocked, "preset_scale_unlocked");
set_bool!(adaptive_email_colors, "adaptive_email_colors");
if sets.is_empty() {
return get_preferences(conn);
@@ -568,7 +573,7 @@ mod tests {
let update: UpdateDisplayPreferences = serde_json::from_value(serde_json::json!({
"theme":"dark", "language":"pl", "color_preset":"blue", "accent_color":"#336699",
"font_size":15, "row_height":64, "folder_pane_width":250, "message_pane_width":480,
"show_avatars":false, "reduce_motion":true, "interface_skin":"roundcube-elastic", "preset_scale_unlocked":true
"show_avatars":false, "reduce_motion":true, "interface_skin":"roundcube-elastic", "preset_scale_unlocked":true, "adaptive_email_colors":true
}))
.unwrap();
let prefs = update_preferences(&conn, &update).unwrap();
@@ -578,6 +583,7 @@ mod tests {
assert!(!prefs.show_avatars);
assert_eq!(prefs.interface_skin, "roundcube-elastic");
assert!(prefs.preset_scale_unlocked);
assert!(prefs.adaptive_email_colors);
}
#[test]
+1
View File
@@ -107,6 +107,7 @@ mod tests {
&conn,
&mail_preferences::UpdateMailPreferences {
messages_per_page: None,
message_loading_mode: None,
mark_read_delay_ms: None,
remote_images: None,
preferred_body: None,
+27 -11
View File
@@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
pub struct MailPreferences {
pub messages_per_page: u32,
pub message_loading_mode: String,
pub mark_read_delay_ms: u64,
pub remote_images: String,
pub preferred_body: String,
@@ -20,6 +21,7 @@ pub struct MailPreferences {
#[derive(Debug, Deserialize)]
pub struct UpdateMailPreferences {
pub messages_per_page: Option<u32>,
pub message_loading_mode: Option<String>,
pub mark_read_delay_ms: Option<u64>,
pub remote_images: Option<String>,
pub preferred_body: Option<String>,
@@ -36,17 +38,18 @@ pub fn get_preferences(conn: &Connection) -> Result<MailPreferences, String> {
conn.query_row(crate::dbq!(db_mail_preferences::Q_001), [], |row| {
Ok(MailPreferences {
messages_per_page: row.get::<_, u32>(0)?,
mark_read_delay_ms: row.get::<_, u64>(1)?,
remote_images: row.get(2)?,
preferred_body: row.get(3)?,
thread_mode: row.get(4)?,
collapse_quotes: row.get::<_, i32>(5)? != 0,
show_snippets: row.get::<_, i32>(6)? != 0,
default_sort: row.get(7)?,
flagged_on_top: row.get::<_, i32>(8)? != 0,
sync_imap_keywords: row.get::<_, i32>(9)? != 0,
compact_wide_rows: row.get::<_, i32>(10)? != 0,
updated_at: row.get(11)?,
message_loading_mode: row.get(1)?,
mark_read_delay_ms: row.get::<_, u64>(2)?,
remote_images: row.get(3)?,
preferred_body: row.get(4)?,
thread_mode: row.get(5)?,
collapse_quotes: row.get::<_, i32>(6)? != 0,
show_snippets: row.get::<_, i32>(7)? != 0,
default_sort: row.get(8)?,
flagged_on_top: row.get::<_, i32>(9)? != 0,
sync_imap_keywords: row.get::<_, i32>(10)? != 0,
compact_wide_rows: row.get::<_, i32>(11)? != 0,
updated_at: row.get(12)?,
})
})
.map_err(|error| format!("Failed to read mail preferences: {error}"))
@@ -64,6 +67,11 @@ pub fn update_preferences(
{
return Err("messages_per_page must be between 20 and 300".to_string());
}
if let Some(ref value) = data.message_loading_mode
&& !matches!(value.as_str(), "pagination" | "progressive" | "all")
{
return Err("message_loading_mode must be pagination, progressive or all".to_string());
}
if let Some(value) = data.mark_read_delay_ms
&& value > 30_000
{
@@ -102,6 +110,10 @@ pub fn update_preferences(
let current = get_preferences(conn)?;
let messages_per_page = data.messages_per_page.unwrap_or(current.messages_per_page);
let message_loading_mode = data
.message_loading_mode
.as_deref()
.unwrap_or(&current.message_loading_mode);
let mark_read_delay_ms = data
.mark_read_delay_ms
.unwrap_or(current.mark_read_delay_ms);
@@ -130,6 +142,7 @@ pub fn update_preferences(
crate::dbq!(db_mail_preferences::Q_003),
params![
messages_per_page,
message_loading_mode,
mark_read_delay_ms,
remote_images,
preferred_body,
@@ -157,12 +170,14 @@ mod tests {
let conn = open_test_db();
let defaults = get_preferences(&conn).unwrap();
assert_eq!(defaults.messages_per_page, 300);
assert_eq!(defaults.message_loading_mode, "pagination");
assert_eq!(defaults.remote_images, "ask");
let updated = update_preferences(
&conn,
&UpdateMailPreferences {
messages_per_page: Some(100),
message_loading_mode: Some("progressive".to_string()),
mark_read_delay_ms: Some(1500),
remote_images: Some("never".to_string()),
preferred_body: Some("text".to_string()),
@@ -177,6 +192,7 @@ mod tests {
)
.unwrap();
assert_eq!(updated.messages_per_page, 100);
assert_eq!(updated.message_loading_mode, "progressive");
assert_eq!(updated.mark_read_delay_ms, 1500);
assert_eq!(updated.thread_mode, "flat");
assert!(updated.flagged_on_top);
+17 -59
View File
@@ -16,65 +16,23 @@ use tokio::sync::Mutex as AsyncMutex;
use crate::config::AppConfig;
pub const BASE_SCHEMA_VERSION: u32 = 46;
pub const BASE_SCHEMA_VERSION: u32 = 49;
const SQLITE_SCHEMA: &str = include_str!("../../migrations/sqlite/schema.sql");
const MYSQL_SCHEMA: &str = include_str!("../../migrations/mysql/schema.sql");
const PGSQL_SCHEMA: &str = include_str!("../../migrations/pgsql/schema.sql");
const SQLITE_MIGRATIONS: &[(u32, &str)] = &[
(
47,
include_str!("../../migrations/sqlite/V047__blob_keys_and_search_outbox.sql"),
),
(
48,
include_str!("../../migrations/sqlite/V048__folder_counter_generation.sql"),
),
(
49,
include_str!("../../migrations/sqlite/V049__blob_delete_outbox.sql"),
),
(
50,
include_str!("../../migrations/sqlite/V050__compact_rows_and_signature_mode.sql"),
),
];
const MYSQL_MIGRATIONS: &[(u32, &str)] = &[
(
47,
include_str!("../../migrations/mysql/V047__blob_keys_and_search_outbox.sql"),
),
(
48,
include_str!("../../migrations/mysql/V048__folder_counter_generation.sql"),
),
(
49,
include_str!("../../migrations/mysql/V049__blob_delete_outbox.sql"),
),
(
50,
include_str!("../../migrations/mysql/V050__compact_rows_and_signature_mode.sql"),
),
];
const PGSQL_MIGRATIONS: &[(u32, &str)] = &[
(
47,
include_str!("../../migrations/pgsql/V047__blob_keys_and_search_outbox.sql"),
),
(
48,
include_str!("../../migrations/pgsql/V048__folder_counter_generation.sql"),
),
(
49,
include_str!("../../migrations/pgsql/V049__blob_delete_outbox.sql"),
),
(
50,
include_str!("../../migrations/pgsql/V050__compact_rows_and_signature_mode.sql"),
),
];
const SQLITE_MIGRATIONS: &[(u32, &str)] = &[(
50,
include_str!("../../migrations/sqlite/V050__compact_rows_and_signature_mode.sql"),
)];
const MYSQL_MIGRATIONS: &[(u32, &str)] = &[(
50,
include_str!("../../migrations/mysql/V050__compact_rows_and_signature_mode.sql"),
)];
const PGSQL_MIGRATIONS: &[(u32, &str)] = &[(
50,
include_str!("../../migrations/pgsql/V050__compact_rows_and_signature_mode.sql"),
)];
const TENANT_TABLES: &[&str] = &[
"blob_delete_outbox",
@@ -1861,7 +1819,7 @@ fn read_legacy_sqlite(path: &Path) -> Result<Vec<LegacyTableData>, String> {
.map_err(|e| format!("failed to read legacy SQLite schema version: {e}"))?;
if version < BASE_SCHEMA_VERSION {
return Err(format!(
"legacy SQLite schema version {version} is older than the legacy RustBox baseline {BASE_SCHEMA_VERSION}; upgrade with RustBox 0.1.0 first"
"legacy SQLite schema version {version} is older than the consolidated RustBox baseline {BASE_SCHEMA_VERSION}; upgrade to schema V049 first"
));
}
let latest_supported_sqlite = SQLITE_MIGRATIONS
@@ -2222,7 +2180,7 @@ fn apply_sqlite_migrations(
) -> Result<(), String> {
if current < BASE_SCHEMA_VERSION {
return Err(format!(
"database schema version {current} is older than the legacy RustBox baseline {BASE_SCHEMA_VERSION}; upgrade with RustBox 0.1.0 first"
"database schema version {current} is older than the consolidated RustBox baseline {BASE_SCHEMA_VERSION}; upgrade to schema V049 first"
));
}
let latest = latest_schema_version();
@@ -2667,7 +2625,7 @@ mod tests {
}
#[test]
fn legacy_sqlite_v046_is_imported_and_backed_up() {
fn legacy_sqlite_v050_is_imported_and_backed_up() {
let temp = tempfile::tempdir().unwrap();
let data_dir = temp.path();
let user_hash = format!("{:x}", Sha256::digest(b"legacy-user"));
@@ -2683,7 +2641,7 @@ mod tests {
legacy
.execute_batch(&tenant_seed_sql(DatabaseBackend::Sqlite, ""))
.unwrap();
legacy.execute_batch("PRAGMA user_version=46;").unwrap();
legacy.execute_batch("PRAGMA user_version=50;").unwrap();
legacy.execute(
"INSERT INTO display_preferences(id, theme, accent_color) VALUES(1, 'dark', '#123456')",
[],
+1
View File
@@ -53,6 +53,7 @@ mod tests {
&conn,
&UpdateMailPreferences {
messages_per_page: Some(100),
message_loading_mode: None,
mark_read_delay_ms: None,
remote_images: None,
preferred_body: None,