Hi,
I am building an application on AppEngine platform. Whenever a user
requests for an invite, the user is sent an email with a link.
The user when clicks on the link is presented with a registration page
which contains two forms :
1. Custom Registration form
2. Image upload form for a profile picture. This form is integrated with
Google Blobstore service.
The user fills in the information. When he clicks on the image upload
button, he is presented with an overlay containing the image upload form
where he chooses and adjusts the image he would like to set as his profile
pic. Once finalized, the overlay is closed and the user now clicks on
"Complete Registration"
button. The controller then makes the entries in the corresponding tables
and the user is redirected to his profile page as can be seen from the code
below.
The code for the custom registration form (controller) is as follows:
email_id = request.get_vars['email']
activation_key = request.get_vars['id']
image_error_msg = ""
try:
# Check if its an already existing user
if dal_db(dal_db.auth_user.email==email_id.lower()).select():
raise HTTP(404)
else:
# Validate the email and activation key
check_user =
dal_db(dal_db.Signup.email==email_id).select().first()
if ((check_user!=None) and (check_user.activation_key!='') and
(check_user.activation_key!=None) and
(check_user.activation_key==activation_key)):
# Define the registration form
form = SQLFORM(dal_db.auth_user,
fields=['first_name','last_name','location','password'],
submit_button='Complete Registration',
_id='info',
_name='registration'
)
form.custom.widget.password['_checkref']='#showpassword'
form.custom.widget.password.requires=dal_db.auth_user.password.requires
if form.validate(hideerror=True):
# Get values from form fields
password = form.vars.password
first_name = form.vars.first_name
last_name = form.vars.last_name
location = form.vars.location
userFriendsID = request.vars.userFriendsID
if (session.profile_image is None) and
(session.thumb_image is None):
image_error_msg = "Required"
return
dict(form=form,image_error_msg=image_error_msg)
# Create User object
new_user =
User(email_id.lower(),password,first_name,location,session.profile_image,session.thumb_image)
new_user.set_user_extras(last_name)
# Define cross transaction options
xg_options = db.create_transaction_options(xg=True)
# Run the new user insert in transaction
registered_id =
db.run_in_transaction_options(xg_options,new_user.create_user,dal_db)
# Make activation key NULL
updated_records =
check_user.update_record(activation_key='',activation_ind='Y')
# Auto Login
user_dict = new_user.__dict__
user_dict['id']=registered_id
session.auth = Storage(user=user_dict,
last_visit=datetime.now(),
expiration=auth.settings.expiration,
hmac_key=web2py_uuid())
redirect(URL('user','profile'))
elif form.errors:
if form.errors.first_name!=None:
form.errors.first_name="First Name cannnot be empty"
if form.errors.location!=None:
form.errors.location="Please tell us where you live"
if form.errors.password!=None:
form.errors.password="Please provide atleast 6
characters"
else:
form.errors.first_name=""
form.errors.location=""
form.errors.password=""
else:
raise HTTP(404)
except (Error, Exception), ex:
logger.error("Fatal Error while registering " + str(ex))
raise HTTP(500)
return dict(form=form,image_error_msg=image_error_msg)
The image upload form code is derived from the source:
http://www.web2pyslices.com/slice/show/1388/google-app-engine-blobstore-api-support
and is implemented with modifications as:
form = SQLFORM(dal_db.blobstore_image,
fields=['blob_key'],_name='uploadimage')
# Get the dynamic upload_url for blobstore and set the form action
upload_url =
blobstore.create_upload_url(URL(r=request,f='upload_image'))
form['_action']=upload_url
(begin, end) = form._xml()
form.custom.begin = XML("<%s %s>" % (form.tag, begin))
image_url = ""
if request.args and request.args[0] and request.args[0]!='-1':
row =
dal_db(dal_db.blobstore_image.id==request.args[0]).select().first()
if row and row.blob_key:
session.image_id = request.args[0]
image_url = row.image_url
elif request.args and request.args[0]=='-1':
image_url="#"
blob_info = None
if request.vars.blob_key == '':
request.vars.blob_key = None
if request.vars.blob_key != None:
blob_info = blobstore.parse_blob_info(request.vars.blob_key)
del request.vars['blob_key']
if form.accepts(request.vars,formname="uploadimage"):
row = dal_db(dal_db.blobstore_image.id ==
form.vars.id).select().first()
# If the image has been updated, remove the previous image from
blobstore
if (blob_info and (row and row.blob_key)):
blobstore.delete(row.blob_key)
row.update_record(blob_key=None)
if blob_info:
try:
# Check for valid extensions
content_type = blob_info.content_type.split('/')[1]
if content_type!='jpeg' and content_type!='png':
raise Exception("Uploaded image does not have a valid
content_type")
elif blob_info.size > 1048576:
raise Exception("Uploaded image is greater than 1 MB")
else:
key = blob_info.key()
url = get_serving_url(str(blob_info.key()))
uploaded_image = images.Image(blob_key=blob_info.key())
uploaded_image.rotate(360)
if (blob_info.content_type).split('/')[1]=='jpeg':
uploaded_image.execute_transforms(output_encoding=images.JPEG)
else:
uploaded_image.execute_transforms()
if uploaded_image.width < 300 or uploaded_image.height
< 300:
raise Exception("Image size less than 300x300")
session.image_width = uploaded_image.width
session.image_height = uploaded_image.height
logger.debug(str(session.image_width))
logger.debug(str(session.image_height))
row.update_record(blob_key = key,image_url = url)
except (Error,Exception), err:
logger.debug("Exception Raised: " + str(err))
blobstore.delete(blob_info.key())
raise HTTP(303,Location=
URL(r=request,f='upload_image',args='-1'))
raise HTTP(303,Location= URL(r=request,f='upload_image',
args=form.vars.id))
elif form.errors:
logger.info(str(form.errors))
if blob_info:
blobstore.delete(blob_info.key())
raise HTTP(303,Location= URL(r=request,f='upload_image',args='-1'))
return dict(form=form,image_url=image_url)
In the view the image upload form is included as a component with ajax=False
For implementing the ajax functionality for uploading profile image we are
using ajaxForm of http://jquery.malsup.com/form/
The code for the .load component is :
{{if image_url=="":}}
<span id="greetingmsg">Please upload a (JPG,PNG) image of minimum
300x300 px and a maximum size of 5MB</span>
{{else:}}
<table>
<tr>
<td><img src="{{=image_url}}" id="selectedphoto"/></td>
<td><div id="previewBox"><img src="{{=image_url}}"
id="preview"/></div></td>
</tr>
</table>
<span id="greetingmsg"></span>
<span id="photocoord">
<input type="hidden" id="x" name="x"/>
<input type="hidden" id="y" name="y"/>
<input type="hidden" id="w" name="w"/>
<input type="hidden" id="h" name="h"/>
<a href="#" id="coord">Done</a>
</span>
{{pass}}
{{=form.custom.begin}}
{{=form.custom.widget.blob_key}}
{{=form.custom.end}}
<script language="javascript" type="text/javascript">
$(document).ready(function(){
$('form').ajaxForm({target:'#target'});
$('input[name=blob_key]').change(function(){
$('#greetingmsg').html('Uploading...');
$('#target form').submit();
});
{{if image_url!="":}}
$('#selectedphoto').Jcrop({
minSize: [300,300],
boxWidth: 440,
boxHeight: 330,
setSelect: [300, 300, 0, 0 ],
aspectRatio: 1,
onChange: updatePreview
},function(){
// Use the API to get the real image size
var bounds = this.getBounds();
boundx = bounds[0];
boundy = bounds[1];
$('#photocoord').show();
$('#photoUpload').css({'margin-left':-($('#photoUpload').width()/2+30)});
});
$('#previewBox').css({width:'300px', height:'300px',
overflow:'hidden'});
$('#photoUpload').css({'margin-left':-($('#photoUpload').width()/2+30)});
$('#photocoord a').click(function(){
//$('span.temp').html('Saving Image');
ajax('create_profile_pic', ['x','y','w','h'], ':eval');
return false;
});
{{pass}}
});
</script>
*The Problem:*
When the user clicks on "Complete Registration" button, the code redirects
to the profile page as we can see in the GAE server logs
INFO 2012-06-14 15:43:31,057 dev_appserver.py:2891] "POST
/devekayan*/registration/[email protected]&id=755047905ed0e8df1d90cfa687ca0f4986d1e946
HTTP/1.1" 303 -*
INFO 2012-06-14 15:43:31,242 gaehandler.py:69] **** Request:
149.23ms/150.00ms (real time/cpu time)
INFO 2012-06-14 15:43:31,248 recording.py:486] Saved; key:
__appstats__:011000, part: 60 bytes, full: 6092 bytes, overhead: 0.000 +
0.005; link: http://localhost:8080/_ah/stats/details?time=1339688611093
INFO 2012-06-14 15:43:31,266 dev_appserver.py:2891] "GET
/devekayan*/user/profile
HTTP/1.1" 200 -*
INFO 2012-06-14 15:43:31,322 dev_appserver.py:2891] "GET
/devekayan/static/js/jquery.js?_=1339688611296 HTTP/1.1" 200 -
INFO 2012-06-14 15:43:31,460 dev_appserver.py:2891] "GET
/devekayan/static/js/web2py.js?_=1339688611425 HTTP/1.1" 200 -
INFO 2012-06-14 15:43:31,508 dev_appserver.py:2891] "GET
/devekayan/static/js/jquery.easing.js?_=1339688611466 HTTP/1.1" 200 -
INFO 2012-06-14 15:43:31,547 dev_appserver.py:2891] "GET
/devekayan/static/js/jquery.form.js?_=1339688611518 HTTP/1.1" 200 -
But on the client side nothing happens. (i.e. the user remains on the
registration page itself). The profile page is not loaded at all.
The problem started occurring only after we integrated the blobstore
service. Earlier we were storing images in datastore and everything was
working fine.
I have reproduced the problem in production and on both Chrome and Firefox
browers.
Can anyone tell me what might be the problem ?
Thanks,
Sushant Taneja