mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 14:32:22 -04:00
Skip new notetype checks when importing apkg
This commit is contained in:
parent
be1b524396
commit
c0dd769090
10 changed files with 69 additions and 35 deletions
|
@ -107,6 +107,7 @@ message Notetype {
|
||||||
message AddOrUpdateNotetypeRequest {
|
message AddOrUpdateNotetypeRequest {
|
||||||
bytes json = 1;
|
bytes json = 1;
|
||||||
bool preserve_usn_and_mtime = 2;
|
bool preserve_usn_and_mtime = 2;
|
||||||
|
bool skip_checks = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message StockNotetype {
|
message StockNotetype {
|
||||||
|
|
|
@ -235,7 +235,7 @@ class Anki2Importer(Importer):
|
||||||
model = srcModel.copy()
|
model = srcModel.copy()
|
||||||
model["id"] = mid
|
model["id"] = mid
|
||||||
model["usn"] = self.col.usn()
|
model["usn"] = self.col.usn()
|
||||||
self.dst.models.update(model)
|
self.dst.models.update(model, skip_checks=True)
|
||||||
break
|
break
|
||||||
# there's an existing model; do the schemas match?
|
# there's an existing model; do the schemas match?
|
||||||
dstModel = self.dst.models.get(mid)
|
dstModel = self.dst.models.get(mid)
|
||||||
|
@ -246,7 +246,7 @@ class Anki2Importer(Importer):
|
||||||
model = srcModel.copy()
|
model = srcModel.copy()
|
||||||
model["id"] = mid
|
model["id"] = mid
|
||||||
model["usn"] = self.col.usn()
|
model["usn"] = self.col.usn()
|
||||||
self.dst.models.update(model)
|
self.dst.models.update(model, skip_checks=True)
|
||||||
break
|
break
|
||||||
# as they don't match, try next id
|
# as they don't match, try next id
|
||||||
mid = NotetypeId(mid + 1)
|
mid = NotetypeId(mid + 1)
|
||||||
|
|
|
@ -527,12 +527,19 @@ and notes.mid = ? and cards.ord = ?""",
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# @deprecated(replaced_by=update_dict)
|
# @deprecated(replaced_by=update_dict)
|
||||||
def update(self, notetype: NotetypeDict, preserve_usn: bool = True) -> None:
|
def update(
|
||||||
|
self,
|
||||||
|
notetype: NotetypeDict,
|
||||||
|
preserve_usn: bool = True,
|
||||||
|
skip_checks: bool = False,
|
||||||
|
) -> None:
|
||||||
"Add or update an existing model. Use .update_dict() instead."
|
"Add or update an existing model. Use .update_dict() instead."
|
||||||
self._remove_from_cache(notetype["id"])
|
self._remove_from_cache(notetype["id"])
|
||||||
self.ensure_name_unique(notetype)
|
self.ensure_name_unique(notetype)
|
||||||
notetype["id"] = self.col._backend.add_or_update_notetype(
|
notetype["id"] = self.col._backend.add_or_update_notetype(
|
||||||
json=to_json_bytes(notetype), preserve_usn_and_mtime=preserve_usn
|
json=to_json_bytes(notetype),
|
||||||
|
preserve_usn_and_mtime=preserve_usn,
|
||||||
|
skip_checks=skip_checks,
|
||||||
)
|
)
|
||||||
self.set_current(notetype)
|
self.set_current(notetype)
|
||||||
self._mutate_after_write(notetype)
|
self._mutate_after_write(notetype)
|
||||||
|
|
|
@ -17,7 +17,7 @@ impl NotetypesService for Backend {
|
||||||
let mut notetype: Notetype = input.into();
|
let mut notetype: Notetype = input.into();
|
||||||
self.with_col(|col| {
|
self.with_col(|col| {
|
||||||
Ok(col
|
Ok(col
|
||||||
.add_notetype(&mut notetype)?
|
.add_notetype(&mut notetype, false)?
|
||||||
.map(|_| notetype.id.0)
|
.map(|_| notetype.id.0)
|
||||||
.into())
|
.into())
|
||||||
})
|
})
|
||||||
|
@ -25,7 +25,7 @@ impl NotetypesService for Backend {
|
||||||
|
|
||||||
fn update_notetype(&self, input: pb::Notetype) -> Result<pb::OpChanges> {
|
fn update_notetype(&self, input: pb::Notetype) -> Result<pb::OpChanges> {
|
||||||
let mut notetype: Notetype = input.into();
|
let mut notetype: Notetype = input.into();
|
||||||
self.with_col(|col| col.update_notetype(&mut notetype))
|
self.with_col(|col| col.update_notetype(&mut notetype, false))
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ impl NotetypesService for Backend {
|
||||||
let mut notetype: Notetype = legacy.into();
|
let mut notetype: Notetype = legacy.into();
|
||||||
self.with_col(|col| {
|
self.with_col(|col| {
|
||||||
Ok(col
|
Ok(col
|
||||||
.add_notetype(&mut notetype)?
|
.add_notetype(&mut notetype, false)?
|
||||||
.map(|_| notetype.id.0)
|
.map(|_| notetype.id.0)
|
||||||
.into())
|
.into())
|
||||||
})
|
})
|
||||||
|
@ -43,7 +43,7 @@ impl NotetypesService for Backend {
|
||||||
fn update_notetype_legacy(&self, input: pb::Json) -> Result<pb::OpChanges> {
|
fn update_notetype_legacy(&self, input: pb::Json) -> Result<pb::OpChanges> {
|
||||||
let legacy: NotetypeSchema11 = serde_json::from_slice(&input.json)?;
|
let legacy: NotetypeSchema11 = serde_json::from_slice(&input.json)?;
|
||||||
let mut notetype: Notetype = legacy.into();
|
let mut notetype: Notetype = legacy.into();
|
||||||
self.with_col(|col| col.update_notetype(&mut notetype))
|
self.with_col(|col| col.update_notetype(&mut notetype, false))
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,11 +58,11 @@ impl NotetypesService for Backend {
|
||||||
nt.set_modified(col.usn()?);
|
nt.set_modified(col.usn()?);
|
||||||
}
|
}
|
||||||
if nt.id.0 == 0 {
|
if nt.id.0 == 0 {
|
||||||
col.add_notetype(&mut nt)?;
|
col.add_notetype(&mut nt, input.skip_checks)?;
|
||||||
} else if !input.preserve_usn_and_mtime {
|
} else if !input.preserve_usn_and_mtime {
|
||||||
col.update_notetype(&mut nt)?;
|
col.update_notetype(&mut nt, input.skip_checks)?;
|
||||||
} else {
|
} else {
|
||||||
col.add_or_update_notetype_with_existing_id(&mut nt)?;
|
col.add_or_update_notetype_with_existing_id(&mut nt, input.skip_checks)?;
|
||||||
}
|
}
|
||||||
Ok(pb::NotetypeId { ntid: nt.id.0 })
|
Ok(pb::NotetypeId { ntid: nt.id.0 })
|
||||||
})
|
})
|
||||||
|
|
|
@ -273,7 +273,7 @@ impl Collection {
|
||||||
// one note type exists
|
// one note type exists
|
||||||
if self.storage.get_all_notetype_names()?.is_empty() {
|
if self.storage.get_all_notetype_names()?.is_empty() {
|
||||||
let mut nt = all_stock_notetypes(&self.tr).remove(0);
|
let mut nt = all_stock_notetypes(&self.tr).remove(0);
|
||||||
self.add_notetype_inner(&mut nt, usn)?;
|
self.add_notetype_inner(&mut nt, usn, true)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if out.card_ords_duplicated > 0
|
if out.card_ords_duplicated > 0
|
||||||
|
@ -367,7 +367,7 @@ impl Collection {
|
||||||
for n in 0..extra_cards_required {
|
for n in 0..extra_cards_required {
|
||||||
basic.add_template(&format!("Card {}", n + 2), &qfmt, &afmt);
|
basic.add_template(&format!("Card {}", n + 2), &qfmt, &afmt);
|
||||||
}
|
}
|
||||||
self.add_notetype(&mut basic)?;
|
self.add_notetype(&mut basic, true)?;
|
||||||
Ok(Arc::new(basic))
|
Ok(Arc::new(basic))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,11 +117,15 @@ impl Notetype {
|
||||||
|
|
||||||
impl Collection {
|
impl Collection {
|
||||||
/// Add a new notetype, and allocate it an ID.
|
/// Add a new notetype, and allocate it an ID.
|
||||||
pub fn add_notetype(&mut self, notetype: &mut Notetype) -> Result<OpOutput<()>> {
|
pub fn add_notetype(
|
||||||
|
&mut self,
|
||||||
|
notetype: &mut Notetype,
|
||||||
|
skip_checks: bool,
|
||||||
|
) -> Result<OpOutput<()>> {
|
||||||
self.transact(Op::AddNotetype, |col| {
|
self.transact(Op::AddNotetype, |col| {
|
||||||
let usn = col.usn()?;
|
let usn = col.usn()?;
|
||||||
notetype.set_modified(usn);
|
notetype.set_modified(usn);
|
||||||
col.add_notetype_inner(notetype, usn)
|
col.add_notetype_inner(notetype, usn, skip_checks)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +134,11 @@ impl Collection {
|
||||||
///
|
///
|
||||||
/// This does not assign ordinals to the provided notetype, so if you wish
|
/// This does not assign ordinals to the provided notetype, so if you wish
|
||||||
/// to make use of template_idx, the notetype must be fetched again.
|
/// to make use of template_idx, the notetype must be fetched again.
|
||||||
pub fn update_notetype(&mut self, notetype: &mut Notetype) -> Result<OpOutput<()>> {
|
pub fn update_notetype(
|
||||||
|
&mut self,
|
||||||
|
notetype: &mut Notetype,
|
||||||
|
skip_checks: bool,
|
||||||
|
) -> Result<OpOutput<()>> {
|
||||||
self.transact(Op::UpdateNotetype, |col| {
|
self.transact(Op::UpdateNotetype, |col| {
|
||||||
let original = col
|
let original = col
|
||||||
.storage
|
.storage
|
||||||
|
@ -138,7 +146,12 @@ impl Collection {
|
||||||
.ok_or(AnkiError::NotFound)?;
|
.ok_or(AnkiError::NotFound)?;
|
||||||
let usn = col.usn()?;
|
let usn = col.usn()?;
|
||||||
notetype.set_modified(usn);
|
notetype.set_modified(usn);
|
||||||
col.add_or_update_notetype_with_existing_id_inner(notetype, Some(original), usn)
|
col.add_or_update_notetype_with_existing_id_inner(
|
||||||
|
notetype,
|
||||||
|
Some(original),
|
||||||
|
usn,
|
||||||
|
skip_checks,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,11 +160,12 @@ impl Collection {
|
||||||
pub fn add_or_update_notetype_with_existing_id(
|
pub fn add_or_update_notetype_with_existing_id(
|
||||||
&mut self,
|
&mut self,
|
||||||
notetype: &mut Notetype,
|
notetype: &mut Notetype,
|
||||||
|
skip_checks: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
self.transact_no_undo(|col| {
|
self.transact_no_undo(|col| {
|
||||||
let usn = col.usn()?;
|
let usn = col.usn()?;
|
||||||
let existing = col.storage.get_notetype(notetype.id)?;
|
let existing = col.storage.get_notetype(notetype.id)?;
|
||||||
col.add_or_update_notetype_with_existing_id_inner(notetype, existing, usn)
|
col.add_or_update_notetype_with_existing_id_inner(notetype, existing, usn, skip_checks)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,7 +433,11 @@ impl Notetype {
|
||||||
self.templates.push(CardTemplate::new(name, qfmt, afmt));
|
self.templates.push(CardTemplate::new(name, qfmt, afmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn prepare_for_update(&mut self, existing: Option<&Notetype>) -> Result<()> {
|
pub(crate) fn prepare_for_update(
|
||||||
|
&mut self,
|
||||||
|
existing: Option<&Notetype>,
|
||||||
|
skip_checks: bool,
|
||||||
|
) -> Result<()> {
|
||||||
if self.fields.is_empty() {
|
if self.fields.is_empty() {
|
||||||
return Err(AnkiError::invalid_input("1 field required"));
|
return Err(AnkiError::invalid_input("1 field required"));
|
||||||
}
|
}
|
||||||
|
@ -450,9 +468,11 @@ impl Notetype {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.config.reqs = reqs;
|
self.config.reqs = reqs;
|
||||||
self.ensure_template_fronts_unique()?;
|
if !skip_checks {
|
||||||
self.ensure_valid_parsed_templates(&parsed_templates)?;
|
self.ensure_template_fronts_unique()?;
|
||||||
self.ensure_cloze_if_cloze_notetype(&parsed_templates)?;
|
self.ensure_valid_parsed_templates(&parsed_templates)?;
|
||||||
|
self.ensure_cloze_if_cloze_notetype(&parsed_templates)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -610,8 +630,13 @@ impl Collection {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Caller must set notetype as modified if appropriate.
|
/// Caller must set notetype as modified if appropriate.
|
||||||
pub(crate) fn add_notetype_inner(&mut self, notetype: &mut Notetype, usn: Usn) -> Result<()> {
|
pub(crate) fn add_notetype_inner(
|
||||||
notetype.prepare_for_update(None)?;
|
&mut self,
|
||||||
|
notetype: &mut Notetype,
|
||||||
|
usn: Usn,
|
||||||
|
skip_checks: bool,
|
||||||
|
) -> Result<()> {
|
||||||
|
notetype.prepare_for_update(None, skip_checks)?;
|
||||||
self.ensure_notetype_name_unique(notetype, usn)?;
|
self.ensure_notetype_name_unique(notetype, usn)?;
|
||||||
self.add_notetype_undoable(notetype)?;
|
self.add_notetype_undoable(notetype)?;
|
||||||
self.set_current_notetype_id(notetype.id)
|
self.set_current_notetype_id(notetype.id)
|
||||||
|
@ -624,9 +649,10 @@ impl Collection {
|
||||||
notetype: &mut Notetype,
|
notetype: &mut Notetype,
|
||||||
original: Option<Notetype>,
|
original: Option<Notetype>,
|
||||||
usn: Usn,
|
usn: Usn,
|
||||||
|
skip_checks: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let normalize = self.get_config_bool(BoolKey::NormalizeNoteText);
|
let normalize = self.get_config_bool(BoolKey::NormalizeNoteText);
|
||||||
notetype.prepare_for_update(original.as_ref())?;
|
notetype.prepare_for_update(original.as_ref(), skip_checks)?;
|
||||||
self.ensure_notetype_name_unique(notetype, usn)?;
|
self.ensure_notetype_name_unique(notetype, usn)?;
|
||||||
|
|
||||||
if let Some(original) = original {
|
if let Some(original) = original {
|
||||||
|
@ -671,7 +697,7 @@ impl Collection {
|
||||||
let all = self.storage.get_all_notetype_names()?;
|
let all = self.storage.get_all_notetype_names()?;
|
||||||
if all.is_empty() {
|
if all.is_empty() {
|
||||||
let mut nt = all_stock_notetypes(&self.tr).remove(0);
|
let mut nt = all_stock_notetypes(&self.tr).remove(0);
|
||||||
self.add_notetype_inner(&mut nt, self.usn()?)?;
|
self.add_notetype_inner(&mut nt, self.usn()?, true)?;
|
||||||
self.set_current_notetype_id(nt.id)
|
self.set_current_notetype_id(nt.id)
|
||||||
} else {
|
} else {
|
||||||
self.set_current_notetype_id(all[0].0)
|
self.set_current_notetype_id(all[0].0)
|
||||||
|
|
|
@ -394,7 +394,7 @@ mod test {
|
||||||
basic.add_field("Text"); // 4
|
basic.add_field("Text"); // 4
|
||||||
basic.add_field("idx5");
|
basic.add_field("idx5");
|
||||||
// re-fetch to get ordinals
|
// re-fetch to get ordinals
|
||||||
col.update_notetype(&mut basic)?;
|
col.update_notetype(&mut basic, false)?;
|
||||||
let basic = col.get_notetype(basic.id)?.unwrap();
|
let basic = col.get_notetype(basic.id)?.unwrap();
|
||||||
|
|
||||||
// if names match, assignments are out of order; unmatched entries
|
// if names match, assignments are out of order; unmatched entries
|
||||||
|
|
|
@ -258,13 +258,13 @@ mod test {
|
||||||
col.add_note(&mut note, DeckId(1))?;
|
col.add_note(&mut note, DeckId(1))?;
|
||||||
|
|
||||||
nt.add_field("three");
|
nt.add_field("three");
|
||||||
col.update_notetype(&mut nt)?;
|
col.update_notetype(&mut nt, false)?;
|
||||||
|
|
||||||
let note = col.storage.get_note(note.id)?.unwrap();
|
let note = col.storage.get_note(note.id)?.unwrap();
|
||||||
assert_eq!(note.fields(), &["one".to_string(), "two".into(), "".into()]);
|
assert_eq!(note.fields(), &["one".to_string(), "two".into(), "".into()]);
|
||||||
|
|
||||||
nt.fields.remove(1);
|
nt.fields.remove(1);
|
||||||
col.update_notetype(&mut nt)?;
|
col.update_notetype(&mut nt, false)?;
|
||||||
|
|
||||||
let note = col.storage.get_note(note.id)?.unwrap();
|
let note = col.storage.get_note(note.id)?.unwrap();
|
||||||
assert_eq!(note.fields(), &["one".to_string(), "".into()]);
|
assert_eq!(note.fields(), &["one".to_string(), "".into()]);
|
||||||
|
@ -281,13 +281,13 @@ mod test {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
nt.templates[0].config.q_format += "\n{{#Front}}{{some:Front}}{{Back}}{{/Front}}";
|
nt.templates[0].config.q_format += "\n{{#Front}}{{some:Front}}{{Back}}{{/Front}}";
|
||||||
nt.fields[0].name = "Test".into();
|
nt.fields[0].name = "Test".into();
|
||||||
col.update_notetype(&mut nt)?;
|
col.update_notetype(&mut nt, false)?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&nt.templates[0].config.q_format,
|
&nt.templates[0].config.q_format,
|
||||||
"{{Test}}\n{{#Test}}{{some:Test}}{{Back}}{{/Test}}"
|
"{{Test}}\n{{#Test}}{{some:Test}}{{Back}}{{/Test}}"
|
||||||
);
|
);
|
||||||
nt.fields.remove(0);
|
nt.fields.remove(0);
|
||||||
col.update_notetype(&mut nt)?;
|
col.update_notetype(&mut nt, false)?;
|
||||||
assert_eq!(&nt.templates[0].config.q_format, "\n{{Back}}");
|
assert_eq!(&nt.templates[0].config.q_format, "\n{{Back}}");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -313,7 +313,7 @@ mod test {
|
||||||
|
|
||||||
// add an extra card template
|
// add an extra card template
|
||||||
nt.add_template("card 2", "{{Front}}2", "");
|
nt.add_template("card 2", "{{Front}}2", "");
|
||||||
col.update_notetype(&mut nt)?;
|
col.update_notetype(&mut nt, false)?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
col.search_cards(note.id, SortMode::NoOrder).unwrap().len(),
|
col.search_cards(note.id, SortMode::NoOrder).unwrap().len(),
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::{
|
||||||
impl SqliteStorage {
|
impl SqliteStorage {
|
||||||
pub(crate) fn add_stock_notetypes(&self, tr: &I18n) -> Result<()> {
|
pub(crate) fn add_stock_notetypes(&self, tr: &I18n) -> Result<()> {
|
||||||
for (idx, mut nt) in all_stock_notetypes(tr).into_iter().enumerate() {
|
for (idx, mut nt) in all_stock_notetypes(tr).into_iter().enumerate() {
|
||||||
nt.prepare_for_update(None)?;
|
nt.prepare_for_update(None, true)?;
|
||||||
self.add_notetype(&mut nt)?;
|
self.add_notetype(&mut nt)?;
|
||||||
if idx == Kind::Basic as usize {
|
if idx == Kind::Basic as usize {
|
||||||
self.set_config_entry(&ConfigEntry::boxed(
|
self.set_config_entry(&ConfigEntry::boxed(
|
||||||
|
|
|
@ -1386,7 +1386,7 @@ mod test {
|
||||||
// and a new notetype
|
// and a new notetype
|
||||||
let mut nt = all_stock_notetypes(&col1.tr).remove(0);
|
let mut nt = all_stock_notetypes(&col1.tr).remove(0);
|
||||||
nt.name = "new".into();
|
nt.name = "new".into();
|
||||||
col1.add_notetype(&mut nt)?;
|
col1.add_notetype(&mut nt, false)?;
|
||||||
|
|
||||||
// add another note+card+tag
|
// add another note+card+tag
|
||||||
let mut note = nt.new_note();
|
let mut note = nt.new_note();
|
||||||
|
@ -1502,7 +1502,7 @@ mod test {
|
||||||
|
|
||||||
let mut nt = col2.storage.get_notetype(nt.id)?.unwrap();
|
let mut nt = col2.storage.get_notetype(nt.id)?.unwrap();
|
||||||
nt.name = "newer".into();
|
nt.name = "newer".into();
|
||||||
col2.update_notetype(&mut nt)?;
|
col2.update_notetype(&mut nt, false)?;
|
||||||
|
|
||||||
// sync the changes back
|
// sync the changes back
|
||||||
let out = ctx.normal_sync(&mut col2).await;
|
let out = ctx.normal_sync(&mut col2).await;
|
||||||
|
|
Loading…
Reference in a new issue