diff --git a/proto/anki/import_export.proto b/proto/anki/import_export.proto index ddb3f9662..0cc2a19d9 100644 --- a/proto/anki/import_export.proto +++ b/proto/anki/import_export.proto @@ -106,8 +106,8 @@ message MediaEntries { message ImportCsvRequest { enum DupeResolution { UPDATE = 0; - ADD = 1; - IGNORE = 2; + IGNORE = 1; + ADD = 2; // UPDATE_IF_NEWER = 3; } string path = 1; @@ -166,6 +166,7 @@ message CsvMetadata { bool force_is_html = 12; repeated generic.StringList preview = 13; uint32 guid_column = 14; + ImportCsvRequest.DupeResolution dupe_resolution = 15; } message ExportCardCsvRequest { diff --git a/rslib/src/config/mod.rs b/rslib/src/config/mod.rs index 6668b382a..1e7f0408a 100644 --- a/rslib/src/config/mod.rs +++ b/rslib/src/config/mod.rs @@ -4,6 +4,7 @@ mod bool; mod deck; mod notetype; +mod number; pub(crate) mod schema11; mod string; pub(crate) mod undo; @@ -14,7 +15,8 @@ use slog::warn; use strum::IntoStaticStr; pub use self::{ - bool::BoolKey, deck::DeckConfigKey, notetype::get_aux_notetype_config_key, string::StringKey, + bool::BoolKey, deck::DeckConfigKey, notetype::get_aux_notetype_config_key, + number::I32ConfigKey, string::StringKey, }; use crate::{backend_proto::preferences::BackupLimits, prelude::*}; diff --git a/rslib/src/config/number.rs b/rslib/src/config/number.rs new file mode 100644 index 000000000..446ff421b --- /dev/null +++ b/rslib/src/config/number.rs @@ -0,0 +1,27 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +use strum::IntoStaticStr; + +use crate::prelude::*; + +#[derive(Debug, Clone, Copy, IntoStaticStr)] +#[strum(serialize_all = "camelCase")] +pub enum I32ConfigKey { + CsvDuplicateResolution, +} + +impl Collection { + pub fn get_config_i32(&self, key: I32ConfigKey) -> i32 { + #[allow(clippy::match_single_binding)] + self.get_config_optional(key).unwrap_or_else(|| match key { + _other => 0, + }) + } +} + +impl Collection { + pub(crate) fn set_config_i32_inner(&mut self, key: I32ConfigKey, value: i32) -> Result { + self.set_config(key, &value) + } +} diff --git a/rslib/src/import_export/text/csv/import.rs b/rslib/src/import_export/text/csv/import.rs index 4b7cfe8d3..7290db031 100644 --- a/rslib/src/import_export/text/csv/import.rs +++ b/rslib/src/import_export/text/csv/import.rs @@ -276,6 +276,7 @@ mod test { field_columns: vec![1, 2], })), preview: Vec::new(), + dupe_resolution: 0, } } } diff --git a/rslib/src/import_export/text/csv/metadata.rs b/rslib/src/import_export/text/csv/metadata.rs index 0ed6e1b32..b77a045cd 100644 --- a/rslib/src/import_export/text/csv/metadata.rs +++ b/rslib/src/import_export/text/csv/metadata.rs @@ -13,10 +13,12 @@ use strum::IntoEnumIterator; use super::import::build_csv_reader; pub use crate::backend_proto::import_export::{ csv_metadata::{Deck as CsvDeck, Delimiter, MappedNotetype, Notetype as CsvNotetype}, + import_csv_request::DupeResolution, CsvMetadata, }; use crate::{ backend_proto::StringList, + config::I32ConfigKey, error::ImportError, import_export::text::NameOrId, notetype::NoteField, @@ -48,7 +50,14 @@ impl Collection { notetype_id: Option, is_html: Option, ) -> Result { - let mut metadata = CsvMetadata::default(); + let dupe_resolution = + DupeResolution::from_i32(self.get_config_i32(I32ConfigKey::CsvDuplicateResolution)) + .map(|r| r as i32) + .unwrap_or_default(); + let mut metadata = CsvMetadata { + dupe_resolution, + ..Default::default() + }; let meta_len = self.parse_meta_lines(&mut reader, &mut metadata)? as u64; maybe_set_fallback_delimiter(delimiter, &mut metadata, &mut reader, meta_len)?; let records = collect_preview_records(&mut metadata, reader)?; diff --git a/rslib/src/import_export/text/import.rs b/rslib/src/import_export/text/import.rs index 9aeb3a285..f036cc6bc 100644 --- a/rslib/src/import_export/text/import.rs +++ b/rslib/src/import_export/text/import.rs @@ -11,6 +11,7 @@ use std::{ use super::NameOrId; use crate::{ card::{CardQueue, CardType}, + config::I32ConfigKey, import_export::{ text::{ DupeResolution, ForeignCard, ForeignData, ForeignNote, ForeignNotetype, ForeignTemplate, @@ -31,6 +32,10 @@ impl ForeignData { let mut progress = IncrementableProgress::new(progress_fn); progress.call(ImportProgress::File)?; col.transact(Op::Import, |col| { + col.set_config_i32_inner( + I32ConfigKey::CsvDuplicateResolution, + self.dupe_resolution as i32, + )?; let mut ctx = Context::new(&self, col)?; ctx.import_foreign_notetypes(self.notetypes)?; ctx.import_foreign_notes( diff --git a/ts/import-csv/ImportCsvPage.svelte b/ts/import-csv/ImportCsvPage.svelte index bc3bada7e..3f7f445d1 100644 --- a/ts/import-csv/ImportCsvPage.svelte +++ b/ts/import-csv/ImportCsvPage.svelte @@ -30,6 +30,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html export let path: string; export let notetypeNameIds: Notetypes.NotetypeNameId[]; export let deckNameIds: Decks.DeckNameId[]; + export let dupeResolution: ImportExport.ImportCsvRequest.DupeResolution; export let delimiter: ImportExport.CsvMetadata.Delimiter; export let forceDelimiter: boolean; @@ -47,7 +48,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html export let deckId: number | null; export let deckColumn: number | null; - let dupeResolution: ImportExport.ImportCsvRequest.DupeResolution; let lastNotetypeId = globalNotetype?.id; let lastDelimeter = delimiter; diff --git a/ts/import-csv/index.ts b/ts/import-csv/index.ts index 0d0df2888..846ec0eeb 100644 --- a/ts/import-csv/index.ts +++ b/ts/import-csv/index.ts @@ -51,6 +51,7 @@ export async function setupImportCsvPage(path: string): Promise { path: path, deckNameIds: decks.entries, notetypeNameIds: notetypes.entries, + dupeResolution: metadata.dupeResolution, delimiter: metadata.delimiter, forceDelimiter: metadata.forceDelimiter, isHtml: metadata.isHtml,