Finished remake of signup page. You can now click "signup" for non-free accounts even if you're not logged in.
This commit is contained in:
parent
e9d2ea28d1
commit
c452408106
|
@ -56,9 +56,10 @@ class Root( object ):
|
||||||
note_title = unicode,
|
note_title = unicode,
|
||||||
invite_id = Valid_id( none_okay = True ),
|
invite_id = Valid_id( none_okay = True ),
|
||||||
after_login = Valid_string( min = 0, max = 100 ),
|
after_login = Valid_string( min = 0, max = 100 ),
|
||||||
|
plan = Valid_int( none_okay = True ),
|
||||||
user_id = Valid_id( none_okay = True ),
|
user_id = Valid_id( none_okay = True ),
|
||||||
)
|
)
|
||||||
def default( self, note_title, invite_id = None, after_login = None, user_id = None ):
|
def default( self, note_title, invite_id = None, after_login = None, plan = None, user_id = None ):
|
||||||
"""
|
"""
|
||||||
Convenience method for accessing a note in the main notebook by name rather than by note id.
|
Convenience method for accessing a note in the main notebook by name rather than by note id.
|
||||||
|
|
||||||
|
@ -68,6 +69,8 @@ class Root( object ):
|
||||||
@param invite_id: id of the invite used to get to this note (optional)
|
@param invite_id: id of the invite used to get to this note (optional)
|
||||||
@type after_login: unicode
|
@type after_login: unicode
|
||||||
@param after_login: URL to redirect to after login (optional, must start with "/")
|
@param after_login: URL to redirect to after login (optional, must start with "/")
|
||||||
|
@type plan: int
|
||||||
|
@param plan: rate plan index (optional, defaults to None)
|
||||||
@rtype: unicode
|
@rtype: unicode
|
||||||
@return: rendered HTML page
|
@return: rendered HTML page
|
||||||
"""
|
"""
|
||||||
|
@ -81,6 +84,8 @@ class Root( object ):
|
||||||
return dict( redirect = u"%s/%s?invite_id=%s" % ( https_url, note_title, invite_id ) )
|
return dict( redirect = u"%s/%s?invite_id=%s" % ( https_url, note_title, invite_id ) )
|
||||||
if after_login:
|
if after_login:
|
||||||
return dict( redirect = u"%s/%s?after_login=%s" % ( https_url, note_title, after_login ) )
|
return dict( redirect = u"%s/%s?after_login=%s" % ( https_url, note_title, after_login ) )
|
||||||
|
if plan:
|
||||||
|
return dict( redirect = u"%s/%s?plan=%s" % ( https_url, note_title, plan ) )
|
||||||
else:
|
else:
|
||||||
return dict( redirect = u"%s/%s" % ( https_url, note_title ) )
|
return dict( redirect = u"%s/%s" % ( https_url, note_title ) )
|
||||||
|
|
||||||
|
@ -100,6 +105,8 @@ class Root( object ):
|
||||||
result[ "invite_id" ] = invite_id
|
result[ "invite_id" ] = invite_id
|
||||||
if after_login and after_login.startswith( u"/" ):
|
if after_login and after_login.startswith( u"/" ):
|
||||||
result[ "after_login" ] = after_login
|
result[ "after_login" ] = after_login
|
||||||
|
if plan:
|
||||||
|
result[ "signup_plan" ] = plan
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ from model.Note import Note
|
||||||
from model.Password_reset import Password_reset
|
from model.Password_reset import Password_reset
|
||||||
from model.Invite import Invite
|
from model.Invite import Invite
|
||||||
from Expose import expose
|
from Expose import expose
|
||||||
from Validate import validate, Valid_string, Valid_bool, Validation_error
|
from Validate import validate, Valid_string, Valid_bool, Valid_int, Validation_error
|
||||||
from Database import Valid_id, end_transaction
|
from Database import Valid_id, end_transaction
|
||||||
from Expire import strongly_expire
|
from Expire import strongly_expire
|
||||||
from view.Json import Json
|
from view.Json import Json
|
||||||
|
@ -21,6 +21,7 @@ from view.Blank_page import Blank_page
|
||||||
from view.Thanks_note import Thanks_note
|
from view.Thanks_note import Thanks_note
|
||||||
from view.Thanks_error_note import Thanks_error_note
|
from view.Thanks_error_note import Thanks_error_note
|
||||||
from view.Processing_note import Processing_note
|
from view.Processing_note import Processing_note
|
||||||
|
from view.Form_submit_page import Form_submit_page
|
||||||
|
|
||||||
|
|
||||||
USERNAME_PATTERN = re.compile( "^[a-zA-Z0-9]+$" )
|
USERNAME_PATTERN = re.compile( "^[a-zA-Z0-9]+$" )
|
||||||
|
@ -205,8 +206,9 @@ class Users( object ):
|
||||||
email_address = ( Valid_string( min = 0, max = 60 ) ),
|
email_address = ( Valid_string( min = 0, max = 60 ) ),
|
||||||
signup_button = unicode,
|
signup_button = unicode,
|
||||||
invite_id = Valid_id( none_okay = True ),
|
invite_id = Valid_id( none_okay = True ),
|
||||||
|
rate_plan = Valid_int( none_okay = True ),
|
||||||
)
|
)
|
||||||
def signup( self, username, password, password_repeat, email_address, signup_button, invite_id = None ):
|
def signup( self, username, password, password_repeat, email_address, signup_button, invite_id = None, rate_plan = None ):
|
||||||
"""
|
"""
|
||||||
Create a new User based on the given information. Start that user with their own Notebook and a
|
Create a new User based on the given information. Start that user with their own Notebook and a
|
||||||
"welcome to your wiki" Note. For convenience, login the newly created user as well.
|
"welcome to your wiki" Note. For convenience, login the newly created user as well.
|
||||||
|
@ -223,6 +225,9 @@ class Users( object ):
|
||||||
@param signup_button: ignored
|
@param signup_button: ignored
|
||||||
@type invite_id: unicode
|
@type invite_id: unicode
|
||||||
@param invite_id: id of invite to redeem upon signup (optional)
|
@param invite_id: id of invite to redeem upon signup (optional)
|
||||||
|
@type rate_plan: int
|
||||||
|
@param rate_plan: index of rate plan to signup for (optional). if greater than zero, redirect
|
||||||
|
to PayPal subscribe page after signup
|
||||||
@rtype: json dict
|
@rtype: json dict
|
||||||
@return: { 'redirect': url, 'authenticated': userdict }
|
@return: { 'redirect': url, 'authenticated': userdict }
|
||||||
@raise Signup_error: passwords don't match or the username is unavailable
|
@raise Signup_error: passwords don't match or the username is unavailable
|
||||||
|
@ -275,6 +280,9 @@ class Users( object ):
|
||||||
|
|
||||||
self.convert_invite_to_access( invite, user_id )
|
self.convert_invite_to_access( invite, user_id )
|
||||||
redirect = u"/notebooks/%s" % invite.notebook_id
|
redirect = u"/notebooks/%s" % invite.notebook_id
|
||||||
|
# if there's a requested rate plan, then redirect to the PayPal subscribe page
|
||||||
|
elif rate_plan and rate_plan > 0:
|
||||||
|
redirect = u"/users/subscribe?rate_plan=%s" % rate_plan
|
||||||
# otherwise, just redirect to the newly created notebook
|
# otherwise, just redirect to the newly created notebook
|
||||||
else:
|
else:
|
||||||
redirect = u"/notebooks/%s" % notebook.object_id
|
redirect = u"/notebooks/%s" % notebook.object_id
|
||||||
|
@ -284,6 +292,39 @@ class Users( object ):
|
||||||
authenticated = user,
|
authenticated = user,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@expose( view = Form_submit_page )
|
||||||
|
@grab_user_id
|
||||||
|
@validate(
|
||||||
|
rate_plan = Valid_int(),
|
||||||
|
user_id = Valid_id(),
|
||||||
|
)
|
||||||
|
def subscribe( self, rate_plan, user_id ):
|
||||||
|
"""
|
||||||
|
Submit a subscription form to PayPal, allowing the user to subscribe to the given rate plan.
|
||||||
|
|
||||||
|
@type rate_plan: int
|
||||||
|
@param rate_plan: index of rate plan to subscribe to
|
||||||
|
@type user_id: unicode
|
||||||
|
@param user_id: id of current logged-in user
|
||||||
|
@rtype: dict
|
||||||
|
@return: { 'form': subscription_form_html }
|
||||||
|
@raise Signup_error: invalid rate plan, no logged-in user, or missing subscribe button
|
||||||
|
"""
|
||||||
|
if rate_plan == 0 or rate_plan >= len( self.__rate_plans ):
|
||||||
|
raise Signup_error( u"The rate plan is invalid." )
|
||||||
|
|
||||||
|
plan = self.__rate_plans[ rate_plan ]
|
||||||
|
button = plan.get( u"button" )
|
||||||
|
if not button or not button.strip():
|
||||||
|
raise Signup_error(
|
||||||
|
u"Sorry, that rate plan is not configured for subscriptions. Please contact %s." % \
|
||||||
|
( self.__support_email or u"support" )
|
||||||
|
)
|
||||||
|
|
||||||
|
return dict(
|
||||||
|
form = button % user_id,
|
||||||
|
)
|
||||||
|
|
||||||
@expose()
|
@expose()
|
||||||
@end_transaction
|
@end_transaction
|
||||||
@grab_user_id
|
@grab_user_id
|
||||||
|
|
|
@ -142,12 +142,14 @@ class Valid_int( object ):
|
||||||
"""
|
"""
|
||||||
Validator for an integer value.
|
Validator for an integer value.
|
||||||
"""
|
"""
|
||||||
def __init__( self, min = None, max = None ):
|
def __init__( self, min = None, max = None, none_okay = False ):
|
||||||
self.min = min
|
self.min = min
|
||||||
self.max = max
|
self.max = max
|
||||||
self.message = None
|
self.message = None
|
||||||
|
self.__none_okay = none_okay
|
||||||
|
|
||||||
def __call__( self, value ):
|
def __call__( self, value ):
|
||||||
|
if self.__none_okay and value in ( None, "None", "" ): return None
|
||||||
value = int( value )
|
value = int( value )
|
||||||
|
|
||||||
if self.min is not None and value < self.min:
|
if self.min is not None and value < self.min:
|
||||||
|
|
|
@ -238,6 +238,21 @@ class Test_root( Test_controller ):
|
||||||
assert result.get( u"after_login" ) is None
|
assert result.get( u"after_login" ) is None
|
||||||
assert result[ u"user" ].object_id == self.anonymous.object_id
|
assert result[ u"user" ].object_id == self.anonymous.object_id
|
||||||
|
|
||||||
|
def test_default_with_plan( self ):
|
||||||
|
plan = u"17"
|
||||||
|
|
||||||
|
result = self.http_get(
|
||||||
|
"/my_note?plan=%s" % plan,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result
|
||||||
|
assert result[ u"notes" ]
|
||||||
|
assert len( result[ u"notes" ] ) == 1
|
||||||
|
assert result[ u"notes" ][ 0 ].object_id == self.anon_note.object_id
|
||||||
|
assert result[ u"notebook" ].object_id == self.anon_notebook.object_id
|
||||||
|
assert result[ u"signup_plan" ] == 17
|
||||||
|
assert result[ u"user" ].object_id == self.anonymous.object_id
|
||||||
|
|
||||||
def test_default_after_login( self ):
|
def test_default_after_login( self ):
|
||||||
self.login()
|
self.login()
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,18 @@ class Test_users( Test_controller ):
|
||||||
|
|
||||||
assert result[ u"redirect" ].startswith( u"/notebooks/" )
|
assert result[ u"redirect" ].startswith( u"/notebooks/" )
|
||||||
|
|
||||||
|
def test_signup_with_rate_plan( self ):
|
||||||
|
result = self.http_post( "/users/signup", dict(
|
||||||
|
username = self.new_username,
|
||||||
|
password = self.new_password,
|
||||||
|
password_repeat = self.new_password,
|
||||||
|
email_address = self.new_email_address,
|
||||||
|
signup_button = u"sign up",
|
||||||
|
rate_plan = u"2",
|
||||||
|
) )
|
||||||
|
|
||||||
|
assert result[ u"redirect" ] == u"/users/subscribe?rate_plan=2"
|
||||||
|
|
||||||
def test_signup_without_email_address( self ):
|
def test_signup_without_email_address( self ):
|
||||||
result = self.http_post( "/users/signup", dict(
|
result = self.http_post( "/users/signup", dict(
|
||||||
username = self.new_username,
|
username = self.new_username,
|
||||||
|
@ -250,6 +262,62 @@ class Test_users( Test_controller ):
|
||||||
assert rate_plan[ u"name" ] == u"super"
|
assert rate_plan[ u"name" ] == u"super"
|
||||||
assert rate_plan[ u"storage_quota_bytes" ] == 1337 * 10
|
assert rate_plan[ u"storage_quota_bytes" ] == 1337 * 10
|
||||||
|
|
||||||
|
def test_current_after_signup_with_rate_plan( self ):
|
||||||
|
result = self.http_post( "/users/signup", dict(
|
||||||
|
username = self.new_username,
|
||||||
|
password = self.new_password,
|
||||||
|
password_repeat = self.new_password,
|
||||||
|
email_address = self.new_email_address,
|
||||||
|
signup_button = u"sign up",
|
||||||
|
rate_plan = u"2",
|
||||||
|
) )
|
||||||
|
session_id = result[ u"session_id" ]
|
||||||
|
|
||||||
|
assert result[ u"redirect" ] == u"/users/subscribe?rate_plan=2"
|
||||||
|
|
||||||
|
user = self.database.last_saved_obj
|
||||||
|
assert isinstance( user, User )
|
||||||
|
result = cherrypy.root.users.current( user.object_id )
|
||||||
|
|
||||||
|
assert result[ u"user" ].object_id == user.object_id
|
||||||
|
assert result[ u"user" ].username == self.new_username
|
||||||
|
assert result[ u"user" ].email_address == self.new_email_address
|
||||||
|
|
||||||
|
notebooks = result[ u"notebooks" ]
|
||||||
|
notebook = notebooks[ 0 ]
|
||||||
|
assert notebook.object_id
|
||||||
|
assert notebook.revision
|
||||||
|
assert notebook.name == u"my notebook"
|
||||||
|
assert notebook.trash_id
|
||||||
|
assert notebook.read_write == True
|
||||||
|
assert notebook.owner == True
|
||||||
|
assert notebook.rank == 0
|
||||||
|
|
||||||
|
notebook = notebooks[ 1 ]
|
||||||
|
assert notebook.object_id == notebooks[ 0 ].trash_id
|
||||||
|
assert notebook.revision
|
||||||
|
assert notebook.name == u"trash"
|
||||||
|
assert notebook.trash_id == None
|
||||||
|
assert notebook.read_write == True
|
||||||
|
assert notebook.owner == True
|
||||||
|
assert notebook.rank == None
|
||||||
|
|
||||||
|
notebook = notebooks[ 2 ]
|
||||||
|
assert notebook.object_id == self.anon_notebook.object_id
|
||||||
|
assert notebook.revision == self.anon_notebook.revision
|
||||||
|
assert notebook.name == self.anon_notebook.name
|
||||||
|
assert notebook.trash_id == None
|
||||||
|
assert notebook.read_write == False
|
||||||
|
assert notebook.owner == False
|
||||||
|
assert notebook.rank == None
|
||||||
|
|
||||||
|
assert result.get( u"login_url" ) is None
|
||||||
|
assert result[ u"logout_url" ] == self.settings[ u"global" ][ u"luminotes.https_url" ] + u"/users/logout"
|
||||||
|
|
||||||
|
rate_plan = result[ u"rate_plan" ]
|
||||||
|
assert rate_plan[ u"name" ] == u"super"
|
||||||
|
assert rate_plan[ u"storage_quota_bytes" ] == 1337 * 10
|
||||||
|
|
||||||
def test_signup_with_different_passwords( self ):
|
def test_signup_with_different_passwords( self ):
|
||||||
result = self.http_post( "/users/signup", dict(
|
result = self.http_post( "/users/signup", dict(
|
||||||
username = self.new_username,
|
username = self.new_username,
|
||||||
|
@ -261,6 +329,58 @@ class Test_users( Test_controller ):
|
||||||
|
|
||||||
assert result[ u"error" ]
|
assert result[ u"error" ]
|
||||||
|
|
||||||
|
def test_subscribe( self ):
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
result = self.http_post( "/users/subscribe", dict(
|
||||||
|
rate_plan = u"1",
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
form = result.get( u"form" )
|
||||||
|
plan = self.settings[ u"global" ][ u"luminotes.rate_plans" ][ 1 ]
|
||||||
|
|
||||||
|
assert form == plan[ u"button" ] % self.user.object_id
|
||||||
|
|
||||||
|
def test_subscribe_with_free_rate_plan( self ):
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
result = self.http_post( "/users/subscribe", dict(
|
||||||
|
rate_plan = u"0",
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
assert u"plan" in result[ u"error" ]
|
||||||
|
assert u"invalid" in result[ u"error" ]
|
||||||
|
|
||||||
|
def test_subscribe_with_invalid_rate_plan( self ):
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
result = self.http_post( "/users/subscribe", dict(
|
||||||
|
rate_plan = u"17",
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
assert u"plan" in result[ u"error" ]
|
||||||
|
assert u"invalid" in result[ u"error" ]
|
||||||
|
|
||||||
|
def test_subscribe_without_login( self ):
|
||||||
|
result = self.http_post( "/users/subscribe", dict(
|
||||||
|
rate_plan = u"1",
|
||||||
|
) )
|
||||||
|
|
||||||
|
assert u"user" in result[ u"error" ]
|
||||||
|
assert u"invalid" in result[ u"error" ]
|
||||||
|
|
||||||
|
def test_subscribe_without_subscribe_button( self ):
|
||||||
|
self.login()
|
||||||
|
self.settings[ u"global" ][ u"luminotes.rate_plans" ][ 1 ][ u"button" ] = u" "
|
||||||
|
|
||||||
|
result = self.http_post( "/users/subscribe", dict(
|
||||||
|
rate_plan = u"1",
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
|
||||||
|
print result
|
||||||
|
assert u"not configured" in result[ u"error" ]
|
||||||
|
|
||||||
def test_demo( self ):
|
def test_demo( self ):
|
||||||
result = self.http_post( "/users/demo", dict() )
|
result = self.http_post( "/users/demo", dict() )
|
||||||
|
|
||||||
|
|
|
@ -348,6 +348,7 @@
|
||||||
|
|
||||||
.upgrade_left_area {
|
.upgrade_left_area {
|
||||||
width: 400px;
|
width: 400px;
|
||||||
|
margin-top: 1.5em;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
@ -17,6 +17,7 @@ function Wiki( invoker ) {
|
||||||
this.invites = evalJSON( getElement( "invites" ).value );
|
this.invites = evalJSON( getElement( "invites" ).value );
|
||||||
this.invite_id = getElement( "invite_id" ).value;
|
this.invite_id = getElement( "invite_id" ).value;
|
||||||
this.after_login = getElement( "after_login" ).value;
|
this.after_login = getElement( "after_login" ).value;
|
||||||
|
this.signup_plan = getElement( "signup_plan" ).value;
|
||||||
this.font_size = null;
|
this.font_size = null;
|
||||||
|
|
||||||
var total_notes_count_node = getElement( "total_notes_count" );
|
var total_notes_count_node = getElement( "total_notes_count" );
|
||||||
|
@ -693,10 +694,12 @@ Wiki.prototype.create_editor = function ( id, note_text, deleted_from_id, revisi
|
||||||
connect( editor, "invites_updated", function ( invites ) { self.invites = invites; self.share_notebook(); } );
|
connect( editor, "invites_updated", function ( invites ) { self.invites = invites; self.share_notebook(); } );
|
||||||
connect( editor, "submit_form", function ( url, form, callback ) {
|
connect( editor, "submit_form", function ( url, form, callback ) {
|
||||||
var args = {}
|
var args = {}
|
||||||
if ( url == "/users/signup" || url == "/users/login" ) {
|
if ( url == "/users/signup" ) {
|
||||||
args[ "invite_id" ] = self.invite_id;
|
args[ "invite_id" ] = self.invite_id;
|
||||||
if ( url == "/users/login" )
|
args[ "rate_plan" ] = self.signup_plan;
|
||||||
args[ "after_login" ] = self.after_login;
|
} else if ( url == "/users/login" ) {
|
||||||
|
args[ "invite_id" ] = self.invite_id;
|
||||||
|
args[ "after_login" ] = self.after_login;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.invoker.invoke( url, "POST", args, callback, form );
|
self.invoker.invoke( url, "POST", args, callback, form );
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
from Tags import Html, Head, Body, Script
|
||||||
|
|
||||||
|
|
||||||
|
class Form_submit_page( Html ):
|
||||||
|
def __init__( self, form ):
|
||||||
|
Html.__init__(
|
||||||
|
self,
|
||||||
|
Head(),
|
||||||
|
Body(
|
||||||
|
form,
|
||||||
|
Script( # auto-submit the form
|
||||||
|
u"document.forms[ 0 ].submit();",
|
||||||
|
type = u"text/javascript",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
|
@ -132,7 +132,7 @@ class Front_page( Product_page ):
|
||||||
separator = u"",
|
separator = u"",
|
||||||
),
|
),
|
||||||
Div(
|
Div(
|
||||||
u"-Scott Tiner",
|
u"-Scott Tiner, Technical Writer",
|
||||||
class_ = u"quote_signature"
|
class_ = u"quote_signature"
|
||||||
),
|
),
|
||||||
class_ = u"quote",
|
class_ = u"quote",
|
||||||
|
|
|
@ -32,6 +32,7 @@ class Main_page( Page ):
|
||||||
invites = None,
|
invites = None,
|
||||||
invite_id = None,
|
invite_id = None,
|
||||||
after_login = None,
|
after_login = None,
|
||||||
|
signup_plan = None,
|
||||||
):
|
):
|
||||||
startup_note_ids = [ startup_note.object_id for startup_note in startup_notes ]
|
startup_note_ids = [ startup_note.object_id for startup_note in startup_notes ]
|
||||||
|
|
||||||
|
@ -108,6 +109,7 @@ class Main_page( Page ):
|
||||||
Input( type = u"hidden", name = u"invites", id = u"invites", value = json( invites ) ),
|
Input( type = u"hidden", name = u"invites", id = u"invites", value = json( invites ) ),
|
||||||
Input( type = u"hidden", name = u"invite_id", id = u"invite_id", value = invite_id ),
|
Input( type = u"hidden", name = u"invite_id", id = u"invite_id", value = invite_id ),
|
||||||
Input( type = u"hidden", name = u"after_login", id = u"after_login", value = after_login ),
|
Input( type = u"hidden", name = u"after_login", id = u"after_login", value = after_login ),
|
||||||
|
Input( type = u"hidden", name = u"signup_plan", id = u"signup_plan", value = signup_plan ),
|
||||||
Div(
|
Div(
|
||||||
id = u"status_area",
|
id = u"status_area",
|
||||||
),
|
),
|
||||||
|
|
|
@ -98,8 +98,8 @@ class Upgrade_page( Product_page ):
|
||||||
alt = u"More room to stretch out",
|
alt = u"More room to stretch out",
|
||||||
),
|
),
|
||||||
Ul(
|
Ul(
|
||||||
Li( u"More room for your wiki notes." ),
|
Li( u"More space for your wiki notes." ),
|
||||||
Li( u"More room for your documents and files." ),
|
Li( u"More space for your documents and files." ),
|
||||||
class_ = u"upgrade_text",
|
class_ = u"upgrade_text",
|
||||||
),
|
),
|
||||||
Img(
|
Img(
|
||||||
|
@ -176,7 +176,8 @@ class Upgrade_page( Product_page ):
|
||||||
class_ = u"price_text",
|
class_ = u"price_text",
|
||||||
separator = u"",
|
separator = u"",
|
||||||
),
|
),
|
||||||
user and user.username and user.rate_plan != index and plan.get( u"button" ).strip() and plan.get( u"button" ) % user.object_id,
|
user and user.username not in ( u"anonymous", None ) and user.rate_plan != index \
|
||||||
|
and plan.get( u"button" ).strip() and plan.get( u"button" ) % user.object_id or None,
|
||||||
) or None,
|
) or None,
|
||||||
( not user or user.username in ( u"anonymous", None ) ) and Div(
|
( not user or user.username in ( u"anonymous", None ) ) and Div(
|
||||||
A(
|
A(
|
||||||
|
|
Reference in New Issue