witten
/
luminotes
Archived
1
0
Fork 0

* Increasing after_login max string size from 100 to 1000 to accomodate larger URLs.

* controller.Notebooks now takes (and stores) an https_url constructor parameter.
 * New controller.Notebooks.updates() method to produce an updates RSS feed for a particular notebook.
 * New controller.Notebooks.get_update_link() method to make a brief page with just a link for an updated note, referred to by the feed.
 * Implemented views for the new RSS feed.
 * Fixed bug in Rss_item's guid that caused newlines to be inserted before and after long URLs.
 * Still need to unit test new controller code.
This commit is contained in:
Dan Helfman 2008-04-22 23:24:30 +00:00
parent d3dce6f775
commit b316b2f4a3
6 changed files with 153 additions and 5 deletions

View File

@ -18,6 +18,8 @@ from view.Json import Json
from view.Html_file import Html_file
from view.Note_tree_area import Note_tree_area
from view.Notebook_rss import Notebook_rss
from view.Updates_rss import Updates_rss
from view.Update_link_page import Update_link_page
class Notebooks( object ):
@ -28,7 +30,7 @@ class Notebooks( object ):
"""
Controller for dealing with notebooks and their notes, corresponding to the "/notebooks" URL.
"""
def __init__( self, database, users, files ):
def __init__( self, database, users, files, https_url ):
"""
Create a new Notebooks object.
@ -39,11 +41,14 @@ class Notebooks( object ):
@type files: controller.Files
@param files: controller for all uploaded files, used here for deleting files that are no longer
referenced within saved notes
@type https_url: unicode
@param https_url: base URL to use for SSL http requests, or an empty string
@return: newly constructed Notebooks
"""
self.__database = database
self.__users = users
self.__files = files
self.__https_url = https_url
@expose( view = Main_page, rss = Notebook_rss )
@strongly_expire
@ -204,6 +209,70 @@ class Notebooks( object ):
invites = invites or [],
)
@expose( view = None, rss = Updates_rss )
@strongly_expire
@end_transaction
@validate(
notebook_id = Valid_id(),
notebook_name = Valid_string(),
)
def updates( self, notebook_id, notebook_name ):
"""
Provide the information necessary to display an updated notes RSS feed for the given notebook.
This method does not require any sort of login.
@type notebook_id: unicode
@param notebook_id: id of the notebook to provide updates for
@type notebook_name: unicode
@param notebook_name: name of the notebook to include in the RSS feed
@rtype: unicode
@return: rendered RSS feed
"""
notebook = self.__database.load( Notebook, notebook_id )
if not notebook:
raise Access_error()
recent_notes = self.__database.select_many( Note, notebook.sql_load_notes( start = 0, count = 10 ) )
return dict(
recent_notes = [ ( note.object_id, note.revision ) for note in recent_notes ],
notebook_id = notebook_id,
notebook_name = notebook_name,
https_url = self.__https_url,
)
@expose( view = Update_link_page )
@strongly_expire
@end_transaction
@validate(
notebook_id = Valid_id(),
notebook_name = Valid_string(),
note_id = Valid_id(),
revision = Valid_revision(),
)
def get_update_link( self, notebook_id, notebook_name, note_id, revision ):
"""
Provide the information necessary to display a link to an updated note. This method does not
require any sort of login.
@type notebook_id: unicode
@param notebook_id: id of the notebook the note is in
@type notebook_name: unicode
@param notebook_name: name of the notebook
@type note_id: unicode
@param note_id: id of the note to link to
@type revision: unicode
@param revision: ignored; present so RSS feed readers distinguish between different revisions
@rtype: unicode
@return: rendered HTML page
"""
return dict(
notebook_id = notebook_id,
notebook_name = notebook_name,
note_id = note_id,
https_url = self.__https_url,
)
@expose( view = Json )
@strongly_expire
@end_transaction

View File

