// Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html use std::collections::HashSet; use crate::cloze::add_cloze_numbers_in_string; use crate::collection::Collection; use crate::decks::DeckId; use crate::error; use crate::error::OrInvalid; use crate::error::OrNotFound; use crate::notes::Note; use crate::notes::NoteId; use crate::prelude::IntoNewtypeVec; pub(crate) fn to_i64s(ids: Vec) -> Vec { ids.into_iter().map(Into::into).collect() } impl crate::services::NotesService for Collection { fn new_note( &mut self, input: anki_proto::notetypes::NotetypeId, ) -> error::Result { let ntid = input.into(); let nt = self.get_notetype(ntid)?.or_not_found(ntid)?; Ok(nt.new_note().into()) } fn add_note( &mut self, input: anki_proto::notes::AddNoteRequest, ) -> error::Result { let mut note: Note = input.note.or_invalid("no note provided")?.into(); let changes = self.add_note(&mut note, DeckId(input.deck_id))?; Ok(anki_proto::notes::AddNoteResponse { note_id: note.id.0, changes: Some(changes.into()), }) } fn defaults_for_adding( &mut self, input: anki_proto::notes::DefaultsForAddingRequest, ) -> error::Result { let home_deck: DeckId = input.home_deck_of_current_review_card.into(); self.defaults_for_adding(home_deck).map(Into::into) } fn default_deck_for_notetype( &mut self, input: anki_proto::notetypes::NotetypeId, ) -> error::Result { Ok(self .default_deck_for_notetype(input.into())? .unwrap_or(DeckId(0)) .into()) } fn update_notes( &mut self, input: anki_proto::notes::UpdateNotesRequest, ) -> error::Result { let notes = input .notes .into_iter() .map(Into::into) .collect::>(); self.update_notes_maybe_undoable(notes, !input.skip_undo_entry) .map(Into::into) } fn get_note( &mut self, input: anki_proto::notes::NoteId, ) -> error::Result { let nid = input.into(); self.storage .get_note(nid)? .or_not_found(nid) .map(Into::into) } fn remove_notes( &mut self, input: anki_proto::notes::RemoveNotesRequest, ) -> error::Result { if !input.note_ids.is_empty() { self.remove_notes( &input .note_ids .into_iter() .map(Into::into) .collect::>(), ) } else { let nids = self.storage.note_ids_of_cards( &input .card_ids .into_iter() .map(Into::into) .collect::>(), )?; self.remove_notes(&nids.into_iter().collect::>()) } .map(Into::into) } fn cloze_numbers_in_note( &mut self, note: anki_proto::notes::Note, ) -> error::Result { let mut set = HashSet::with_capacity(4); for field in ¬e.fields { add_cloze_numbers_in_string(field, &mut set); } Ok(anki_proto::notes::ClozeNumbersInNoteResponse { numbers: set.into_iter().map(|n| n as u32).collect(), }) } fn after_note_updates( &mut self, input: anki_proto::notes::AfterNoteUpdatesRequest, ) -> error::Result { self.after_note_updates( &to_note_ids(input.nids), input.generate_cards, input.mark_notes_modified, ) .map(Into::into) } fn field_names_for_notes( &mut self, input: anki_proto::notes::FieldNamesForNotesRequest, ) -> error::Result { let nids: Vec<_> = input.nids.into_iter().map(NoteId).collect(); self.storage .field_names_for_notes(&nids) .map(|fields| anki_proto::notes::FieldNamesForNotesResponse { fields }) } fn note_fields_check( &mut self, input: anki_proto::notes::Note, ) -> error::Result { let note: Note = input.into(); self.note_fields_check(¬e) .map(|r| anki_proto::notes::NoteFieldsCheckResponse { state: r as i32 }) } fn cards_of_note( &mut self, input: anki_proto::notes::NoteId, ) -> error::Result { self.storage .all_card_ids_of_note_in_template_order(NoteId(input.nid)) .map(|v| anki_proto::cards::CardIds { cids: v.into_iter().map(Into::into).collect(), }) } fn get_single_notetype_of_notes( &mut self, input: anki_proto::notes::NoteIds, ) -> error::Result { self.get_single_notetype_of_notes(&input.note_ids.into_newtype(NoteId)) .map(Into::into) } } pub(crate) fn to_note_ids(ids: Vec) -> Vec { ids.into_iter().map(NoteId).collect() } impl From for NoteId { fn from(nid: anki_proto::notes::NoteId) -> Self { NoteId(nid.nid) } } impl From for anki_proto::notes::NoteId { fn from(nid: NoteId) -> Self { anki_proto::notes::NoteId { nid: nid.0 } } }