witten
/
luminotes
Archived
1
0
Fork 0

Lots of work on user storage quotas:

* Each model.User now has a current storage bytes and a rate plan.
 * model.User.to_dict() updated accordingly.
 * Minor Scheduler.add() change to bail of the given thread is None.
 * controller.Users.current() returns current user's rate plan details.
 * controller.Users.update_storage() now takes an optional callback.
 * Various methods in controller.Notebooks responsible for calling controller.Users.update_storage().
 * Added rate plan details to config/Common.py.
 * Added quota utilization colors to style.css.
 * Implemented quota utilization calculation and display in Wiki.js.

Still to-do: Return updated storage bytes where appropriate in controller.Notebook and update the
client accordingly.
This commit is contained in:
Dan Helfman 2007-09-20 20:36:19 +00:00
parent ebf1538313
commit 4d736d4821
13 changed files with 243 additions and 17 deletions

View File

@ -1,6 +1,9 @@
import cherrypy
MEGABYTE = 1024 * 1024
settings = {
"global": {
"server.socket_port": 8081,
@ -20,5 +23,19 @@ settings = {
"luminotes.http_proxy_ip": "127.0.0.1",
"luminotes.https_proxy_ip": "127.0.0.2",
"luminotes.support_email": "support@luminotes.com",
"luminotes.rate_plans": [
{
"name": "basic",
"storage_quota_bytes": 30 * MEGABYTE,
},
{
"name": "standard",
"storage_quota_bytes": 100 * MEGABYTE,
},
{
"name": "professional",
"storage_quota_bytes": 300 * MEGABYTE,
},
],
},
}

View File

@ -33,7 +33,7 @@ class Notebooks( object ):
"""
Controller for dealing with notebooks and their notes, corresponding to the "/notebooks" URL.
"""
def __init__( self, scheduler, database ):
def __init__( self, scheduler, database, users ):
"""
Create a new Notebooks object.
@ -41,11 +41,14 @@ class Notebooks( object ):
@param scheduler: scheduler to use for asynchronous calls
@type database: controller.Database
@param database: database that notebooks are stored in
@type users: controller.Users
@param users: controller for all users, used here for updating storage utilization
@rtype: Notebooks
@return: newly constructed Notebooks
"""
self.__scheduler = scheduler
self.__database = database
self.__users = users
@expose( view = Main_page )
@validate(
@ -363,7 +366,11 @@ class Notebooks( object ):
startup_changed = notebook.remove_startup_note( note )
if new_revision or startup_changed:
self.__database.save( notebook )
self.__database.save( notebook, self.__scheduler.thread )
yield Scheduler.SLEEP
self.__users.update_storage( user_id, self.__scheduler.thread )
user = ( yield Scheduler.SLEEP )
self.__database.save( user )
yield dict(
new_revision = new_revision,
@ -411,7 +418,11 @@ class Notebooks( object ):
if note:
notebook.add_startup_note( note )
self.__database.save( notebook )
self.__database.save( notebook, self.__scheduler.thread )
yield Scheduler.SLEEP
self.__users.update_storage( user_id, self.__scheduler.thread )
user = ( yield Scheduler.SLEEP )
self.__database.save( user )
yield dict()
@ -456,7 +467,11 @@ class Notebooks( object ):
if note:
notebook.remove_startup_note( note )
self.__database.save( notebook )
self.__database.save( notebook, self.__scheduler.thread )
yield Scheduler.SLEEP
self.__users.update_storage( user_id, self.__scheduler.thread )
user = ( yield Scheduler.SLEEP )
self.__database.save( user )
yield dict()
@ -508,7 +523,11 @@ class Notebooks( object ):
notebook.trash.add_note( note )
notebook.trash.add_startup_note( note )
self.__database.save( notebook )
self.__database.save( notebook, self.__scheduler.thread )
yield Scheduler.SLEEP
self.__users.update_storage( user_id, self.__scheduler.thread )
user = ( yield Scheduler.SLEEP )
self.__database.save( user )
yield dict()
@ -567,7 +586,11 @@ class Notebooks( object ):
notebook.add_note( note )
notebook.add_startup_note( note )
self.__database.save( notebook )
self.__database.save( notebook, self.__scheduler.thread )
yield Scheduler.SLEEP
self.__users.update_storage( user_id, self.__scheduler.thread )
user = ( yield Scheduler.SLEEP )
self.__database.save( user )
yield dict()
@ -613,7 +636,11 @@ class Notebooks( object ):
notebook.trash.add_note( note )
notebook.trash.add_startup_note( note )
self.__database.save( notebook )
self.__database.save( notebook, self.__scheduler.thread )
yield Scheduler.SLEEP
self.__users.update_storage( user_id, self.__scheduler.thread )
user = ( yield Scheduler.SLEEP )
self.__database.save( user )
yield dict()

View File

@ -33,13 +33,14 @@ class Root( object ):
self.__scheduler = scheduler
self.__database = database
self.__settings = settings
self.__notebooks = Notebooks( scheduler, database )
self.__users = Users(
scheduler,
database,
settings[ u"global" ].get( u"luminotes.http_url", u"" ),
settings[ u"global" ].get( u"luminotes.https_url", u"" ),
settings[ u"global" ].get( u"luminotes.rate_plans", [] ),
)
self.__notebooks = Notebooks( scheduler, database, self.__users )
@expose( view = Main_page )
def index( self ):

View File

@ -125,6 +125,9 @@ class Scheduler( object ):
@type args: tuple
@param args: arguments to send() to the given thread when it is executed
"""
if thread is None:
return
self.__idle.release()
if thread in self.__sleeping:

View File

@ -106,7 +106,7 @@ class Users( object ):
"""
Controller for dealing with users, corresponding to the "/users" URL.
"""
def __init__( self, scheduler, database, http_url, https_url ):
def __init__( self, scheduler, database, http_url, https_url, rate_plans ):
"""
Create a new Users object.
@ -118,6 +118,8 @@ class Users( object ):
@param http_url: base URL to use for non-SSL http requests, or an empty string
@type https_url: unicode
@param https_url: base URL to use for SSL http requests, or an empty string
@type rate_plans: [ { "name": unicode, "storage_quota_bytes": int } ]
@param rate_plans: list of configured rate plans
@rtype: Users
@return: newly constructed Users
"""
@ -125,6 +127,7 @@ class Users( object ):
self.__database = database
self.__http_url = http_url
self.__https_url = https_url
self.__rate_plans = rate_plans
@expose( view = Json )
@update_auth
@ -275,7 +278,14 @@ class Users( object ):
@type user_id: unicode
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
@rtype: json dict
@return: { 'user': userdict or None, 'notebooks': notebooksdict, 'http_url': url }
@return: {
'user': userdict or None,
'notebooks': notebooksdict,
'startup_notes': noteslist,
'http_url': url,
'login_url': url,
'rate_plan': rateplandict,
}
"""
# if there's no logged-in user, default to the anonymous user
self.__database.load( user_id or u"User anonymous", self.__scheduler.thread )
@ -312,6 +322,7 @@ class Users( object ):
startup_notes = include_startup_notes and len( notebooks ) > 0 and notebooks[ 0 ].startup_notes or [],
http_url = self.__http_url,
login_url = login_url,
rate_plan = ( user.rate_plan < len( self.__rate_plans ) ) and self.__rate_plans[ user.rate_plan ] or {},
)
def calculate_storage( self, user ):
@ -344,13 +355,20 @@ class Users( object ):
return total_bytes
@async
def update_storage( self, user ):
def update_storage( self, user_id, callback = None ):
"""
Calculate and record total storage utilization for the given user.
@type user: User
@param user: user for which to calculate storage utilization
@type user_id: unicode or NoneType
@param user_id: id of user for which to calculate storage utilization
@type callback: generator or NoneType
@param callback: generator to wakeup when the update is complete (optional)
"""
user.storage_bytes = self.calculate_storage( user )
yield None
self.__database.load( user_id, self.__scheduler.thread )
user = ( yield Scheduler.SLEEP )
if user:
user.storage_bytes = self.calculate_storage( user )
yield callback, user
scheduler = property( lambda self: self.__scheduler )

View File

@ -19,6 +19,16 @@ class Test_controller( object ):
u"luminotes.https_url" : u"https://luminotes.com",
u"luminotes.http_proxy_ip" : u"127.0.0.1",
u"luminotes.https_proxy_ip" : u"127.0.0.2",
"luminotes.rate_plans": [
{
"name": "super",
"storage_quota_bytes": 1337,
},
{
"name": "extra super",
"storage_quota_bytes": 31337,
},
],
},
}

