mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
Fix newer notes incorrectly being skipped when importing successive exports (#3693)
* add Note::set_modified_with_mtime * add struct for Collection::update_note_inner_without_cards's args * refactor Collection::update_note_inner_without_cards to use the arg struct * add Collection::update_note_inner_without_cards_using_mtime * use incoming note's mtime when updating notes during import
This commit is contained in:
parent
afd7fca4cb
commit
2a1448bc45
3 changed files with 86 additions and 48 deletions
|
@ -15,6 +15,7 @@ use crate::import_export::package::UpdateCondition;
|
||||||
use crate::import_export::ImportError;
|
use crate::import_export::ImportError;
|
||||||
use crate::import_export::ImportProgress;
|
use crate::import_export::ImportProgress;
|
||||||
use crate::import_export::NoteLog;
|
use crate::import_export::NoteLog;
|
||||||
|
use crate::notes::UpdateNoteInnerWithoutCardsArgs;
|
||||||
use crate::notetype::ChangeNotetypeInput;
|
use crate::notetype::ChangeNotetypeInput;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::progress::ThrottlingProgressHandler;
|
use crate::progress::ThrottlingProgressHandler;
|
||||||
|
@ -463,14 +464,20 @@ impl<'n> NoteContext<'n> {
|
||||||
self.munge_media(&mut note)?;
|
self.munge_media(&mut note)?;
|
||||||
let original = self.get_expected_note(note.id)?;
|
let original = self.get_expected_note(note.id)?;
|
||||||
let notetype = self.get_expected_notetype(note.notetype_id)?;
|
let notetype = self.get_expected_notetype(note.notetype_id)?;
|
||||||
self.target_col.update_note_inner_without_cards(
|
// Preserve the incoming note's mtime to allow imports of successive exports
|
||||||
&mut note,
|
let incoming_mtime = note.mtime;
|
||||||
&original,
|
self.target_col
|
||||||
¬etype,
|
.update_note_inner_without_cards_using_mtime(
|
||||||
self.usn,
|
UpdateNoteInnerWithoutCardsArgs {
|
||||||
true,
|
note: &mut note,
|
||||||
self.normalize_notes,
|
original: &original,
|
||||||
true,
|
notetype: ¬etype,
|
||||||
|
usn: self.usn,
|
||||||
|
mark_note_modified: true,
|
||||||
|
normalize_text: self.normalize_notes,
|
||||||
|
update_tags: true,
|
||||||
|
},
|
||||||
|
Some(incoming_mtime),
|
||||||
)?;
|
)?;
|
||||||
self.imports.log_updated(note, source_id);
|
self.imports.log_updated(note, source_id);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -220,11 +220,16 @@ impl Note {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_modified(&mut self, usn: Usn) {
|
#[inline]
|
||||||
self.mtime = TimestampSecs::now();
|
pub(crate) fn set_modified_with_mtime(&mut self, usn: Usn, mtime: TimestampSecs) {
|
||||||
|
self.mtime = mtime;
|
||||||
self.usn = usn;
|
self.usn = usn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_modified(&mut self, usn: Usn) {
|
||||||
|
self.set_modified_with_mtime(usn, TimestampSecs::now())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn nonempty_fields<'a>(&self, fields: &'a [NoteField]) -> HashSet<&'a str> {
|
pub(crate) fn nonempty_fields<'a>(&self, fields: &'a [NoteField]) -> HashSet<&'a str> {
|
||||||
self.fields
|
self.fields
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -346,6 +351,18 @@ fn invalid_char_for_field(c: char) -> bool {
|
||||||
c.is_ascii_control() && c != '\n' && c != '\t'
|
c.is_ascii_control() && c != '\n' && c != '\t'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used when calling [Collection::update_note_inner_without_cards] and
|
||||||
|
/// [Collection::update_note_inner_without_cards_using_mtime]
|
||||||
|
pub(crate) struct UpdateNoteInnerWithoutCardsArgs<'a> {
|
||||||
|
pub(crate) note: &'a mut Note,
|
||||||
|
pub(crate) original: &'a Note,
|
||||||
|
pub(crate) notetype: &'a Notetype,
|
||||||
|
pub(crate) usn: Usn,
|
||||||
|
pub(crate) mark_note_modified: bool,
|
||||||
|
pub(crate) normalize_text: bool,
|
||||||
|
pub(crate) update_tags: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl Collection {
|
impl Collection {
|
||||||
pub(crate) fn canonify_note_tags(&mut self, note: &mut Note, usn: Usn) -> Result<()> {
|
pub(crate) fn canonify_note_tags(&mut self, note: &mut Note, usn: Usn) -> Result<()> {
|
||||||
if !note.tags.is_empty() {
|
if !note.tags.is_empty() {
|
||||||
|
@ -434,40 +451,53 @@ impl Collection {
|
||||||
normalize_text: bool,
|
normalize_text: bool,
|
||||||
update_tags: bool,
|
update_tags: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
self.update_note_inner_without_cards(
|
self.update_note_inner_without_cards(UpdateNoteInnerWithoutCardsArgs {
|
||||||
note,
|
note,
|
||||||
original,
|
original,
|
||||||
ctx.notetype,
|
notetype: ctx.notetype,
|
||||||
ctx.usn,
|
usn: ctx.usn,
|
||||||
mark_note_modified,
|
mark_note_modified,
|
||||||
normalize_text,
|
normalize_text,
|
||||||
update_tags,
|
update_tags,
|
||||||
)?;
|
})?;
|
||||||
self.generate_cards_for_existing_note(ctx, note)
|
self.generate_cards_for_existing_note(ctx, note)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: refactor into struct
|
#[inline]
|
||||||
#[allow(clippy::too_many_arguments)]
|
pub(crate) fn update_note_inner_without_cards_using_mtime(
|
||||||
pub(crate) fn update_note_inner_without_cards(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
note: &mut Note,
|
UpdateNoteInnerWithoutCardsArgs {
|
||||||
original: &Note,
|
note,
|
||||||
notetype: &Notetype,
|
original,
|
||||||
usn: Usn,
|
notetype,
|
||||||
mark_note_modified: bool,
|
usn,
|
||||||
normalize_text: bool,
|
mark_note_modified,
|
||||||
update_tags: bool,
|
normalize_text,
|
||||||
|
update_tags,
|
||||||
|
}: UpdateNoteInnerWithoutCardsArgs,
|
||||||
|
mtime: Option<TimestampSecs>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if update_tags {
|
if update_tags {
|
||||||
self.canonify_note_tags(note, usn)?;
|
self.canonify_note_tags(note, usn)?;
|
||||||
}
|
}
|
||||||
note.prepare_for_update(notetype, normalize_text)?;
|
note.prepare_for_update(notetype, normalize_text)?;
|
||||||
if mark_note_modified {
|
if mark_note_modified {
|
||||||
|
if let Some(mtime) = mtime {
|
||||||
|
note.set_modified_with_mtime(usn, mtime);
|
||||||
|
} else {
|
||||||
note.set_modified(usn);
|
note.set_modified(usn);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
self.update_note_undoable(note, original)
|
self.update_note_undoable(note, original)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn update_note_inner_without_cards(
|
||||||
|
&mut self,
|
||||||
|
args: UpdateNoteInnerWithoutCardsArgs<'_>,
|
||||||
|
) -> Result<()> {
|
||||||
|
self.update_note_inner_without_cards_using_mtime(args, None)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn remove_notes_inner(&mut self, nids: &[NoteId], usn: Usn) -> Result<usize> {
|
pub(crate) fn remove_notes_inner(&mut self, nids: &[NoteId], usn: Usn) -> Result<usize> {
|
||||||
let mut card_count = 0;
|
let mut card_count = 0;
|
||||||
for nid in nids {
|
for nid in nids {
|
||||||
|
@ -542,15 +572,15 @@ impl Collection {
|
||||||
out.update_tags,
|
out.update_tags,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
self.update_note_inner_without_cards(
|
self.update_note_inner_without_cards(UpdateNoteInnerWithoutCardsArgs {
|
||||||
&mut note,
|
note: &mut note,
|
||||||
&original,
|
original: &original,
|
||||||
&nt,
|
notetype: &nt,
|
||||||
usn,
|
usn,
|
||||||
out.mark_modified,
|
mark_note_modified: out.mark_modified,
|
||||||
norm,
|
normalize_text: norm,
|
||||||
out.update_tags,
|
update_tags: out.update_tags,
|
||||||
)?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
changed_notes += 1;
|
changed_notes += 1;
|
||||||
|
|
|
@ -9,6 +9,7 @@ use std::mem;
|
||||||
use super::CardGenContext;
|
use super::CardGenContext;
|
||||||
use super::CardTemplate;
|
use super::CardTemplate;
|
||||||
use super::Notetype;
|
use super::Notetype;
|
||||||
|
use crate::notes::UpdateNoteInnerWithoutCardsArgs;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::search::JoinSearches;
|
use crate::search::JoinSearches;
|
||||||
use crate::search::TemplateKind;
|
use crate::search::TemplateKind;
|
||||||
|
@ -80,15 +81,15 @@ impl Collection {
|
||||||
for nid in nids {
|
for nid in nids {
|
||||||
let mut note = self.storage.get_note(nid)?.unwrap();
|
let mut note = self.storage.get_note(nid)?.unwrap();
|
||||||
let original = note.clone();
|
let original = note.clone();
|
||||||
self.update_note_inner_without_cards(
|
self.update_note_inner_without_cards(UpdateNoteInnerWithoutCardsArgs {
|
||||||
&mut note,
|
note: &mut note,
|
||||||
&original,
|
original: &original,
|
||||||
nt,
|
notetype: nt,
|
||||||
usn,
|
usn,
|
||||||
true,
|
mark_note_modified: true,
|
||||||
normalize_text,
|
normalize_text,
|
||||||
false,
|
update_tags: false,
|
||||||
)?;
|
})?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
|
@ -104,15 +105,15 @@ impl Collection {
|
||||||
let mut note = self.storage.get_note(nid)?.unwrap();
|
let mut note = self.storage.get_note(nid)?.unwrap();
|
||||||
let original = note.clone();
|
let original = note.clone();
|
||||||
note.reorder_fields(&ords);
|
note.reorder_fields(&ords);
|
||||||
self.update_note_inner_without_cards(
|
self.update_note_inner_without_cards(UpdateNoteInnerWithoutCardsArgs {
|
||||||
&mut note,
|
note: &mut note,
|
||||||
&original,
|
original: &original,
|
||||||
nt,
|
notetype: nt,
|
||||||
usn,
|
usn,
|
||||||
true,
|
mark_note_modified: true,
|
||||||
normalize_text,
|
normalize_text,
|
||||||
false,
|
update_tags: false,
|
||||||
)?;
|
})?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue