embed deck config and expose to frontend

This commit is contained in:
Damien Elmes 2021-04-04 22:24:35 +10:00
parent 037df9522b
commit 42a4d11416
6 changed files with 103 additions and 74 deletions

View file

@ -39,7 +39,7 @@ from anki.cards import Card, CardId
from anki.config import Config, ConfigManager
from anki.consts import *
from anki.dbproxy import DBProxy
from anki.decks import Deck, DeckId, DeckManager
from anki.decks import Deck, DeckConfig, DeckConfigId, DeckId, DeckManager
from anki.errors import AbortSchemaModification, DBError
from anki.lang import FormatTimeSpan
from anki.media import MediaManager, media_paths_from_col_path
@ -335,6 +335,10 @@ class Collection:
"Get a new-style deck object. Currently read-only."
return self._backend.get_deck(id)
def get_deck_config(self, id: DeckConfigId) -> DeckConfig:
"Get a new-style deck config object. Currently read-only."
return self._backend.get_deck_config(id)
def get_notetype(self, id: NotetypeId) -> Notetype:
"""Get a new-style notetype object. This is not cached; avoid calling frequently."""
return self._backend.get_notetype(id)

View file

@ -32,12 +32,13 @@ DeckConfigDict = Dict[str, Any]
# currently only supports read-only access
Deck = _pb.Deck
DeckConfig = _pb.DeckConfig
DeckId = NewType("DeckId", int)
DeckConfId = NewType("DeckConfId", int)
DeckConfigId = NewType("DeckConfigId", int)
DEFAULT_DECK_ID = DeckId(1)
DEFAULT_DECK_CONF_ID = DeckConfId(1)
DEFAULT_DECK_CONF_ID = DeckConfigId(1)
class DecksDictProxy:
@ -128,7 +129,7 @@ class DeckManager:
self,
name: str,
create: bool = True,
type: DeckConfId = DeckConfId(0),
type: DeckConfigId = DeckConfigId(0),
) -> Optional[DeckId]:
"Add a deck with NAME. Reuse deck if already exists. Return id as int."
id = self.id_for_name(name)
@ -323,7 +324,7 @@ class DeckManager:
deck = self.get(did, default=False)
assert deck
if "conf" in deck:
dcid = DeckConfId(int(deck["conf"])) # may be a string
dcid = DeckConfigId(int(deck["conf"])) # may be a string
conf = self.get_config(dcid)
if not conf:
# fall back on default
@ -333,7 +334,7 @@ class DeckManager:
# dynamic decks have embedded conf
return deck
def get_config(self, conf_id: DeckConfId) -> Optional[DeckConfigDict]:
def get_config(self, conf_id: DeckConfigId) -> Optional[DeckConfigDict]:
try:
return from_json_bytes(self.col._backend.get_deck_config_legacy(conf_id))
except NotFoundError:
@ -358,10 +359,10 @@ class DeckManager:
def add_config_returning_id(
self, name: str, clone_from: Optional[DeckConfigDict] = None
) -> DeckConfId:
) -> DeckConfigId:
return self.add_config(name, clone_from)["id"]
def remove_config(self, id: DeckConfId) -> None:
def remove_config(self, id: DeckConfigId) -> None:
"Remove a configuration and update all decks using it."
self.col.modSchema(check=True)
for g in self.all():
@ -373,7 +374,7 @@ class DeckManager:
self.save(g)
self.col._backend.remove_deck_config(id)
def setConf(self, grp: DeckConfigDict, id: DeckConfId) -> None:
def setConf(self, grp: DeckConfigDict, id: DeckConfigId) -> None:
grp["conf"] = id
self.save(grp)

View file

@ -219,6 +219,7 @@ service CardRenderingService {
service DeckConfigService {
rpc AddOrUpdateDeckConfigLegacy(AddOrUpdateDeckConfigLegacyIn)
returns (DeckConfigId);
rpc GetDeckConfig(DeckConfigId) returns (DeckConfig);
rpc AllDeckConfigLegacy(Empty) returns (Json);
rpc GetDeckConfigLegacy(DeckConfigId) returns (Json);
rpc NewDeckConfigLegacy(Empty) returns (Json);
@ -294,7 +295,8 @@ service CardsService {
// These should be moved to a separate file in the future
///////////////////////////////////////////////////////////
message DeckConfigInner {
message DeckConfig {
message Config {
enum NewCardOrder {
NEW_CARD_ORDER_DUE = 0;
NEW_CARD_ORDER_RANDOM = 1;
@ -356,8 +358,12 @@ message DeckConfigInner {
bytes other = 255;
}
// Containers for passing around database objects
///////////////////////////////////////////////////////////
int64 id = 1;
string name = 2;
int64 mtime_secs = 3;
int32 usn = 4;
Config config = 5;
}
message Deck {
message Common {
@ -504,6 +510,9 @@ message Notetype {
repeated Template templates = 9;
}
// Database objects
///////////////////////////////////////////////////////////
message Note {
int64 id = 1;
string guid = 2;

View file

@ -38,6 +38,10 @@ impl DeckConfigService for Backend {
.map(Into::into)
}
fn get_deck_config(&self, input: pb::DeckConfigId) -> Result<pb::DeckConfig> {
self.with_col(|col| Ok(col.get_deck_config(input.into(), true)?.unwrap().into()))
}
fn get_deck_config_legacy(&self, input: pb::DeckConfigId) -> Result<pb::Json> {
self.with_col(|col| {
let conf = col.get_deck_config(input.into(), true)?.unwrap();
@ -58,3 +62,15 @@ impl DeckConfigService for Backend {
.map(Into::into)
}
}
impl From<DeckConf> for pb::DeckConfig {
fn from(c: DeckConf) -> Self {
pb::DeckConfig {
id: c.id.0,
name: c.name,
mtime_secs: c.mtime_secs.0,
usn: c.usn.0,
config: Some(c.inner),
}
}
}

View file

@ -11,8 +11,8 @@ use crate::{
};
pub use crate::backend_proto::{
deck_config_inner::{LeechAction, NewCardOrder, ReviewCardOrder, ReviewMix},
DeckConfigInner,
deck_config::config::{LeechAction, NewCardOrder, ReviewCardOrder, ReviewMix},
deck_config::Config as DeckConfigInner,
};
pub use schema11::{DeckConfSchema11, NewCardOrderSchema11};
/// Old deck config and cards table store 250% as 2500.

View file

@ -2,8 +2,7 @@
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use super::{DeckConf, DeckConfId, INITIAL_EASE_FACTOR_THOUSANDS};
use crate::backend_proto::deck_config_inner::NewCardOrder;
use crate::backend_proto::DeckConfigInner;
use super::{DeckConfigInner, NewCardOrder};
use crate::{serde::default_on_invalid, timestamp::TimestampSecs, types::Usn};
use serde_aux::field_attributes::deserialize_number_from_string;
use serde_derive::{Deserialize, Serialize};