View File

@ -66,12 +66,14 @@ class Test_notebooks( Test_controller ):
result = self.http_get( "/notebooks/%s" % self.notebook.object_id )
assert result.get( u"notebook_id" ) == self.notebook.object_id
assert self.user.storage_bytes == 0
def test_default_with_note( self ):
result = self.http_get( "/notebooks/%s?note_id=%s" % ( self.notebook.object_id, self.note.object_id ) )
assert result.get( u"notebook_id" ) == self.notebook.object_id
assert result.get( u"note_id" ) == self.note.object_id
assert self.user.storage_bytes == 0
def test_default_with_note_and_revision( self ):
result = self.http_get( "/notebooks/%s?note_id=%s&revision=%s" % (
@ -83,6 +85,7 @@ class Test_notebooks( Test_controller ):
assert result.get( u"notebook_id" ) == self.notebook.object_id
assert result.get( u"note_id" ) == self.note.object_id
assert result.get( u"revision" ) == unicode( self.note.revision )
assert self.user.storage_bytes == 0
def test_default_with_parent( self ):
parent_id = "foo"
@ -90,6 +93,7 @@ class Test_notebooks( Test_controller ):
assert result.get( u"notebook_id" ) == self.notebook.object_id
assert result.get( u"parent_id" ) == parent_id
assert self.user.storage_bytes == 0
def test_contents( self ):
self.login()
@ -105,6 +109,7 @@ class Test_notebooks( Test_controller ):
assert notebook.object_id == self.notebook.object_id
assert len( startup_notes ) == 1
assert startup_notes[ 0 ] == self.note
assert self.user.storage_bytes == 0
def test_contents_with_note( self ):
self.login()
@ -124,6 +129,7 @@ class Test_notebooks( Test_controller ):
note = result[ "note" ]
assert note.object_id == self.note.object_id
assert self.user.storage_bytes == 0
def test_contents_with_note_and_revision( self ):
self.login()
@ -147,6 +153,7 @@ class Test_notebooks( Test_controller ):
note = result[ "note" ]
assert note.object_id == self.note.object_id
assert self.user.storage_bytes == 0
def test_contents_without_login( self ):
result = self.http_get(
@ -155,6 +162,7 @@ class Test_notebooks( Test_controller ):
)
assert result.get( "error" )
assert self.user.storage_bytes == 0
def test_load_note( self ):
self.login()
@ -169,6 +177,7 @@ class Test_notebooks( Test_controller ):
assert note.object_id == self.note.object_id
assert note.title == self.note.title
assert note.contents == self.note.contents
assert self.user.storage_bytes == 0
def test_load_note_with_revision( self ):
self.login()
@ -198,6 +207,7 @@ class Test_notebooks( Test_controller ):
assert note.revision == previous_revision
assert note.title == previous_title
assert note.contents == previous_contents
assert self.user.storage_bytes == 0
def test_load_note_without_login( self ):
result = self.http_post( "/notebooks/load_note/", dict(
@ -216,6 +226,7 @@ class Test_notebooks( Test_controller ):
), session_id = self.session_id )
assert result.get( "error" )
assert self.user.storage_bytes == 0
def test_load_unknown_note( self ):
self.login()
@ -227,6 +238,7 @@ class Test_notebooks( Test_controller ):
note = result[ "note" ]
assert note == None
assert self.user.storage_bytes == 0
def test_load_note_by_title( self ):
self.login()
@ -241,6 +253,7 @@ class Test_notebooks( Test_controller ):
assert note.object_id == self.note.object_id
assert note.title == self.note.title
assert note.contents == self.note.contents
assert self.user.storage_bytes == 0
def test_load_note_by_title_without_login( self ):
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -249,6 +262,7 @@ class Test_notebooks( Test_controller ):
), session_id = self.session_id )
assert result.get( "error" )
assert self.user.storage_bytes == 0
def test_load_note_by_title_with_unknown_notebook( self ):
self.login()
@ -259,6 +273,7 @@ class Test_notebooks( Test_controller ):
), session_id = self.session_id )
assert result.get( "error" )
assert self.user.storage_bytes == 0
def test_load_unknown_note_by_title( self ):
self.login()
@ -270,6 +285,7 @@ class Test_notebooks( Test_controller ):
note = result[ "note" ]
assert note == None
assert self.user.storage_bytes == 0
def test_lookup_note_id( self ):
self.login()
@ -280,6 +296,7 @@ class Test_notebooks( Test_controller ):
), session_id = self.session_id )
assert result.get( "note_id" ) == self.note.object_id
assert self.user.storage_bytes == 0
def test_lookup_note_id_without_login( self ):
result = self.http_post( "/notebooks/lookup_note_id/", dict(
@ -288,6 +305,7 @@ class Test_notebooks( Test_controller ):
), session_id = self.session_id )
assert result.get( "error" )
assert self.user.storage_bytes == 0
def test_lookup_note_id_with_unknown_notebook( self ):
self.login()
@ -298,6 +316,7 @@ class Test_notebooks( Test_controller ):
), session_id = self.session_id )
assert result.get( "error" )
assert self.user.storage_bytes == 0
def test_lookup_unknown_note_id( self ):
self.login()
@ -308,6 +327,7 @@ class Test_notebooks( Test_controller ):
), session_id = self.session_id )
assert result.get( "note_id" ) == None
assert self.user.storage_bytes == 0
def test_save_note( self, startup = False ):
self.login()
@ -325,6 +345,7 @@ class Test_notebooks( Test_controller ):
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
assert result[ "previous_revision" ] == previous_revision
assert self.user.storage_bytes > 0
# make sure the old title can no longer be loaded
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -367,6 +388,7 @@ class Test_notebooks( Test_controller ):
), session_id = self.session_id )
assert result.get( "error" )
assert self.user.storage_bytes == 0
def test_save_startup_note_without_login( self ):
self.test_save_note_without_login( startup = True )
@ -393,6 +415,7 @@ class Test_notebooks( Test_controller ):
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
assert result[ "previous_revision" ] == previous_revision
assert self.user.storage_bytes > 0
# make sure the old title can no longer be loaded
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -446,6 +469,7 @@ class Test_notebooks( Test_controller ):
), session_id = self.session_id )
# now attempt to save over that note again without changing the contents
previous_storage_bytes = self.user.storage_bytes
previous_revision = self.note.revision
result = self.http_post( "/notebooks/save_note/", dict(
notebook_id = self.notebook.object_id,
@ -458,6 +482,7 @@ class Test_notebooks( Test_controller ):
# assert that the note wasn't actually updated the second time
assert result[ "new_revision" ] == None
assert result[ "previous_revision" ] == previous_revision
assert self.user.storage_bytes == previous_storage_bytes
result = self.http_post( "/notebooks/load_note_by_title/", dict(
notebook_id = self.notebook.object_id,
@ -491,6 +516,7 @@ class Test_notebooks( Test_controller ):
), session_id = self.session_id )
# now attempt to save over that note again without changing the contents
previous_storage_bytes = self.user.storage_bytes
previous_revision = self.note.revision
result = self.http_post( "/notebooks/save_note/", dict(
notebook_id = self.notebook.object_id,
@ -503,6 +529,7 @@ class Test_notebooks( Test_controller ):
# assert that the note wasn't actually updated the second time
assert result[ "new_revision" ] == None
assert result[ "previous_revision" ] == previous_revision
assert self.user.storage_bytes == previous_storage_bytes
result = self.http_post( "/notebooks/load_note_by_title/", dict(
notebook_id = self.notebook.object_id,
@ -553,6 +580,7 @@ class Test_notebooks( Test_controller ):
# assert that the note wasn't actually updated the second time
assert result[ "new_revision" ] == None
assert result[ "previous_revision" ] == previous_revision
assert self.user.storage_bytes > 0
result = self.http_post( "/notebooks/load_note_by_title/", dict(
notebook_id = self.notebook.object_id,
@ -602,6 +630,7 @@ class Test_notebooks( Test_controller ):
assert result[ "new_revision" ]
assert result[ "new_revision" ] not in ( first_revision, second_revision )
assert result[ "previous_revision" ] == second_revision
assert self.user.storage_bytes > 0
# make sure the first title can no longer be loaded
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -646,6 +675,7 @@ class Test_notebooks( Test_controller ):
), session_id = self.session_id )
assert result.get( "error" )
assert self.user.storage_bytes == 0
def test_save_new_note( self, startup = False ):
self.login()
@ -663,6 +693,7 @@ class Test_notebooks( Test_controller ):
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
assert result[ "previous_revision" ] == None
assert self.user.storage_bytes > 0
# make sure the new title is now loadable
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -705,6 +736,7 @@ class Test_notebooks( Test_controller ):
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
assert result[ "previous_revision" ] == None
assert self.user.storage_bytes > 0
# make sure the new title is now loadable
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -738,6 +770,7 @@ class Test_notebooks( Test_controller ):
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
assert result[ "previous_revision" ] == None
assert self.user.storage_bytes > 0
# make sure the new title is now loadable
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -770,6 +803,7 @@ class Test_notebooks( Test_controller ):
assert len( notebook.startup_notes ) == 2
assert notebook.startup_notes[ 0 ] == self.note
assert notebook.startup_notes[ 1 ] == self.note2
assert self.user.storage_bytes > 0
def test_add_startup_note_without_login( self ):
result = self.http_post( "/notebooks/add_startup_note/", dict(
@ -778,6 +812,7 @@ class Test_notebooks( Test_controller ):
), session_id = self.session_id )
assert result.get( "error" )
assert self.user.storage_bytes == 0
def test_add_startup_note_with_unknown_notebook( self ):
self.login()
@ -797,6 +832,7 @@ class Test_notebooks( Test_controller ):
assert len( notebook.startup_notes ) == 1
assert notebook.startup_notes[ 0 ] == self.note
assert self.user.storage_bytes == 0
def test_add_startup_unknown_note( self ):
self.login()
@ -816,6 +852,7 @@ class Test_notebooks( Test_controller ):
assert len( notebook.startup_notes ) == 1
assert notebook.startup_notes[ 0 ] == self.note
assert self.user.storage_bytes == 0
def test_remove_startup_note( self ):
self.login()
@ -834,6 +871,7 @@ class Test_notebooks( Test_controller ):
notebook = result[ "notebook" ]
assert len( notebook.startup_notes ) == 0
assert self.user.storage_bytes > 0
def test_remove_startup_note_without_login( self ):
result = self.http_post( "/notebooks/remove_startup_note/", dict(
@ -842,6 +880,7 @@ class Test_notebooks( Test_controller ):
), session_id = self.session_id )
assert result.get( "error" )
assert self.user.storage_bytes == 0
def test_remove_startup_note_with_unknown_notebook( self ):
self.login()
@ -861,6 +900,7 @@ class Test_notebooks( Test_controller ):
assert len( notebook.startup_notes ) == 1
assert notebook.startup_notes[ 0 ] == self.note
assert self.user.storage_bytes == 0
def test_remove_startup_unknown_note( self ):
self.login()
@ -880,6 +920,7 @@ class Test_notebooks( Test_controller ):
assert len( notebook.startup_notes ) == 1
assert notebook.startup_notes[ 0 ] == self.note
assert self.user.storage_bytes == 0
def test_is_startup_note( self ):
self.login()

View File

@ -98,6 +98,10 @@ class Test_users( Test_controller ):
else:
assert startup_notes == []
rate_plan = result[ u"rate_plan" ]
assert rate_plan[ u"name" ] == u"super"
assert rate_plan[ u"storage_quota_bytes" ] == 1337
def test_current_with_startup_notes_after_signup( self ):
self.test_current_after_signup( include_startup_notes = True )
@ -229,10 +233,37 @@ class Test_users( Test_controller ):
def test_update_storage( self ):
previous_revision = self.user.revision
cherrypy.root.users.update_storage( self.user )
cherrypy.root.users.update_storage( self.user.object_id )
self.scheduler.wait_until_idle()
expected_size = cherrypy.root.users.calculate_storage( self.user )
assert self.user.storage_bytes == expected_size
assert self.user.revision > previous_revision
def test_update_storage_with_unknown_user_id( self ):
original_revision = self.user.revision
cherrypy.root.users.update_storage( 77 )
self.scheduler.wait_until_idle()
expected_size = cherrypy.root.users.calculate_storage( self.user )
assert self.user.storage_bytes == 0
assert self.user.revision == original_revision
def test_update_storage_with_callback( self ):
def gen():
previous_revision = self.user.revision
cherrypy.root.users.update_storage( self.user.object_id, self.scheduler.thread )
user = ( yield Scheduler.SLEEP )
expected_size = cherrypy.root.users.calculate_storage( self.user )
assert user == self.user
assert self.user.storage_bytes == expected_size
assert self.user.revision > previous_revision
g = gen()
self.scheduler.add( g )
self.scheduler.wait_for( g )

View File

@ -13,7 +13,9 @@ class User( Persistent ):
def __setstate__( self, state ):
if "_User__storage_bytes" not in state:
state[ "_User__storage_bytes" ] = False
state[ "_User__storage_bytes" ] = 0
if "_User__rate_plan" not in state:
state[ "_User__rate_plan" ] = 0
self.__dict__.update( state )
@ -40,6 +42,7 @@ class User( Persistent ):
self.__email_address = email_address
self.__notebooks = notebooks or []
self.__storage_bytes = 0 # total storage bytes for this user's notebooks, notes, and revisions
self.__rate_plan = 0 # each rate plan is an integer index into the array in config/Common.py
def __create_salt( self ):
return "".join( [ random.choice( self.SALT_CHARS ) for i in range( self.SALT_SIZE ) ] )
@ -82,6 +85,8 @@ class User( Persistent ):
d = Persistent.to_dict( self )
d.update( dict(
username = self.username,
storage_bytes = self.__storage_bytes,
rate_plan = self.__rate_plan,
) )
return d
@ -99,10 +104,15 @@ class User( Persistent ):
self.update_revision()
self.__storage_bytes = storage_bytes
def __set_rate_plan( self, rate_plan ):
self.update_revision()
self.__rate_plan = rate_plan
username = property( lambda self: self.secondary_id )
email_address = property( lambda self: self.__email_address )
password = property( None, __set_password )
storage_bytes = property( lambda self: self.__storage_bytes, __set_storage_bytes )
rate_plan = property( lambda self: self.__rate_plan, __set_rate_plan )
# the notebooks (read-only and read-write) that this user has access to
notebooks = property( lambda self: copy( self.__notebooks ), __set_notebooks )

View File

@ -17,6 +17,7 @@ class Test_user( object ):
assert self.user.email_address == self.email_address
assert self.user.notebooks == []
assert self.user.storage_bytes == 0
assert self.user.rate_plan == 0
def test_check_correct_password( self ):
assert self.user.check_password( self.password ) == True
@ -60,6 +61,14 @@ class Test_user( object ):
assert self.user.storage_bytes == storage_bytes
assert self.user.revision > previous_revision
def test_set_rate_plan( self ):
previous_revision = self.user.revision
rate_plan = 2
self.user.rate_plan = rate_plan
assert self.user.rate_plan == rate_plan
assert self.user.revision > previous_revision
class Test_user_with_notebooks( object ):
def setUp( self ):
@ -116,3 +125,10 @@ class Test_user_with_notebooks( object ):
trash = Notebook( trash_id, u"trash" )
notebook = Notebook( notebook_id, u"my new notebook", trash )
assert self.user.has_access( notebook.object_id ) == False
def test_to_dict( self ):
d = self.user.to_dict()
assert d.get( "username" ) == self.username
assert d.get( "storage_bytes" ) == self.user.storage_bytes
assert d.get( "rate_plan" ) == self.user.rate_plan

View File

@ -346,6 +346,27 @@ ol li {
padding: 0.25em 0.25em 0.25em 0.5em;
}
.storage_usage_area {
}
.storage_usage_low {
color: green;
font-weight: bold;
margin-top: 1.5em;
}
.storage_usage_medium {
color: orange;
font-weight: bold;
margin-top: 1.5em;
}
.storage_usage_high {
color: red;
font-weight: bold;
margin-top: 1.5em;
}
.current_notebook_name {
background-color: #b0d0ff;
-moz-border-radius: 0.5em;

View File

@ -12,6 +12,7 @@ function Wiki( invoker ) {
this.search_results_editor = null; // editor for display of search results
this.invoker = invoker;
this.search_titles_only = true;
this.rate_plan = null;
connect( this.invoker, "error_message", this, "display_error" );
connect( "search_form", "onsubmit", this, "search" );
@ -86,6 +87,9 @@ Wiki.prototype.display_user = function ( result ) {
}, notebook.name ) ) );
}
this.rate_plan = result.rate_plan;
this.display_storage_usage( result.user.storage_bytes );
// display the name of the logged in user and a logout link
appendChildNodes( user_span, "logged in as " + result.user.username );
appendChildNodes( user_span, " | " );
@ -99,6 +103,30 @@ Wiki.prototype.display_user = function ( result ) {
} );
}
Wiki.prototype.display_storage_usage = function( storage_bytes ) {
// display the user's current storage usage
var MEGABYTE = 1024 * 1024;
function bytes_to_megabytes( storage_bytes ) {
return Math.round( storage_bytes / MEGABYTE );
}
var quota_bytes = this.rate_plan.storage_quota_bytes || 0;
var usage_percent = Math.round( storage_bytes / quota_bytes * 100.0 );
if ( usage_percent > 90 )
var storage_usage_class = "storage_usage_high";
else if ( usage_percent > 75 )
var storage_usage_class = "storage_usage_medium";
else
var storage_usage_class = "storage_usage_low";
replaceChildNodes(
"storage_usage_area",
createDOM( "div", { "class": storage_usage_class },
bytes_to_megabytes( storage_bytes ) + " MB (" + usage_percent + "%) of " + bytes_to_megabytes( quota_bytes ) + " MB used" )
);
}
Wiki.prototype.populate = function ( result ) {
this.notebook = result.notebook;
var self = this;

View File

@ -11,4 +11,7 @@ class Link_area( Div ):
Div(
id = u"notebooks_area",
),
Div(
id = u"storage_usage_area",
),
)