History & HDA API: fix unicode support in update

This commit is contained in:
Carl Eberhard
2014-01-10 12:55:43 -05:00
parent cabe4ee445
commit eaf33b5d40
5 changed files with 97 additions and 186 deletions
+23
View File
@@ -179,6 +179,29 @@ class BaseController( object ):
rval[k] = self.encode_all_ids(trans, v, recursive)
return rval
# incoming param validation
# should probably be in sep. serializer class/object _used_ by controller
def validate_and_sanitize_basestring( self, key, val ):
if not isinstance( val, basestring ):
raise ValueError( '%s must be a string or unicode: %s' %( key, str( type( val ) ) ) )
return unicode( sanitize_html( val, 'utf-8', 'text/html' ), 'utf-8' )
def validate_and_sanitize_basestring_list( self, key, val ):
if not isinstance( val, list ):
raise ValueError( '%s must be a list: %s' %( key, str( type( val ) ) ) )
return [ unicode( sanitize_html( t, 'utf-8', 'text/html' ), 'utf-8' ) for t in val ]
def validate_boolean( self, key, val ):
if not isinstance( val, bool ):
raise ValueError( '%s must be a boolean: %s' %( key, str( type( val ) ) ) )
return val
#TODO:
#def validate_integer( self, key, val, min, max ):
#def validate_float( self, key, val, min, max ):
#def validate_number( self, key, val, min, max ):
#def validate_genome_build( self, key, val ):
Root = BaseController
+5 -25
View File
@@ -342,34 +342,14 @@ class HistoriesController( BaseAPIController, UsesHistoryMixin, UsesTagsMixin ):
'id', 'model_class', 'nice_size', 'contents_url', 'purged', 'tags',
'state', 'state_details', 'state_ids'
)
validated_payload = {}
for key, val in payload.items():
# TODO: lots of boilerplate here, but overhead on abstraction is equally onerous
if key == 'name':
if not ( isinstance( val, str ) or isinstance( val, unicode ) ):
raise ValueError( 'name must be a string or unicode: %s' %( str( type( val ) ) ) )
validated_payload[ 'name' ] = sanitize_html( val, 'utf-8' )
#TODO:?? if sanitized != val: log.warn( 'script kiddie' )
elif key == 'deleted':
if not isinstance( val, bool ):
raise ValueError( 'deleted must be a boolean: %s' %( str( type( val ) ) ) )
validated_payload[ 'deleted' ] = val
elif key == 'published':
if not isinstance( val, bool ):
raise ValueError( 'published must be a boolean: %s' %( str( type( val ) ) ) )
validated_payload[ 'published' ] = val
elif key == 'genome_build' and val is not None:
if not ( isinstance( val, str ) or isinstance( val, unicode ) ):
raise ValueError( 'genome_build must be a string: %s' %( str( type( val ) ) ) )
validated_payload[ 'genome_build' ] = sanitize_html( val, 'utf-8' )
elif key == 'annotation':
if not ( isinstance( val, str ) or isinstance( val, unicode ) ):
raise ValueError( 'annotation must be a string or unicode: %s' %( str( type( val ) ) ) )
validated_payload[ 'annotation' ] = sanitize_html( val, 'utf-8' )
if key in ( 'name', 'genome_build', 'annotation' ):
validated_payload[ key ] = self.validate_and_sanitize_basestring( key, val )
if key in ( 'deleted', 'published' ):
validated_payload[ key ] = self.validate_boolean( key, val )
elif key == 'tags':
if isinstance( val, list ):
validated_payload[ 'tags' ] = [ sanitize_html( t, 'utf-8' ) for t in val ]
validated_payload[ key ] = self.validate_and_sanitize_basestring_list( key, val )
elif key not in valid_but_uneditable_keys:
pass
#log.warn( 'unknown key: %s', str( key ) )
@@ -385,38 +385,17 @@ class HistoryContentsController( BaseAPIController, UsesHistoryDatasetAssociatio
)
validated_payload = {}
for key, val in payload.items():
# TODO: lots of boilerplate here, but overhead on abstraction is equally onerous
# typecheck, parse, remap key
if key == 'name':
if not ( isinstance( val, str ) or isinstance( val, unicode ) ):
raise ValueError( 'name must be a string or unicode: %s' %( str( type( val ) ) ) )
validated_payload[ 'name' ] = util.sanitize_html.sanitize_html( val, 'utf-8' )
#TODO:?? if sanitized != val: log.warn( 'script kiddie' )
elif key == 'deleted':
if not isinstance( val, bool ):
raise ValueError( 'deleted must be a boolean: %s' %( str( type( val ) ) ) )
validated_payload[ 'deleted' ] = val
elif key == 'visible':
if not isinstance( val, bool ):
raise ValueError( 'visible must be a boolean: %s' %( str( type( val ) ) ) )
validated_payload[ 'visible' ] = val
elif key == 'genome_build':
if not ( isinstance( val, str ) or isinstance( val, unicode ) ):
raise ValueError( 'genome_build must be a string: %s' %( str( type( val ) ) ) )
validated_payload[ 'dbkey' ] = util.sanitize_html.sanitize_html( val, 'utf-8' )
elif key == 'annotation' and val is not None:
if not ( isinstance( val, str ) or isinstance( val, unicode ) ):
raise ValueError( 'annotation must be a string or unicode: %s' %( str( type( val ) ) ) )
validated_payload[ 'annotation' ] = util.sanitize_html.sanitize_html( val, 'utf-8' )
elif key == 'misc_info':
if not ( isinstance( val, str ) or isinstance( val, unicode ) ):
raise ValueError( 'misc_info must be a string or unicode: %s' %( str( type( val ) ) ) )
validated_payload[ 'info' ] = util.sanitize_html.sanitize_html( val, 'utf-8' )
if key in ( 'name', 'genome_build', 'misc_info', 'annotation' ):
val = self.validate_and_sanitize_basestring( key, val )
#TODO: need better remap system or eliminate the need altogether
key = 'dbkey' if key == 'genome_build' else key
key = 'info' if key == 'misc_info' else key
validated_payload[ key ] = val
if key in ( 'deleted', 'visible' ):
validated_payload[ key ] = self.validate_boolean( key, val )
elif key == 'tags':
if isinstance( val, list ):
validated_payload[ 'tags' ] = [ sanitize_html( t, 'utf-8' ) for t in val ]
validated_payload[ key ] = self.validate_and_sanitize_basestring_list( key, val )
elif key not in valid_but_uneditable_keys:
pass
#log.warn( 'unknown key: %s', str( key ) )
return validated_payload
+35 -75
View File
@@ -174,24 +174,14 @@ spaceghost.historypanel.waitForHdas().then( function(){
hdaShow = this.api.hdas.show( lastHistory.id, firstHda.id );
this.test.assert( hdaShow.name === 'New name', "Update sanitized name: " + hdaShow.name );
//NOTE!: this fails on sqlite3 (with default setup)
try {
this.test.comment( 'update should allow unicode in names' );
var unicodeName = 'Ржевский сапоги';
returned = this.api.hdas.update( lastHistory.id, firstHda.id, {
name : unicodeName
});
//this.debug( 'returned:\n' + this.jsonStr( returned ) );
hdaShow = this.api.hdas.show( lastHistory.id, firstHda.id );
this.test.assert( hdaShow.name === unicodeName, "Update accepted unicode name: " + hdaShow.name );
} catch( err ){
//this.debug( this.jsonStr( err ) );
if( ( err instanceof this.api.APIError )
&& ( err.status === 500 )
&& ( err.message.indexOf( '(ProgrammingError) You must not use 8-bit bytestrings' ) !== -1 ) ){
this.skipTest( 'Unicode update failed. Are you using sqlite3 as the db?' );
}
}
this.test.comment( 'update should allow unicode in names' );
var unicodeName = 'Ржевский сапоги';
returned = this.api.hdas.update( lastHistory.id, firstHda.id, {
name : unicodeName
});
//this.debug( 'returned:\n' + this.jsonStr( returned ) );
hdaShow = this.api.hdas.show( lastHistory.id, firstHda.id );
this.test.assert( hdaShow.name === unicodeName, "Update accepted unicode name: " + hdaShow.name );
this.test.comment( 'update should allow escaped quotations in names' );
var quotedName = '"Bler"';
@@ -239,11 +229,11 @@ spaceghost.historypanel.waitForHdas().then( function(){
});
//this.debug( 'returned:\n' + this.jsonStr( returned ) );
hdaShow = this.api.hdas.show( lastHistory.id, firstHda.id );
//this.debug( 'hdaShow:\n' + this.jsonStr( hdaShow ) );
this.test.assert( hdaShow.genome_build === 'hg18',
"genome_build successfully set via update: " + hdaShow.genome_build );
this.test.assert( hdaShow.metadata_dbkey === 'hg18',
"metadata_dbkey successfully set via the same update: " + hdaShow.metadata_dbkey );
this.test.comment( 'update should sanitize any genome_build' );
returned = this.api.hdas.update( lastHistory.id, firstHda.id, {
genome_build : 'hg18<script type="text/javascript" src="bler">alert("blah");</script>'
@@ -257,23 +247,14 @@ spaceghost.historypanel.waitForHdas().then( function(){
this.test.comment( 'update should allow unicode in genome builds' );
var unicodeBuild = 'Ржевский18';
//NOTE!: this fails on sqlite3 (with default setup)
try {
returned = this.api.hdas.update( lastHistory.id, firstHda.id, {
name : unicodeBuild
});
//this.debug( 'returned:\n' + this.jsonStr( returned ) );
hdaShow = this.api.hdas.show( lastHistory.id, firstHda.id );
this.test.assert( hdaShow.genome_build === unicodeBuild,
"Update accepted unicode genome_build: " + hdaShow.name );
} catch( err ){
//this.debug( this.jsonStr( err ) );
if( ( err instanceof this.api.APIError )
&& ( err.status === 500 )
&& ( err.message.indexOf( '(ProgrammingError) You must not use 8-bit bytestrings' ) !== -1 ) ){
this.skipTest( 'Unicode update failed. Are you using sqlite3 as the db?' );
}
}
returned = this.api.hdas.update( lastHistory.id, firstHda.id, {
genome_build : unicodeBuild
});
this.debug( 'returned:\n' + this.jsonStr( returned ) );
hdaShow = this.api.hdas.show( lastHistory.id, firstHda.id );
this.debug( 'hdaShow:\n' + this.jsonStr( hdaShow ) );
this.test.assert( hdaShow.genome_build === unicodeBuild,
"Update accepted unicode genome_build: " + hdaShow.genome_build );
// ........................................................................................... misc_info/info
this.test.comment( 'update should allow changing the misc_info' );
@@ -298,25 +279,14 @@ spaceghost.historypanel.waitForHdas().then( function(){
this.test.comment( 'update should allow unicode in misc_info' );
var unicodeInfo = '여보!';
//NOTE!: this fails on sqlite3 (with default setup)
try {
returned = this.api.hdas.update( lastHistory.id, firstHda.id, {
misc_info : unicodeInfo
});
//this.debug( 'returned:\n' + this.jsonStr( returned ) );
hdaShow = this.api.hdas.show( lastHistory.id, firstHda.id );
this.test.assert( hdaShow.misc_info === unicodeInfo,
"Update accepted unicode misc_info: " + hdaShow.misc_info );
} catch( err ){
//this.debug( this.jsonStr( err ) );
if( ( err instanceof this.api.APIError )
&& ( err.status === 500 )
&& ( err.message.indexOf( '(ProgrammingError) You must not use 8-bit bytestrings' ) !== -1 ) ){
this.skipTest( 'Unicode update failed. Are you using sqlite3 as the db?' );
}
}
returned = this.api.hdas.update( lastHistory.id, firstHda.id, {
misc_info : unicodeInfo
});
//this.debug( 'returned:\n' + this.jsonStr( returned ) );
hdaShow = this.api.hdas.show( lastHistory.id, firstHda.id );
this.test.assert( hdaShow.misc_info === unicodeInfo,
"Update accepted unicode misc_info: " + hdaShow.misc_info );
/*
// ........................................................................................... annotation
// currently fails because no annotation is returned in details
this.test.comment( 'update should allow changing the annotation' );
@@ -338,25 +308,15 @@ spaceghost.historypanel.waitForHdas().then( function(){
this.test.assert( hdaShow.annotation === 'New annotation',
"Update sanitized annotation: " + hdaShow.annotation );
//NOTE!: this fails on sqlite3 (with default setup)
try {
this.test.comment( 'update should allow unicode in annotations' );
var unicodeAnnotation = 'お願いは、それが落下させない';
returned = this.api.hdas.update( lastHistory.id, firstHda.id, {
annotation : unicodeAnnotation
});
//this.debug( 'returned:\n' + this.jsonStr( returned ) );
hdaShow = this.api.hdas.show( lastHistory.id, firstHda.id );
this.test.assert( hdaShow.annotation === unicodeAnnotation,
"Update accepted unicode annotation: " + hdaShow.annotation );
} catch( err ){
//this.debug( this.jsonStr( err ) );
if( ( err instanceof this.api.APIError )
&& ( err.status === 500 )
&& ( err.message.indexOf( '(ProgrammingError) You must not use 8-bit bytestrings' ) !== -1 ) ){
this.skipTest( 'Unicode update failed. Are you using sqlite3 as the db?' );
}
}
this.test.comment( 'update should allow unicode in annotations' );
var unicodeAnnotation = 'お願いは、それが落下させない';
returned = this.api.hdas.update( lastHistory.id, firstHda.id, {
annotation : unicodeAnnotation
});
//this.debug( 'returned:\n' + this.jsonStr( returned ) );
hdaShow = this.api.hdas.show( lastHistory.id, firstHda.id );
this.test.assert( hdaShow.annotation === unicodeAnnotation,
"Update accepted unicode annotation: " + hdaShow.annotation );
this.test.comment( 'update should allow escaped quotations in annotations' );
var quotedAnnotation = '"Bler"';
@@ -367,8 +327,6 @@ spaceghost.historypanel.waitForHdas().then( function(){
hdaShow = this.api.hdas.show( lastHistory.id, firstHda.id );
this.test.assert( hdaShow.annotation === quotedAnnotation,
"Update accepted escaped quotations in annotation: " + hdaShow.annotation );
*/
// ------------------------------------------------------------------------------------------- ERRORS
this.test.comment( 'create should error with "Please define the source" when the param "from_ld_id" is not used' );
@@ -391,6 +349,8 @@ spaceghost.historypanel.waitForHdas().then( function(){
//var returned = this.api.hdas.update( lastHistory.id, { deleted: true, blerp: 'blerp' });
//this.debug( 'returned:' + this.jsonStr( returned ) );
//this.debug( 'page:' + this.jsonStr( this.page ) );
/*
*/
});
// ===================================================================
+25 -56
View File
@@ -218,23 +218,14 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
this.test.assert( historyShow.name === 'New name', "Update sanitized name: " + historyShow.name );
//NOTE!: this fails on sqlite3 (with default setup)
try {
this.test.comment( 'update should allow unicode in names' );
var unicodeName = '桜ゲノム';
returned = this.api.histories.update( newFirstHistory.id, {
name : unicodeName
});
//this.debug( 'returned:\n' + this.jsonStr( returned ) );
historyShow = this.api.histories.show( newFirstHistory.id );
this.test.assert( historyShow.name === unicodeName, "Update accepted unicode name: " + historyShow.name );
} catch( err ){
//this.debug( this.jsonStr( err ) );
if( ( err instanceof this.api.APIError )
&& ( err.status === 500 )
&& ( err.message.indexOf( '(ProgrammingError) You must not use 8-bit bytestrings' ) !== -1 ) ){
this.skipTest( 'Unicode update failed. Are you using sqlite3 as the db?' );
}
}
this.test.comment( 'update should allow unicode in names' );
var unicodeName = '桜ゲノム';
returned = this.api.histories.update( newFirstHistory.id, {
name : unicodeName
});
//this.debug( 'returned:\n' + this.jsonStr( returned ) );
historyShow = this.api.histories.show( newFirstHistory.id );
this.test.assert( historyShow.name === unicodeName, "Update accepted unicode name: " + historyShow.name );
this.test.comment( 'update should allow escaped quotations in names' );
var quotedName = '"Bler"';
@@ -294,27 +285,16 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
this.test.assert( historyShow.genome_build === 'hg18',
"Update sanitized genome_build: " + historyShow.genome_build );
// removing for now until I can determine the relationship between unicode and genome_builds
this.test.comment( 'update should allow unicode in genome builds' );
var unicodeBuild = '桜12';
//NOTE!: this fails on sqlite3 (with default setup)
try {
returned = this.api.histories.update( newFirstHistory.id, {
name : unicodeBuild
});
//this.debug( 'returned:\n' + this.jsonStr( returned ) );
historyShow = this.api.histories.show( newFirstHistory.id );
this.test.assert( historyShow.genome_build === unicodeBuild,
"Update accepted unicode genome_build: " + historyShow.genome_build );
} catch( err ){
//this.debug( this.jsonStr( err ) );
if( ( err instanceof this.api.APIError )
&& ( err.status === 500 )
&& ( err.message.indexOf( '(ProgrammingError) You must not use 8-bit bytestrings' ) !== -1 ) ){
this.skipTest( 'Unicode update failed. Are you using sqlite3 as the db?' );
} else {
throw err;
}
}
returned = this.api.histories.update( newFirstHistory.id, {
genome_build : unicodeBuild
});
//this.debug( 'returned:\n' + this.jsonStr( returned ) );
historyShow = this.api.histories.show( newFirstHistory.id );
this.test.assert( historyShow.genome_build === unicodeBuild,
"Update accepted unicode genome_build: " + historyShow.genome_build );
// ........................................................................................... annotation
@@ -337,25 +317,15 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
this.test.assert( historyShow.annotation === 'New annotation',
"Update sanitized annotation: " + historyShow.annotation );
//NOTE!: this fails on sqlite3 (with default setup)
try {
this.test.comment( 'update should allow unicode in annotations' );
var unicodeAnnotation = 'お願いは、それが落下させない';
returned = this.api.histories.update( newFirstHistory.id, {
annotation : unicodeAnnotation
});
//this.debug( 'returned:\n' + this.jsonStr( returned ) );
historyShow = this.api.histories.show( newFirstHistory.id );
this.test.assert( historyShow.annotation === unicodeAnnotation,
"Update accepted unicode annotation: " + historyShow.annotation );
} catch( err ){
//this.debug( this.jsonStr( err ) );
if( ( err instanceof this.api.APIError )
&& ( err.status === 500 )
&& ( err.message.indexOf( '(ProgrammingError) You must not use 8-bit bytestrings' ) !== -1 ) ){
this.skipTest( 'Unicode update failed. Are you using sqlite3 as the db?' );
}
}
this.test.comment( 'update should allow unicode in annotations' );
var unicodeAnnotation = 'お願いは、それが落下させない';
returned = this.api.histories.update( newFirstHistory.id, {
annotation : unicodeAnnotation
});
//this.debug( 'returned:\n' + this.jsonStr( returned ) );
historyShow = this.api.histories.show( newFirstHistory.id );
this.test.assert( historyShow.annotation === unicodeAnnotation,
"Update accepted unicode annotation: " + historyShow.annotation );
this.test.comment( 'update should allow escaped quotations in annotations' );
var quotedAnnotation = '"Bler"';
@@ -371,7 +341,6 @@ spaceghost.thenOpen( spaceghost.baseUrl ).then( function(){
// ------------------------------------------------------------------------------------------- ERRORS
//TODO: make sure expected errors are being passed back (but no permissions checks here - different suite)
// bad ids: index, show, update, delete, undelete
/*
*/
//this.debug( this.jsonStr( historyShow ) );