@ -46,7 +46,7 @@ class Root( object ):
settings[ u"global" ].get( u"luminotes.rate_plans", [] ),
)
self.__files = Files( database, self.__users )
self.__notebooks = Notebooks( database, self.__users, self.__files )
self.__notebooks = Notebooks( database, self.__users, self.__files, settings[ u"global" ].get( u"luminotes.https_url", u"" ) )
self.__suppress_exceptions = suppress_exceptions # used for unit tests
@expose( Main_page )
@ -55,7 +55,7 @@ class Root( object ):
@validate(
note_title = unicode,
invite_id = Valid_id( none_okay = True ),
after_login = Valid_string( min = 0, max = 100 ),
after_login = Valid_string( min = 0, max = 1000 ),
plan = Valid_int( none_okay = True ),
user_id = Valid_id( none_okay = True ),
)

View File

@ -407,7 +407,7 @@ class Users( object ):
password = Valid_string( min = 1, max = 30 ),
login_button = unicode,
invite_id = Valid_id( none_okay = True ),
after_login = Valid_string( min = 0, max = 100 ),
after_login = Valid_string( min = 0, max = 1000 ),
)
def login( self, username, password, login_button, invite_id = None, after_login = None ):
"""

View File

@ -9,5 +9,7 @@ class Rss_item( Item ):
Link( link ),
Description( description ),
Dc_date( date ),
Guid( guid ),
# if we don't set the separator to empty, Node inserts newlines when the guid gets too long.
# newlines in guids make Thunderbird angry
Guid( guid, separator = u"" ),
)

28
view/Update_link_page.py Normal file
View File

@ -0,0 +1,28 @@
from Tags import Html, Head, Title, Body, A
class Update_link_page( Html ):
def __init__( self, notebook_id, notebook_name, note_id, https_url ):
if notebook_name == u"Luminotes":
notebook_path = u"/"
elif notebook_name == u"Luminotes user guide":
notebook_path = u"/guide"
elif notebook_name == u"Luminotes blog":
notebook_path = u"/blog"
else:
notebook_path = u"/notebooks/%s" % notebook_id
notebook_path = https_url + notebook_path
Html.__init__(
self,
Head(
Title( "Note updated" ),
),
Body(
u"A note in ",
A( u"this notebook", href = notebook_path ),
u"has been updated.",
A( u"View the note.", href = u"%s?note_id=%s" % ( notebook_path, note_id ) ),
),
)

49
view/Updates_rss.py Normal file
View File

@ -0,0 +1,49 @@
import cgi
from urllib import urlencode
from Rss_channel import Rss_channel
from Rss_item import Rss_item
class Updates_rss( Rss_channel ):
def __init__(
self,
recent_notes,
notebook_id,
notebook_name,
https_url,
):
if notebook_name == u"Luminotes":
notebook_path = u"/"
elif notebook_name == u"Luminotes user guide":
notebook_path = u"/guide"
elif notebook_name == u"Luminotes blog":
notebook_path = u"/blog"
else:
notebook_path = u"/notebooks/%s" % notebook_id
notebook_path = https_url + notebook_path
Rss_channel.__init__(
self,
cgi.escape( notebook_name ),
notebook_path,
u"Luminotes notebook",
[ Rss_item(
title = u"Note updated",
link = self.note_link( notebook_id, notebook_name, note_id, revision, https_url ),
description = cgi.escape( u'A note in <a href="%s">this notebook</a> has been updated. <a href="%s?note_id=%s">View the note.</a>' % ( notebook_path, notebook_path, note_id ) ),
date = revision.strftime( "%Y-%m-%dT%H:%M:%SZ" ),
guid = self.note_link( notebook_id, notebook_name, note_id, revision, https_url ),
) for ( note_id, revision ) in recent_notes ],
)
@staticmethod
def note_link( notebook_id, notebook_name, note_id, revision, https_url ):
query = urlencode( [
( u"notebook_id", notebook_id ),
( u"notebook_name", notebook_name ),
( u"note_id", note_id ),
( u"revision", unicode( revision ) ),
] )
return cgi.escape( u"%s/notebooks/get_update_link?%s" % ( https_url, query ) )