merge the filtered deck errors into an enum

Fixes the wrong message being shown when trying to move cards to a
filtered deck
This commit is contained in:
Damien Elmes 2021-04-01 21:09:21 +10:00
parent 7df128a103
commit ac1b9fadde
8 changed files with 53 additions and 25 deletions

View file

@ -50,18 +50,14 @@ class ExistsError(Exception):
class DeckRenameError(Exception): class DeckRenameError(Exception):
"""Legacy error, use DeckIsFilteredError instead.""" """Legacy error, use FilteredDeckError instead."""
def __init__(self, description: str, *args: object) -> None: def __init__(self, description: str, *args: object) -> None:
super().__init__(description, *args) super().__init__(description, *args)
self.description = description self.description = description
class DeckIsFilteredError(StringError, DeckRenameError): class FilteredDeckError(StringError, DeckRenameError):
pass
class FilteredDeckEmpty(StringError):
pass pass
@ -95,10 +91,8 @@ def backend_exception_to_pylib(err: _pb.BackendError) -> Exception:
return NotFoundError() return NotFoundError()
elif val == "exists": elif val == "exists":
return ExistsError() return ExistsError()
elif val == "deck_is_filtered": elif val == "filtered_deck_error":
return DeckIsFilteredError(err.localized) return FilteredDeckError(err.localized)
elif val == "filtered_deck_empty":
return FilteredDeckEmpty(err.localized)
elif val == "proto_error": elif val == "proto_error":
return StringError(err.localized) return StringError(err.localized)
elif val == "search_error": elif val == "search_error":

View file

@ -568,9 +568,8 @@ message BackendError {
string proto_error = 10; string proto_error = 10;
Empty not_found_error = 11; Empty not_found_error = 11;
Empty exists = 12; Empty exists = 12;
Empty deck_is_filtered = 13; Empty filtered_deck_error = 13;
Empty filtered_deck_empty = 14; Empty search_error = 14;
Empty search_error = 15;
} }
} }

View file

@ -29,11 +29,10 @@ pub(super) fn anki_error_to_proto_error(err: AnkiError, tr: &I18n) -> pb::Backen
AnkiError::ProtoError(info) => V::ProtoError(info), AnkiError::ProtoError(info) => V::ProtoError(info),
AnkiError::NotFound => V::NotFoundError(pb::Empty {}), AnkiError::NotFound => V::NotFoundError(pb::Empty {}),
AnkiError::Existing => V::Exists(pb::Empty {}), AnkiError::Existing => V::Exists(pb::Empty {}),
AnkiError::DeckIsFiltered => V::DeckIsFiltered(pb::Empty {}), AnkiError::FilteredDeckError(_) => V::FilteredDeckError(pb::Empty {}),
AnkiError::SearchError(_) => V::SearchError(pb::Empty {}), AnkiError::SearchError(_) => V::SearchError(pb::Empty {}),
AnkiError::TemplateSaveError { .. } => V::TemplateParse(pb::Empty {}), AnkiError::TemplateSaveError { .. } => V::TemplateParse(pb::Empty {}),
AnkiError::ParseNumError => V::InvalidInput(pb::Empty {}), AnkiError::ParseNumError => V::InvalidInput(pb::Empty {}),
AnkiError::FilteredDeckEmpty => V::FilteredDeckEmpty(pb::Empty {}),
AnkiError::InvalidRegex(_) => V::InvalidInput(pb::Empty {}), AnkiError::InvalidRegex(_) => V::InvalidInput(pb::Empty {}),
}; };

View file

