2007-07-16 20:22:38 +00:00
|
|
|
import cherrypy
|
|
|
|
from Scheduler import Scheduler
|
|
|
|
from Expose import expose
|
|
|
|
from Validate import validate, Valid_string, Validation_error, Valid_bool
|
2007-08-23 23:56:42 +00:00
|
|
|
from Database import Valid_id, Valid_revision
|
2007-07-16 20:22:38 +00:00
|
|
|
from Users import grab_user_id
|
|
|
|
from Updater import wait_for_update, update_client
|
|
|
|
from Expire import strongly_expire
|
|
|
|
from Html_nuker import Html_nuker
|
|
|
|
from Async import async
|
|
|
|
from model.Notebook import Notebook
|
2007-07-17 01:21:31 +00:00
|
|
|
from model.Note import Note
|
2007-07-16 20:22:38 +00:00
|
|
|
from view.Main_page import Main_page
|
|
|
|
from view.Json import Json
|
|
|
|
from view.Html_file import Html_file
|
|
|
|
|
|
|
|
|
|
|
|
class Access_error( Exception ):
|
|
|
|
def __init__( self, message = None ):
|
|
|
|
if message is None:
|
2007-07-26 01:18:41 +00:00
|
|
|
message = u"You don't have access to this notebook."
|
2007-07-16 20:22:38 +00:00
|
|
|
|
|
|
|
Exception.__init__( self, message )
|
|
|
|
self.__message = message
|
|
|
|
|
|
|
|
def to_dict( self ):
|
|
|
|
return dict(
|
|
|
|
error = self.__message
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class Notebooks( object ):
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
|
|
|
Controller for dealing with notebooks and their notes, corresponding to the "/notebooks" URL.
|
|
|
|
"""
|
2007-07-16 20:22:38 +00:00
|
|
|
def __init__( self, scheduler, database ):
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
|
|
|
Create a new Notebooks object.
|
|
|
|
|
|
|
|
@type scheduler: controller.Scheduler
|
|
|
|
@param scheduler: scheduler to use for asynchronous calls
|
|
|
|
@type database: controller.Database
|
|
|
|
@param database: database that notebooks are stored in
|
|
|
|
@rtype: Notebooks
|
|
|
|
@return: newly constructed Notebooks
|
|
|
|
"""
|
2007-07-16 20:22:38 +00:00
|
|
|
self.__scheduler = scheduler
|
|
|
|
self.__database = database
|
|
|
|
|
|
|
|
@expose( view = Main_page )
|
|
|
|
@validate(
|
|
|
|
notebook_id = Valid_id(),
|
2007-07-28 04:23:17 +00:00
|
|
|
note_id = Valid_id(),
|
2007-08-29 00:50:46 +00:00
|
|
|
parent_id = Valid_id(),
|
2007-08-23 23:56:42 +00:00
|
|
|
revision = Valid_revision(),
|
2007-07-16 20:22:38 +00:00
|
|
|
)
|
2007-08-29 00:50:46 +00:00
|
|
|
def default( self, notebook_id, note_id = None, parent_id = None, revision = None ):
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
|
|
|
Provide the information necessary to display the page for a particular notebook. If a
|
|
|
|
particular note id is given without a revision, then the most recent version of that note is
|
|
|
|
displayed.
|
|
|
|
|
|
|
|
@type notebook_id: unicode
|
|
|
|
@param notebook_id: id of the notebook to display
|
|
|
|
@type note_id: unicode or NoneType
|
|
|
|
@param note_id: id of single note in this notebook to display (optional)
|
2007-08-29 00:50:46 +00:00
|
|
|
@type parent_id: unicode or NoneType
|
|
|
|
@param parent_id: id of parent notebook to this notebook (optional)
|
2007-08-09 19:06:01 +00:00
|
|
|
@type revision: unicode or NoneType
|
|
|
|
@param revision: revision timestamp of the provided note (optional)
|
|
|
|
@rtype: unicode
|
|
|
|
@return: rendered HTML page
|
|
|
|
"""
|
2007-07-16 20:22:38 +00:00
|
|
|
return dict(
|
|
|
|
notebook_id = notebook_id,
|
2007-07-28 04:23:17 +00:00
|
|
|
note_id = note_id,
|
2007-08-29 00:50:46 +00:00
|
|
|
parent_id = parent_id,
|
2007-07-31 22:53:57 +00:00
|
|
|
revision = revision,
|
2007-07-16 20:22:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
@expose( view = Json )
|
|
|
|
@strongly_expire
|
|
|
|
@wait_for_update
|
|
|
|
@grab_user_id
|
|
|
|
@async
|
|
|
|
@update_client
|
|
|
|
@validate(
|
|
|
|
notebook_id = Valid_id(),
|
2007-07-28 04:23:17 +00:00
|
|
|
note_id = Valid_id( none_okay = True ),
|
2007-07-31 22:53:57 +00:00
|
|
|
revision = Valid_string( min = 0, max = 30 ),
|
2007-07-16 20:22:38 +00:00
|
|
|
user_id = Valid_id( none_okay = True ),
|
|
|
|
)
|
2007-07-31 22:53:57 +00:00
|
|
|
def contents( self, notebook_id, note_id = None, revision = None, user_id = None ):
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
|
|
|
Return the information on particular notebook, including the contents of its startup notes.
|
|
|
|
Optionally include the contents of a single requested note as well.
|
|
|
|
|
|
|
|
@type notebook_id: unicode
|
|
|
|
@param notebook_id: id of notebook to return
|
|
|
|
@type note_id: unicode or NoneType
|
|
|
|
@param note_id: id of single note in this notebook to return (optional)
|
|
|
|
@type revision: unicode or NoneType
|
|
|
|
@param revision: revision timestamp of the provided note (optional)
|
|
|
|
@type user_id: unicode or NoneType
|
|
|
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
|
|
|
@rtype: json dict
|
|
|
|
@return: { 'notebook': notebookdict, 'note': notedict or None }
|
|
|
|
@raise Access_error: the current user doesn't have access to the given notebook
|
2007-08-09 19:44:26 +00:00
|
|
|
@raise Validation_error: one of the arguments is invalid
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
2007-07-16 20:22:38 +00:00
|
|
|
self.check_access( notebook_id, user_id, self.__scheduler.thread )
|
|
|
|
if not ( yield Scheduler.SLEEP ):
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
self.__database.load( notebook_id, self.__scheduler.thread )
|
|
|
|
notebook = ( yield Scheduler.SLEEP )
|
|
|
|
|
2007-07-31 22:53:57 +00:00
|
|
|
if notebook is None:
|
|
|
|
note = None
|
|
|
|
else:
|
|
|
|
note = notebook.lookup_note( note_id )
|
|
|
|
|
|
|
|
if revision:
|
|
|
|
self.__database.load( note_id, self.__scheduler.thread, revision )
|
|
|
|
note = ( yield Scheduler.SLEEP )
|
|
|
|
|
2007-07-16 20:22:38 +00:00
|
|
|
yield dict(
|
|
|
|
notebook = notebook,
|
2007-08-27 22:37:22 +00:00
|
|
|
startup_notes = notebook.startup_notes,
|
2007-07-31 22:53:57 +00:00
|
|
|
note = note,
|
2007-07-16 20:22:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
@expose( view = Json )
|
|
|
|
@strongly_expire
|
|
|
|
@wait_for_update
|
|
|
|
@grab_user_id
|
|
|
|
@async
|
|
|
|
@update_client
|
|
|
|
@validate(
|
|
|
|
notebook_id = Valid_id(),
|
2007-07-17 01:21:31 +00:00
|
|
|
note_id = Valid_id(),
|
2007-08-23 23:56:42 +00:00
|
|
|
revision = Valid_revision(),
|
2007-07-16 20:22:38 +00:00
|
|
|
user_id = Valid_id( none_okay = True ),
|
|
|
|
)
|
2007-07-31 22:53:57 +00:00
|
|
|
def load_note( self, notebook_id, note_id, revision = None, user_id = None ):
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
|
|
|
Return the information on a particular note by its id.
|
|
|
|
|
|
|
|
@type notebook_id: unicode
|
|
|
|
@param notebook_id: id of notebook the note is in
|
|
|
|
@type note_id: unicode
|
|
|
|
@param note_id: id of note to return
|
|
|
|
@type revision: unicode or NoneType
|
|
|
|
@param revision: revision timestamp of the note (optional)
|
|
|
|
@type user_id: unicode or NoneType
|
|
|
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
|
|
|
@rtype: json dict
|
|
|
|
@return: { 'note': notedict or None }
|
|
|
|
@raise Access_error: the current user doesn't have access to the given notebook
|
2007-08-09 19:44:26 +00:00
|
|
|
@raise Validation_error: one of the arguments is invalid
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
2007-07-16 20:22:38 +00:00
|
|
|
self.check_access( notebook_id, user_id, self.__scheduler.thread )
|
|
|
|
if not ( yield Scheduler.SLEEP ):
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
self.__database.load( notebook_id, self.__scheduler.thread )
|
|
|
|
notebook = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
if notebook is None:
|
2007-07-17 01:21:31 +00:00
|
|
|
note = None
|
2007-07-16 20:22:38 +00:00
|
|
|
else:
|
2007-07-17 01:21:31 +00:00
|
|
|
note = notebook.lookup_note( note_id )
|
2007-07-16 20:22:38 +00:00
|
|
|
|
2007-07-31 22:53:57 +00:00
|
|
|
if revision:
|
|
|
|
self.__database.load( note_id, self.__scheduler.thread, revision )
|
|
|
|
note = ( yield Scheduler.SLEEP )
|
|
|
|
|
2007-07-16 20:22:38 +00:00
|
|
|
yield dict(
|
2007-07-17 01:21:31 +00:00
|
|
|
note = note,
|
2007-07-16 20:22:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
@expose( view = Json )
|
|
|
|
@strongly_expire
|
|
|
|
@wait_for_update
|
|
|
|
@grab_user_id
|
|
|
|
@async
|
|
|
|
@update_client
|
|
|
|
@validate(
|
|
|
|
notebook_id = Valid_id(),
|
2007-07-17 01:21:31 +00:00
|
|
|
note_title = Valid_string( min = 1, max = 500 ),
|
2007-07-16 20:22:38 +00:00
|
|
|
user_id = Valid_id( none_okay = True ),
|
|
|
|
)
|
2007-07-17 01:21:31 +00:00
|
|
|
def load_note_by_title( self, notebook_id, note_title, user_id ):
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
|
|
|
Return the information on a particular note by its title.
|
|
|
|
|
|
|
|
@type notebook_id: unicode
|
|
|
|
@param notebook_id: id of notebook the note is in
|
|
|
|
@type note_title: unicode
|
|
|
|
@param note_title: title of the note to return
|
|
|
|
@type user_id: unicode or NoneType
|
|
|
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
|
|
|
@rtype: json dict
|
|
|
|
@return: { 'note': notedict or None }
|
|
|
|
@raise Access_error: the current user doesn't have access to the given notebook
|
2007-08-09 19:44:26 +00:00
|
|
|
@raise Validation_error: one of the arguments is invalid
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
2007-07-16 20:22:38 +00:00
|
|
|
self.check_access( notebook_id, user_id, self.__scheduler.thread )
|
|
|
|
if not ( yield Scheduler.SLEEP ):
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
self.__database.load( notebook_id, self.__scheduler.thread )
|
|
|
|
notebook = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
if notebook is None:
|
2007-07-17 01:21:31 +00:00
|
|
|
note = None
|
2007-07-16 20:22:38 +00:00
|
|
|
else:
|
2007-07-17 01:21:31 +00:00
|
|
|
note = notebook.lookup_note_by_title( note_title )
|
2007-07-16 20:22:38 +00:00
|
|
|
|
|
|
|
yield dict(
|
2007-07-17 01:21:31 +00:00
|
|
|
note = note,
|
2007-07-16 20:22:38 +00:00
|
|
|
)
|
|
|
|
|
2007-08-14 04:13:49 +00:00
|
|
|
@expose( view = Json )
|
|
|
|
@strongly_expire
|
|
|
|
@wait_for_update
|
|
|
|
@grab_user_id
|
|
|
|
@async
|
|
|
|
@update_client
|
|
|
|
@validate(
|
|
|
|
notebook_id = Valid_id(),
|
|
|
|
note_title = Valid_string( min = 1, max = 500 ),
|
|
|
|
user_id = Valid_id( none_okay = True ),
|
|
|
|
)
|
|
|
|
def lookup_note_id( self, notebook_id, note_title, user_id ):
|
|
|
|
"""
|
|
|
|
Return a note's id by looking up its title.
|
|
|
|
|
|
|
|
@type notebook_id: unicode
|
|
|
|
@param notebook_id: id of notebook the note is in
|
|
|
|
@type note_title: unicode
|
|
|
|
@param note_title: title of the note id to return
|
|
|
|
@type user_id: unicode or NoneType
|
|
|
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
|
|
|
@rtype: json dict
|
|
|
|
@return: { 'note_id': noteid or None }
|
|
|
|
@raise Access_error: the current user doesn't have access to the given notebook
|
|
|
|
@raise Validation_error: one of the arguments is invalid
|
|
|
|
"""
|
|
|
|
self.check_access( notebook_id, user_id, self.__scheduler.thread )
|
|
|
|
if not ( yield Scheduler.SLEEP ):
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
self.__database.load( notebook_id, self.__scheduler.thread )
|
|
|
|
notebook = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
if notebook is None:
|
|
|
|
note = None
|
|
|
|
else:
|
|
|
|
note = notebook.lookup_note_by_title( note_title )
|
|
|
|
|
|
|
|
yield dict(
|
|
|
|
note_id = note and note.object_id or None,
|
|
|
|
)
|
|
|
|
|
2007-07-16 20:22:38 +00:00
|
|
|
@expose( view = Json )
|
|
|
|
@wait_for_update
|
|
|
|
@grab_user_id
|
|
|
|
@async
|
|
|
|
@update_client
|
|
|
|
@validate(
|
|
|
|
notebook_id = Valid_id(),
|
2007-07-17 01:21:31 +00:00
|
|
|
note_id = Valid_id(),
|
2007-07-16 20:22:38 +00:00
|
|
|
contents = Valid_string( min = 1, max = 25000, escape_html = False ),
|
|
|
|
startup = Valid_bool(),
|
2007-08-23 23:56:42 +00:00
|
|
|
previous_revision = Valid_revision( none_okay = True ),
|
2007-07-16 20:22:38 +00:00
|
|
|
user_id = Valid_id( none_okay = True ),
|
|
|
|
)
|
2007-08-23 23:56:42 +00:00
|
|
|
def save_note( self, notebook_id, note_id, contents, startup, previous_revision, user_id ):
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
|
|
|
Save a new revision of the given note. This function will work both for creating a new note and
|
|
|
|
for updating an existing note. If the note exists and the given contents are identical to the
|
2007-08-23 23:56:42 +00:00
|
|
|
existing contents for the given previous_revision, then no saving takes place and a new_revision
|
|
|
|
of None is returned. Otherwise this method returns the timestamp of the new revision.
|
2007-08-09 19:06:01 +00:00
|
|
|
|
|
|
|
@type notebook_id: unicode
|
|
|
|
@param notebook_id: id of notebook the note is in
|
|
|
|
@type note_id: unicode
|
|
|
|
@param note_id: id of note to save
|
|
|
|
@type contents: unicode
|
|
|
|
@param contents: new textual contents of the note, including its title
|
|
|
|
@type startup: bool
|
|
|
|
@param startup: whether the note should be displayed on startup
|
2007-08-23 23:56:42 +00:00
|
|
|
@type previous_revision: unicode or NoneType
|
|
|
|
@param previous_revision: previous known revision timestamp of the provided note, or None if
|
|
|
|
the note is new
|
2007-08-09 19:06:01 +00:00
|
|
|
@type user_id: unicode or NoneType
|
|
|
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
|
|
|
@rtype: json dict
|
2007-08-23 23:56:42 +00:00
|
|
|
@return: {
|
|
|
|
'new_revision': new revision of saved note, or None if nothing was saved,
|
|
|
|
'previous_revision': revision immediately before new_revision, or None if the note is new
|
|
|
|
}
|
2007-08-09 19:06:01 +00:00
|
|
|
@raise Access_error: the current user doesn't have access to the given notebook
|
2007-08-09 19:44:26 +00:00
|
|
|
@raise Validation_error: one of the arguments is invalid
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
2007-07-16 20:22:38 +00:00
|
|
|
self.check_access( notebook_id, user_id, self.__scheduler.thread )
|
|
|
|
if not ( yield Scheduler.SLEEP ):
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
self.__database.load( notebook_id, self.__scheduler.thread )
|
|
|
|
notebook = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
if not notebook:
|
2007-07-26 01:18:41 +00:00
|
|
|
raise Access_error()
|
2007-07-16 20:22:38 +00:00
|
|
|
|
2007-07-17 01:21:31 +00:00
|
|
|
self.__database.load( note_id, self.__scheduler.thread )
|
|
|
|
note = ( yield Scheduler.SLEEP )
|
2007-07-16 20:22:38 +00:00
|
|
|
|
2007-08-24 20:35:06 +00:00
|
|
|
# check whether the provided note contents have been changed since the previous revision
|
|
|
|
def update_note( current_notebook, old_note ):
|
2007-08-23 23:56:42 +00:00
|
|
|
# the note hasn't been changed, so bail without updating it
|
|
|
|
if contents == old_note.contents:
|
|
|
|
new_revision = None
|
|
|
|
# the note has changed, so update it
|
|
|
|
else:
|
|
|
|
notebook.update_note( note, contents )
|
|
|
|
new_revision = note.revision
|
2007-08-24 20:35:06 +00:00
|
|
|
|
|
|
|
return new_revision
|
|
|
|
|
|
|
|
# if the note is already in the given notebook, load it and update it
|
|
|
|
if note and note in notebook.notes:
|
|
|
|
self.__database.load( note_id, self.__scheduler.thread, previous_revision )
|
|
|
|
old_note = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
previous_revision = note.revision
|
|
|
|
new_revision = update_note( notebook, old_note )
|
|
|
|
|
|
|
|
# the note is not already in the given notebook, so look for it in the trash
|
|
|
|
elif note and notebook.trash and note in notebook.trash.notes:
|
|
|
|
self.__database.load( note_id, self.__scheduler.thread, previous_revision )
|
|
|
|
old_note = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
# undelete the note, putting it back in the given notebook
|
|
|
|
previous_revision = note.revision
|
|
|
|
notebook.trash.remove_note( note )
|
|
|
|
note.deleted_from = None
|
|
|
|
notebook.add_note( note )
|
|
|
|
|
|
|
|
new_revision = update_note( notebook, old_note )
|
|
|
|
|
|
|
|
# otherwise, create a new note
|
2007-07-16 20:22:38 +00:00
|
|
|
else:
|
2007-08-23 23:56:42 +00:00
|
|
|
previous_revision = None
|
2007-07-17 01:21:31 +00:00
|
|
|
note = Note( note_id, contents )
|
|
|
|
notebook.add_note( note )
|
2007-08-23 23:56:42 +00:00
|
|
|
new_revision = note.revision
|
2007-07-16 20:22:38 +00:00
|
|
|
|
|
|
|
if startup:
|
2007-08-23 23:56:42 +00:00
|
|
|
startup_changed = notebook.add_startup_note( note )
|
2007-07-16 20:22:38 +00:00
|
|
|
else:
|
2007-08-23 23:56:42 +00:00
|
|
|
startup_changed = notebook.remove_startup_note( note )
|
2007-07-16 20:22:38 +00:00
|
|
|
|
2007-08-23 23:56:42 +00:00
|
|
|
if new_revision or startup_changed:
|
|
|
|
self.__database.save( notebook )
|
2007-07-16 20:22:38 +00:00
|
|
|
|
2007-08-23 23:56:42 +00:00
|
|
|
yield dict(
|
|
|
|
new_revision = new_revision,
|
|
|
|
previous_revision = previous_revision,
|
|
|
|
)
|
2007-07-16 20:22:38 +00:00
|
|
|
|
|
|
|
@expose( view = Json )
|
|
|
|
@wait_for_update
|
|
|
|
@grab_user_id
|
|
|
|
@async
|
|
|
|
@update_client
|
|
|
|
@validate(
|
|
|
|
notebook_id = Valid_id(),
|
2007-07-17 01:21:31 +00:00
|
|
|
note_id = Valid_id(),
|
2007-07-16 20:22:38 +00:00
|
|
|
user_id = Valid_id( none_okay = True ),
|
|
|
|
)
|
2007-07-17 01:21:31 +00:00
|
|
|
def add_startup_note( self, notebook_id, note_id, user_id ):
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
|
|
|
Designate a particular note to be shown upon startup, e.g. whenever its notebook is displayed.
|
|
|
|
The given note must already be within this notebook.
|
|
|
|
|
|
|
|
@type notebook_id: unicode
|
|
|
|
@param notebook_id: id of notebook the note is in
|
|
|
|
@type note_id: unicode
|
|
|
|
@param note_id: id of note to show on startup
|
|
|
|
@type user_id: unicode or NoneType
|
|
|
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
|
|
|
@rtype: json dict
|
|
|
|
@return: {}
|
|
|
|
@raise Access_error: the current user doesn't have access to the given notebook
|
2007-08-09 19:44:26 +00:00
|
|
|
@raise Validation_error: one of the arguments is invalid
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
2007-07-16 20:22:38 +00:00
|
|
|
self.check_access( notebook_id, user_id, self.__scheduler.thread )
|
|
|
|
if not ( yield Scheduler.SLEEP ):
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
self.__database.load( notebook_id, self.__scheduler.thread )
|
|
|
|
notebook = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
if not notebook:
|
2007-07-26 01:18:41 +00:00
|
|
|
raise Access_error()
|
2007-07-16 20:22:38 +00:00
|
|
|
|
2007-07-17 01:21:31 +00:00
|
|
|
self.__database.load( note_id, self.__scheduler.thread )
|
|
|
|
note = ( yield Scheduler.SLEEP )
|
2007-07-16 20:22:38 +00:00
|
|
|
|
2007-07-17 01:21:31 +00:00
|
|
|
if note:
|
|
|
|
notebook.add_startup_note( note )
|
2007-07-16 20:22:38 +00:00
|
|
|
self.__database.save( notebook )
|
|
|
|
|
|
|
|
yield dict()
|
|
|
|
|
|
|
|
@expose( view = Json )
|
|
|
|
@wait_for_update
|
|
|
|
@grab_user_id
|
|
|
|
@async
|
|
|
|
@update_client
|
|
|
|
@validate(
|
|
|
|
notebook_id = Valid_id(),
|
2007-07-17 01:21:31 +00:00
|
|
|
note_id = Valid_id(),
|
2007-07-16 20:22:38 +00:00
|
|
|
user_id = Valid_id( none_okay = True ),
|
|
|
|
)
|
2007-07-17 01:21:31 +00:00
|
|
|
def remove_startup_note( self, notebook_id, note_id, user_id ):
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
|
|
|
Prevent a particular note from being shown on startup, e.g. whenever its notebook is displayed.
|
|
|
|
The given note must already be within this notebook.
|
|
|
|
|
|
|
|
@type notebook_id: unicode
|
|
|
|
@param notebook_id: id of notebook the note is in
|
|
|
|
@type note_id: unicode
|
|
|
|
@param note_id: id of note to no longer show on startup
|
|
|
|
@type user_id: unicode or NoneType
|
|
|
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
|
|
|
@rtype: json dict
|
|
|
|
@return: {}
|
|
|
|
@raise Access_error: the current user doesn't have access to the given notebook
|
2007-08-09 19:44:26 +00:00
|
|
|
@raise Validation_error: one of the arguments is invalid
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
2007-07-16 20:22:38 +00:00
|
|
|
self.check_access( notebook_id, user_id, self.__scheduler.thread )
|
|
|
|
if not ( yield Scheduler.SLEEP ):
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
self.__database.load( notebook_id, self.__scheduler.thread )
|
|
|
|
notebook = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
if not notebook:
|
2007-07-26 01:18:41 +00:00
|
|
|
raise Access_error()
|
2007-07-16 20:22:38 +00:00
|
|
|
|
2007-07-17 01:21:31 +00:00
|
|
|
self.__database.load( note_id, self.__scheduler.thread )
|
|
|
|
note = ( yield Scheduler.SLEEP )
|
2007-07-16 20:22:38 +00:00
|
|
|
|
2007-07-17 01:21:31 +00:00
|
|
|
if note:
|
|
|
|
notebook.remove_startup_note( note )
|
2007-07-16 20:22:38 +00:00
|
|
|
self.__database.save( notebook )
|
|
|
|
|
|
|
|
yield dict()
|
|
|
|
|
|
|
|
@expose( view = Json )
|
|
|
|
@wait_for_update
|
|
|
|
@grab_user_id
|
|
|
|
@async
|
|
|
|
@update_client
|
|
|
|
@validate(
|
|
|
|
notebook_id = Valid_id(),
|
2007-07-17 01:21:31 +00:00
|
|
|
note_id = Valid_id(),
|
2007-07-16 20:22:38 +00:00
|
|
|
user_id = Valid_id( none_okay = True ),
|
|
|
|
)
|
2007-07-17 01:21:31 +00:00
|
|
|
def delete_note( self, notebook_id, note_id, user_id ):
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
|
|
|
Delete the given note from its notebook and move it to the notebook's trash. The note is added
|
2007-09-01 21:06:37 +00:00
|
|
|
as a startup note within the trash. If the given notebook is the trash and the given note is
|
|
|
|
already there, then it is deleted from the trash forever.
|
2007-08-09 19:06:01 +00:00
|
|
|
|
|
|
|
@type notebook_id: unicode
|
|
|
|
@param notebook_id: id of notebook the note is in
|
|
|
|
@type note_id: unicode
|
|
|
|
@param note_id: id of note to delete
|
|
|
|
@type user_id: unicode or NoneType
|
|
|
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
|
|
|
@rtype: json dict
|
|
|
|
@return: {}
|
|
|
|
@raise Access_error: the current user doesn't have access to the given notebook
|
2007-08-09 19:44:26 +00:00
|
|
|
@raise Validation_error: one of the arguments is invalid
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
2007-07-16 20:22:38 +00:00
|
|
|
self.check_access( notebook_id, user_id, self.__scheduler.thread )
|
|
|
|
if not ( yield Scheduler.SLEEP ):
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
self.__database.load( notebook_id, self.__scheduler.thread )
|
|
|
|
notebook = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
if not notebook:
|
2007-07-26 01:18:41 +00:00
|
|
|
raise Access_error()
|
2007-07-16 20:22:38 +00:00
|
|
|
|
2007-07-17 01:21:31 +00:00
|
|
|
self.__database.load( note_id, self.__scheduler.thread )
|
|
|
|
note = ( yield Scheduler.SLEEP )
|
2007-07-16 20:22:38 +00:00
|
|
|
|
2007-07-17 01:21:31 +00:00
|
|
|
if note:
|
|
|
|
notebook.remove_note( note )
|
2007-08-03 21:12:17 +00:00
|
|
|
|
|
|
|
if notebook.trash:
|
2007-08-07 01:48:43 +00:00
|
|
|
note.deleted_from = notebook.object_id
|
2007-08-03 21:12:17 +00:00
|
|
|
notebook.trash.add_note( note )
|
2007-08-07 01:48:43 +00:00
|
|
|
notebook.trash.add_startup_note( note )
|
|
|
|
|
|
|
|
self.__database.save( notebook )
|
|
|
|
|
|
|
|
yield dict()
|
|
|
|
|
|
|
|
@expose( view = Json )
|
|
|
|
@wait_for_update
|
|
|
|
@grab_user_id
|
|
|
|
@async
|
|
|
|
@update_client
|
|
|
|
@validate(
|
|
|
|
notebook_id = Valid_id(),
|
|
|
|
note_id = Valid_id(),
|
|
|
|
user_id = Valid_id( none_okay = True ),
|
|
|
|
)
|
|
|
|
def undelete_note( self, notebook_id, note_id, user_id ):
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
|
|
|
Undelete the given note from the trash, moving it back into its notebook. The note is added
|
|
|
|
as a startup note within its notebook.
|
|
|
|
|
|
|
|
@type notebook_id: unicode
|
|
|
|
@param notebook_id: id of notebook the note was in
|
|
|
|
@type note_id: unicode
|
|
|
|
@param note_id: id of note to undelete
|
|
|
|
@type user_id: unicode or NoneType
|
|
|
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
|
|
|
@rtype: json dict
|
|
|
|
@return: {}
|
|
|
|
@raise Access_error: the current user doesn't have access to the given notebook
|
2007-08-09 19:44:26 +00:00
|
|
|
@raise Validation_error: one of the arguments is invalid
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
2007-08-07 01:48:43 +00:00
|
|
|
self.check_access( notebook_id, user_id, self.__scheduler.thread )
|
|
|
|
if not ( yield Scheduler.SLEEP ):
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
self.__database.load( notebook_id, self.__scheduler.thread )
|
|
|
|
notebook = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
if not notebook:
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
self.__database.load( note_id, self.__scheduler.thread )
|
|
|
|
note = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
if note and notebook.trash:
|
2007-08-23 23:56:42 +00:00
|
|
|
# if the note isn't deleted, and it's already in this notebook, just return
|
|
|
|
if note.deleted_from is None and notebook.lookup_note( note.object_id ):
|
|
|
|
yield dict()
|
|
|
|
return
|
|
|
|
|
|
|
|
# if the note was deleted from a different notebook than the notebook given, raise
|
2007-08-07 01:48:43 +00:00
|
|
|
if note.deleted_from != notebook_id:
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
notebook.trash.remove_note( note )
|
|
|
|
|
|
|
|
note.deleted_from = None
|
|
|
|
notebook.add_note( note )
|
|
|
|
notebook.add_startup_note( note )
|
2007-08-03 21:12:17 +00:00
|
|
|
|
2007-07-16 20:22:38 +00:00
|
|
|
self.__database.save( notebook )
|
|
|
|
|
|
|
|
yield dict()
|
|
|
|
|
2007-09-01 21:06:37 +00:00
|
|
|
@expose( view = Json )
|
|
|
|
@wait_for_update
|
|
|
|
@grab_user_id
|
|
|
|
@async
|
|
|
|
@update_client
|
|
|
|
@validate(
|
|
|
|
notebook_id = Valid_id(),
|
|
|
|
user_id = Valid_id( none_okay = True ),
|
|
|
|
)
|
|
|
|
def delete_all_notes( self, notebook_id, user_id ):
|
|
|
|
"""
|
|
|
|
Delete all notes from the given notebook and move them to the notebook's trash (if any). The
|
|
|
|
notes are added as startup notes within the trash. If the given notebook is the trash, then
|
|
|
|
all notes in the trash are deleted forever.
|
|
|
|
|
|
|
|
@type notebook_id: unicode
|
|
|
|
@param notebook_id: id of notebook the note is in
|
|
|
|
@type user_id: unicode or NoneType
|
|
|
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
|
|
|
@rtype: json dict
|
|
|
|
@return: {}
|
|
|
|
@raise Access_error: the current user doesn't have access to the given notebook
|
|
|
|
@raise Validation_error: one of the arguments is invalid
|
|
|
|
"""
|
|
|
|
self.check_access( notebook_id, user_id, self.__scheduler.thread )
|
|
|
|
if not ( yield Scheduler.SLEEP ):
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
self.__database.load( notebook_id, self.__scheduler.thread )
|
|
|
|
notebook = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
if not notebook:
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
for note in notebook.notes:
|
|
|
|
notebook.remove_note( note )
|
|
|
|
|
|
|
|
if notebook.trash:
|
|
|
|
note.deleted_from = notebook.object_id
|
|
|
|
notebook.trash.add_note( note )
|
|
|
|
notebook.trash.add_startup_note( note )
|
|
|
|
|
|
|
|
self.__database.save( notebook )
|
|
|
|
|
|
|
|
yield dict()
|
2007-07-16 20:22:38 +00:00
|
|
|
|
|
|
|
@expose( view = Json )
|
|
|
|
@strongly_expire
|
|
|
|
@wait_for_update
|
|
|
|
@grab_user_id
|
|
|
|
@async
|
|
|
|
@update_client
|
|
|
|
@validate(
|
|
|
|
notebook_id = Valid_id(),
|
|
|
|
search_text = Valid_string( min = 0, max = 100 ),
|
|
|
|
user_id = Valid_id( none_okay = True ),
|
2007-08-17 22:26:02 +00:00
|
|
|
titles_only = Valid_bool(),
|
2007-07-16 20:22:38 +00:00
|
|
|
)
|
2007-08-17 22:26:02 +00:00
|
|
|
def search( self, notebook_id, search_text, titles_only, user_id ):
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
|
|
|
Search the notes within a particular notebook for the given search text. Note that the search
|
|
|
|
is case-insensitive, and all HTML tags are ignored. The matching notes are returned with title
|
|
|
|
matches first, followed by all other matches.
|
|
|
|
|
|
|
|
@type notebook_id: unicode
|
|
|
|
@param notebook_id: id of notebook to search
|
2007-08-17 22:26:02 +00:00
|
|
|
@type search_text: unicode
|
|
|
|
@param search_text: search term
|
|
|
|
@type titles_only: bool
|
|
|
|
@param titles_only: if true, only search titles. if false, search all note titles and contents
|
2007-08-09 19:06:01 +00:00
|
|
|
@type user_id: unicode or NoneType
|
|
|
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
|
|
|
@rtype: json dict
|
|
|
|
@return: { 'notes': [ matching notes ] }
|
|
|
|
@raise Access_error: the current user doesn't have access to the given notebook
|
2007-08-09 19:44:26 +00:00
|
|
|
@raise Validation_error: one of the arguments is invalid
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
2007-07-16 20:22:38 +00:00
|
|
|
self.check_access( notebook_id, user_id, self.__scheduler.thread )
|
|
|
|
if not ( yield Scheduler.SLEEP ):
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
self.__database.load( notebook_id, self.__scheduler.thread )
|
|
|
|
notebook = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
if not notebook:
|
2007-07-26 01:18:41 +00:00
|
|
|
raise Access_error()
|
2007-07-16 20:22:38 +00:00
|
|
|
|
|
|
|
search_text = search_text.lower()
|
|
|
|
title_matches = []
|
|
|
|
content_matches = []
|
|
|
|
nuker = Html_nuker()
|
|
|
|
|
|
|
|
if len( search_text ) > 0:
|
2007-07-17 01:21:31 +00:00
|
|
|
for note in notebook.notes:
|
2007-07-24 21:12:12 +00:00
|
|
|
if note is None: continue
|
2007-07-17 01:21:31 +00:00
|
|
|
if search_text in nuker.nuke( note.title ).lower():
|
|
|
|
title_matches.append( note )
|
2007-08-17 22:26:02 +00:00
|
|
|
elif not titles_only and search_text in nuker.nuke( note.contents ).lower():
|
2007-07-17 01:21:31 +00:00
|
|
|
content_matches.append( note )
|
2007-07-16 20:22:38 +00:00
|
|
|
|
2007-07-17 01:21:31 +00:00
|
|
|
notes = title_matches + content_matches
|
2007-07-16 20:22:38 +00:00
|
|
|
|
|
|
|
yield dict(
|
2007-07-17 01:21:31 +00:00
|
|
|
notes = notes,
|
2007-07-16 20:22:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
@expose( view = Json )
|
|
|
|
@strongly_expire
|
|
|
|
@wait_for_update
|
|
|
|
@grab_user_id
|
|
|
|
@async
|
|
|
|
@update_client
|
|
|
|
@validate(
|
|
|
|
notebook_id = Valid_id(),
|
|
|
|
user_id = Valid_id( none_okay = True ),
|
|
|
|
)
|
2007-09-04 21:37:48 +00:00
|
|
|
def all_notes( self, notebook_id, user_id ):
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
2007-09-04 21:37:48 +00:00
|
|
|
Return ids and titles of all notes in this notebook, sorted by reverse chronological order.
|
2007-08-09 19:06:01 +00:00
|
|
|
|
|
|
|
@type notebook_id: unicode
|
2007-09-04 21:37:48 +00:00
|
|
|
@param notebook_id: id of notebook to pull notes from
|
2007-08-09 19:06:01 +00:00
|
|
|
@type user_id: unicode
|
|
|
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
|
|
|
@rtype: json dict
|
2007-09-04 21:37:48 +00:00
|
|
|
@return: { 'notes': [ ( noteid, notetitle ) ] }
|
2007-08-09 19:06:01 +00:00
|
|
|
@raise Access_error: the current user doesn't have access to the given notebook
|
2007-08-09 19:44:26 +00:00
|
|
|
@raise Validation_error: one of the arguments is invalid
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
2007-07-16 20:22:38 +00:00
|
|
|
self.check_access( notebook_id, user_id, self.__scheduler.thread )
|
|
|
|
if not ( yield Scheduler.SLEEP ):
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
self.__database.load( notebook_id, self.__scheduler.thread )
|
|
|
|
notebook = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
if not notebook:
|
2007-07-26 01:18:41 +00:00
|
|
|
raise Access_error()
|
2007-07-16 20:22:38 +00:00
|
|
|
|
2007-09-04 21:37:48 +00:00
|
|
|
notes = [ note for note in notebook.notes if note is not None and note.title is not None ]
|
2007-07-17 01:21:31 +00:00
|
|
|
notes.sort( lambda a, b: cmp( b.revision, a.revision ) )
|
2007-07-16 20:22:38 +00:00
|
|
|
|
|
|
|
yield dict(
|
2007-09-04 21:37:48 +00:00
|
|
|
notes = [ ( note.object_id, note.title ) for note in notes ]
|
2007-07-16 20:22:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
@expose( view = Html_file )
|
|
|
|
@strongly_expire
|
|
|
|
@wait_for_update
|
|
|
|
@grab_user_id
|
|
|
|
@async
|
|
|
|
@update_client
|
|
|
|
@validate(
|
|
|
|
notebook_id = Valid_id(),
|
|
|
|
user_id = Valid_id( none_okay = True ),
|
|
|
|
)
|
|
|
|
def download_html( self, notebook_id, user_id ):
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
2007-09-10 19:43:51 +00:00
|
|
|
Download the entire contents of the given notebook as a stand-alone HTML page (no JavaScript).
|
2007-08-09 19:06:01 +00:00
|
|
|
|
|
|
|
@type notebook_id: unicode
|
|
|
|
@param notebook_id: id of notebook to download
|
|
|
|
@type user_id: unicode
|
|
|
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
|
|
|
@rtype: unicode
|
|
|
|
@return: rendered HTML page
|
|
|
|
@raise Access_error: the current user doesn't have access to the given notebook
|
2007-08-09 19:44:26 +00:00
|
|
|
@raise Validation_error: one of the arguments is invalid
|
2007-08-09 19:06:01 +00:00
|
|
|
"""
|
2007-07-16 20:22:38 +00:00
|
|
|
self.check_access( notebook_id, user_id, self.__scheduler.thread )
|
|
|
|
if not ( yield Scheduler.SLEEP ):
|
|
|
|
raise Access_error()
|
|
|
|
|
|
|
|
self.__database.load( notebook_id, self.__scheduler.thread )
|
|
|
|
notebook = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
if not notebook:
|
2007-07-26 01:18:41 +00:00
|
|
|
raise Access_error()
|
2007-07-16 20:22:38 +00:00
|
|
|
|
2007-07-17 01:21:31 +00:00
|
|
|
normal_notes = list( set( notebook.notes ) - set( notebook.startup_notes ) )
|
|
|
|
normal_notes.sort( lambda a, b: -cmp( a.revision, b.revision ) )
|
2007-07-16 20:22:38 +00:00
|
|
|
|
|
|
|
yield dict(
|
|
|
|
notebook_name = notebook.name,
|
2007-07-18 20:17:58 +00:00
|
|
|
notes = [ note for note in notebook.startup_notes + normal_notes if note is not None ],
|
2007-07-16 20:22:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
@async
|
|
|
|
def check_access( self, notebook_id, user_id, callback ):
|
|
|
|
# check if the anonymous user has access to this notebook
|
2007-07-20 20:05:02 +00:00
|
|
|
self.__database.load( u"User anonymous", self.__scheduler.thread )
|
2007-07-16 20:22:38 +00:00
|
|
|
anonymous = ( yield Scheduler.SLEEP )
|
|
|
|
|
|
|
|
access = False
|
|
|
|
if anonymous.has_access( notebook_id ):
|
|
|
|
access = True
|
|
|
|
|
|
|
|
if user_id:
|
|
|
|
# check if the currently logged in user has access to this notebook
|
|
|
|
self.__database.load( user_id, self.__scheduler.thread )
|
|
|
|
user = ( yield Scheduler.SLEEP )
|
|
|
|
|
2007-07-31 22:53:57 +00:00
|
|
|
if user and user.has_access( notebook_id ):
|
2007-07-16 20:22:38 +00:00
|
|
|
access = True
|
|
|
|
|
|
|
|
yield callback, access
|
|
|
|
|
|
|
|
scheduler = property( lambda self: self.__scheduler )
|