* Simplified the *HandlerGroup to *Handler.

* Added lots of operations connected with models and notes.
This commit is contained in:
David Snopek
2013-07-16 15:12:05 +01:00
parent 93094ebb48
commit 022235ec60
2 changed files with 190 additions and 44 deletions

View File

@@ -23,16 +23,11 @@ def noReturnValue(func):
return func
class RestHandlerBase(object):
"""Parent class for single handler callbacks."""
hasReturnValue = True
def __call__(self, collection, data, ids):
pass
class RestHandlerGroupBase(object):
"""Parent class for a handler group."""
hasReturnValue = True
class _RestHandlerWrapper(RestHandlerBase):
"""Wrapper for functions that we can't modify."""
def __init__(self, func_name, func, hasReturnValue=True):
self.func_name = func_name
self.func = func
@@ -44,7 +39,9 @@ class RestApp(object):
"""A WSGI app that implements RESTful operations on Collections, Decks and Cards."""
# Defines not only the valid handler types, but their position in the URL string
handler_types = ['collection', ['deck', 'note'], 'card']
# TODO: this broken - it allows a model to contain cards, for example.. We need to
# give a pattern for each handler type.
handler_types = ['collection', ['model', 'note', 'deck'], 'card']
def __init__(self, data_root, allowed_hosts='*', use_default_handlers=True, collection_manager=None):
from AnkiServer.threading import getCollectionManager
@@ -53,9 +50,9 @@ class RestApp(object):
self.allowed_hosts = allowed_hosts
if collection_manager is not None:
self.collection_manager = collection_manager
col = collection_manager
else:
self.collection_manager = getCollectionManager()
col = getCollectionManager()
self.handlers = {}
for type_list in self.handler_types:
@@ -65,10 +62,11 @@ class RestApp(object):
self.handlers[handler_type] = {}
if use_default_handlers:
self.add_handler_group('collection', CollectionHandlerGroup())
self.add_handler_group('note', NoteHandlerGroup())
self.add_handler_group('deck', DeckHandlerGroup())
self.add_handler_group('card', CardHandlerGroup())
self.add_handler_group('collection', CollectionHandler())
self.add_handler_group('note', NoteHandler())
self.add_handler_group('model', ModelHandler())
self.add_handler_group('deck', DeckHandler())
self.add_handler_group('card', CardHandler())
def add_handler(self, type, name, handler):
"""Adds a callback handler for a type (collection, deck, card) with a unique name.
@@ -77,7 +75,7 @@ class RestApp(object):
- 'name' is a unique name for the handler that gets used in the URL.
- 'handler' handler can be a Python method or a subclass of the RestHandlerBase class.
- 'handler' is a callable that takes (collection, data, ids).
"""
if self.handlers[type].has_key(name):
@@ -85,7 +83,7 @@ class RestApp(object):
self.handlers[type][name] = handler
def add_handler_group(self, type, group):
"""Adds several handlers for every public method on an object descended from RestHandlerGroup.
"""Adds several handlers for every public method on an object descended from RestHandlerBase.
This allows you to create a single class with several methods, so that you can quickly
create a group of related handlers."""
@@ -241,37 +239,117 @@ class RestApp(object):
else:
return Response(json.dumps(output), content_type='application/json')
class CollectionHandlerGroup(RestHandlerGroupBase):
class CollectionHandler(RestHandlerBase):
"""Default handler group for 'collection' type."""
#
# MODELS - Store fields definitions and templates for notes
#
def list_models(self, col, data, ids):
# This is already a list of dicts, so it doesn't need to be serialized
return col.models.all()
def find_model_by_name(self, col, data, ids):
# This is already a list of dicts, so it doesn't need to be serialized
return col.models.byName(data['model'])
#
# NOTES - Information (in fields per the model) that can generate a card
# (based on a template from the model).
#
def find_notes(self, col, data, ids):
query = data.get('query', '')
ids = col.findNotes(query)
if data.get('preload', False):
nodes = [NoteHandler._serialize(col.getNote(id)) for id in ids]
else:
nodes = [{'id': id} for id in ids]
return nodes
def add_note(self, col, data, ids):
from anki.notes import Note
if type(data['model']) in (str, unicode):
model = col.models.byName(data['model'])
else:
model = col.models.get(data['model'])
note = Note(col, model)
for name, value in data['fields'].items():
note[name] = value
if data.has_key('tags'):
note.setTagsFromStr(data['tags'])
col.addNote(note)
#
# DECKS - Groups of cards
#
def list_decks(self, col, data, ids):
# This is already a list of dicts, so it doesn't need to be serialized
return col.decks.all()
@noReturnValue
def select_deck(self, col, data, ids):
col.decks.select(data['deck_id'])
#
# CARD - A specific card in a deck with a history of review (generated from
# a note based on the template).
#
def find_cards(self, col, data, ids):
query = data.get('query', '')
ids = col.findCards(query)
if data.get('preload', False):
cards = [CardHandler._serialize(col.getCard(id)) for id in ids]
else:
cards = [{'id': id} for id in ids]
return cards
#
# SCHEDULER - Controls card review, ie. intervals, what cards are due, answering a card, etc.
#
@noReturnValue
def sched_reset(self, col, data, ids):
col.sched.reset()
class NoteHandlerGroup(RestHandlerGroupBase):
class ModelHandler(RestHandlerBase):
"""Default handler group for 'model' type."""
def field_names(self, col, data, ids):
model = col.models.get(ids[1])
if model is None:
raise HTTPNotFound()
return col.models.fieldNames(model)
class NoteHandler(RestHandlerBase):
"""Default handler group for 'note' type."""
@staticmethod
def _serialize_note(note):
def _serialize(note):
d = {
'id': note.id,
'model': note.model()['name'],
'tags': ' '.join(note.tags),
}
# TODO: do more stuff!
return d
def index(self, col, data, ids):
note = col.getNote(ids[1])
return self._serialize_note(note)
return self._serialize(note)
class DeckHandlerGroup(RestHandlerGroupBase):
class DeckHandler(RestHandlerBase):
"""Default handler group for 'deck' type."""
def next_card(self, col, data, ids):
@@ -282,13 +360,13 @@ class DeckHandlerGroup(RestHandlerGroupBase):
if card is None:
return None
return CardHandlerGroup._serialize_card(card)
return CardHandler._serialize(card)
class CardHandlerGroup(RestHandlerGroupBase):
class CardHandler(RestHandlerBase):
"""Default handler group for 'card' type."""
@staticmethod
def _serialize_card(card):
def _serialize(card):
d = {
'id': card.id
}