@ -3,7 +3,7 @@
pub(crate) mod undo; pub(crate) mod undo;
use crate::error::{AnkiError, Result}; use crate::error::{AnkiError, FilteredDeckError, Result};
use crate::notes::NoteId; use crate::notes::NoteId;
use crate::{ use crate::{
collection::Collection, config::SchedulerVersion, prelude::*, timestamp::TimestampSecs, collection::Collection, config::SchedulerVersion, prelude::*, timestamp::TimestampSecs,
@ -234,7 +234,7 @@ impl Collection {
pub fn set_deck(&mut self, cards: &[CardId], deck_id: DeckId) -> Result<OpOutput<()>> { pub fn set_deck(&mut self, cards: &[CardId], deck_id: DeckId) -> Result<OpOutput<()>> {
let deck = self.get_deck(deck_id)?.ok_or(AnkiError::NotFound)?; let deck = self.get_deck(deck_id)?.ok_or(AnkiError::NotFound)?;
if deck.is_filtered() { if deck.is_filtered() {
return Err(AnkiError::DeckIsFiltered); return Err(FilteredDeckError::CanNotMoveCardsInto.into());
} }
self.storage.set_search_table_to_card_ids(cards, false)?; self.storage.set_search_table_to_card_ids(cards, false)?;
let sched = self.scheduler_version(); let sched = self.scheduler_version();

View file

@ -12,14 +12,17 @@ pub use crate::backend_proto::{
filtered_deck::{search_term::Order as FilteredSearchOrder, SearchTerm as FilteredSearchTerm}, filtered_deck::{search_term::Order as FilteredSearchOrder, SearchTerm as FilteredSearchTerm},
Deck as DeckProto, DeckCommon, DeckKind as DeckKindProto, FilteredDeck, NormalDeck, Deck as DeckProto, DeckCommon, DeckKind as DeckKindProto, FilteredDeck, NormalDeck,
}; };
use crate::{backend_proto as pb, markdown::render_markdown, text::sanitize_html_no_images};
use crate::{ use crate::{
backend_proto as pb,
collection::Collection, collection::Collection,
deckconf::DeckConfId, deckconf::DeckConfId,
define_newtype, define_newtype,
error::FilteredDeckError,
error::{AnkiError, Result}, error::{AnkiError, Result},
markdown::render_markdown,
prelude::*, prelude::*,
text::normalize_to_nfc, text::normalize_to_nfc,
text::sanitize_html_no_images,
timestamp::TimestampSecs, timestamp::TimestampSecs,
types::Usn, types::Usn,
}; };
@ -421,7 +424,7 @@ impl Collection {
let child_split: Vec<_> = deck.name.split('\x1f').collect(); let child_split: Vec<_> = deck.name.split('\x1f').collect();
if let Some(parent_deck) = self.first_existing_parent(&deck.name, 0)? { if let Some(parent_deck) = self.first_existing_parent(&deck.name, 0)? {
if parent_deck.is_filtered() { if parent_deck.is_filtered() {
return Err(AnkiError::DeckIsFiltered); return Err(FilteredDeckError::MustBeLeafNode.into());
} }
let parent_count = parent_deck.name.matches('\x1f').count() + 1; let parent_count = parent_deck.name.matches('\x1f').count() + 1;
let need_create = parent_count != child_split.len() - 1; let need_create = parent_count != child_split.len() - 1;
@ -654,7 +657,7 @@ impl Collection {
if let Some(target) = new_parent { if let Some(target) = new_parent {
if let Some(target) = self.storage.get_deck(target)? { if let Some(target) = self.storage.get_deck(target)? {
if target.is_filtered() { if target.is_filtered() {
return Err(AnkiError::DeckIsFiltered); return Err(FilteredDeckError::MustBeLeafNode.into());
} }
target_deck = target; target_deck = target;
target_name = Some(target_deck.name.as_str()); target_name = Some(target_deck.name.as_str());

View file

@ -0,0 +1,32 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use anki_i18n::I18n;
use super::AnkiError;
#[derive(Debug, PartialEq)]
pub enum FilteredDeckError {
MustBeLeafNode,
CanNotMoveCardsInto,
SearchReturnedNoCards,
}
impl FilteredDeckError {
pub fn localized_description(&self, tr: &I18n) -> String {
match self {
FilteredDeckError::MustBeLeafNode => tr.errors_filtered_parent_deck(),
FilteredDeckError::CanNotMoveCardsInto => {
tr.browsing_cards_cant_be_manually_moved_into()
}
FilteredDeckError::SearchReturnedNoCards => tr.decks_filtered_deck_search_empty(),
}
.into()
}
}
impl From<FilteredDeckError> for AnkiError {
fn from(e: FilteredDeckError) -> Self {
AnkiError::FilteredDeckError(e)
}
}

View file

@ -2,11 +2,13 @@
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
mod db; mod db;
mod filtered;
mod network; mod network;
mod search; mod search;
pub use { pub use {
db::{DbError, DbErrorKind}, db::{DbError, DbErrorKind},
filtered::FilteredDeckError,
network::{NetworkError, NetworkErrorKind, SyncError, SyncErrorKind}, network::{NetworkError, NetworkErrorKind, SyncError, SyncErrorKind},
search::{ParseError, SearchErrorKind}, search::{ParseError, SearchErrorKind},
}; };
@ -34,9 +36,8 @@ pub enum AnkiError {
CollectionAlreadyOpen, CollectionAlreadyOpen,
NotFound, NotFound,
Existing, Existing,
DeckIsFiltered, FilteredDeckError(FilteredDeckError),
SearchError(SearchErrorKind), SearchError(SearchErrorKind),
FilteredDeckEmpty,
InvalidRegex(String), InvalidRegex(String),
} }
@ -73,8 +74,7 @@ impl AnkiError {
} }
} }
AnkiError::ParseNumError => tr.errors_parse_number_fail().into(), AnkiError::ParseNumError => tr.errors_parse_number_fail().into(),
AnkiError::DeckIsFiltered => tr.errors_filtered_parent_deck().into(), AnkiError::FilteredDeckError(err) => err.localized_description(tr),
AnkiError::FilteredDeckEmpty => tr.decks_filtered_deck_search_empty().into(),
_ => format!("{:?}", self), _ => format!("{:?}", self),
} }
} }

View file

@ -8,6 +8,7 @@ use std::convert::{TryFrom, TryInto};
use crate::{ use crate::{
config::ConfigKey, config::ConfigKey,
decks::{human_deck_name_to_native, FilteredDeck, FilteredSearchTerm}, decks::{human_deck_name_to_native, FilteredDeck, FilteredSearchTerm},
error::FilteredDeckError,
search::writer::{deck_search, normalize_search}, search::writer::{deck_search, normalize_search},
}; };
use crate::{ use crate::{
@ -176,7 +177,7 @@ impl Collection {
// if it failed to match any cards, we revert the changes // if it failed to match any cards, we revert the changes
if count == 0 { if count == 0 {
Err(AnkiError::FilteredDeckEmpty) Err(FilteredDeckError::SearchReturnedNoCards.into())
} else { } else {
// update current deck and return id // update current deck and return id
self.set_config(ConfigKey::CurrentDeckId, &deck.id)?; self.set_config(ConfigKey::CurrentDeckId, &deck.id)?;