[2] | 1 | import os, os.path, shutil, urllib, StringIO, re, gzip, tempfile, shutil, zipfile, copy, glob, string |
---|
| 2 | from galaxy.web.base.controller import * |
---|
| 3 | from galaxy import util, jobs |
---|
| 4 | from galaxy.datatypes import sniff |
---|
| 5 | from galaxy.security import RBACAgent |
---|
| 6 | from galaxy.util.json import to_json_string |
---|
| 7 | from galaxy.tools.actions import upload_common |
---|
| 8 | from galaxy.model.orm import * |
---|
| 9 | from galaxy.util.streamball import StreamBall |
---|
| 10 | from galaxy.web.form_builder import AddressField, CheckboxField, SelectField, TextArea, TextField, WorkflowField |
---|
| 11 | import logging, tempfile, zipfile, tarfile, os, sys |
---|
| 12 | |
---|
| 13 | if sys.version_info[:2] < ( 2, 6 ): |
---|
| 14 | zipfile.BadZipFile = zipfile.error |
---|
| 15 | if sys.version_info[:2] < ( 2, 5 ): |
---|
| 16 | zipfile.LargeZipFile = zipfile.error |
---|
| 17 | |
---|
| 18 | log = logging.getLogger( __name__ ) |
---|
| 19 | |
---|
| 20 | # Test for available compression types |
---|
| 21 | tmpd = tempfile.mkdtemp() |
---|
| 22 | comptypes = [] |
---|
| 23 | for comptype in ( 'gz', 'bz2' ): |
---|
| 24 | tmpf = os.path.join( tmpd, 'compression_test.tar.' + comptype ) |
---|
| 25 | try: |
---|
| 26 | archive = tarfile.open( tmpf, 'w:' + comptype ) |
---|
| 27 | archive.close() |
---|
| 28 | comptypes.append( comptype ) |
---|
| 29 | except tarfile.CompressionError: |
---|
| 30 | log.exception( "Compression error when testing %s compression. This option will be disabled for library downloads." % comptype ) |
---|
| 31 | try: |
---|
| 32 | os.unlink( tmpf ) |
---|
| 33 | except OSError: |
---|
| 34 | pass |
---|
| 35 | ziptype = '32' |
---|
| 36 | tmpf = os.path.join( tmpd, 'compression_test.zip' ) |
---|
| 37 | try: |
---|
| 38 | archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED, True ) |
---|
| 39 | archive.close() |
---|
| 40 | comptypes.append( 'zip' ) |
---|
| 41 | ziptype = '64' |
---|
| 42 | except RuntimeError: |
---|
| 43 | log.exception( "Compression error when testing zip compression. This option will be disabled for library downloads." ) |
---|
| 44 | except (TypeError, zipfile.LargeZipFile): |
---|
| 45 | # ZIP64 is only in Python2.5+. Remove TypeError when 2.4 support is dropped |
---|
| 46 | log.warning( 'Max zip file size is 2GB, ZIP64 not supported' ) |
---|
| 47 | comptypes.append( 'zip' ) |
---|
| 48 | try: |
---|
| 49 | os.unlink( tmpf ) |
---|
| 50 | except OSError: |
---|
| 51 | pass |
---|
| 52 | os.rmdir( tmpd ) |
---|
| 53 | |
---|
| 54 | class LibraryCommon( BaseController, UsesFormDefinitionWidgets ): |
---|
| 55 | @web.json |
---|
| 56 | def library_item_updates( self, trans, ids=None, states=None ): |
---|
| 57 | # Avoid caching |
---|
| 58 | trans.response.headers['Pragma'] = 'no-cache' |
---|
| 59 | trans.response.headers['Expires'] = '0' |
---|
| 60 | # Create new HTML for any that have changed |
---|
| 61 | rval = {} |
---|
| 62 | if ids is not None and states is not None: |
---|
| 63 | ids = map( int, ids.split( "," ) ) |
---|
| 64 | states = states.split( "," ) |
---|
| 65 | for id, state in zip( ids, states ): |
---|
| 66 | data = trans.sa_session.query( self.app.model.LibraryDatasetDatasetAssociation ).get( id ) |
---|
| 67 | if data.state != state: |
---|
| 68 | job_ldda = data |
---|
| 69 | while job_ldda.copied_from_library_dataset_dataset_association: |
---|
| 70 | job_ldda = job_ldda.copied_from_library_dataset_dataset_association |
---|
| 71 | force_history_refresh = False |
---|
| 72 | rval[id] = { |
---|
| 73 | "state": data.state, |
---|
| 74 | "html": unicode( trans.fill_template( "library/common/library_item_info.mako", ldda=data ), 'utf-8' ) |
---|
| 75 | #"force_history_refresh": force_history_refresh |
---|
| 76 | } |
---|
| 77 | return rval |
---|
| 78 | @web.expose |
---|
| 79 | def browse_library( self, trans, cntrller, **kwd ): |
---|
| 80 | params = util.Params( kwd ) |
---|
| 81 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 82 | status = params.get( 'status', 'done' ) |
---|
| 83 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 84 | library_id = params.get( 'id', None ) |
---|
| 85 | if not library_id: |
---|
| 86 | # To handle bots |
---|
| 87 | message = "You must specify a library id." |
---|
| 88 | status = 'error' |
---|
| 89 | is_admin = trans.user_is_admin() and cntrller == 'library_admin' |
---|
| 90 | current_user_roles = trans.get_current_user_roles() |
---|
| 91 | try: |
---|
| 92 | library = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( library_id ) ) |
---|
| 93 | except: |
---|
| 94 | # Protect against attempts to phish for valid keys that return libraries |
---|
| 95 | library = None |
---|
| 96 | # Most security for browsing libraries is handled in the template, but do a basic check here. |
---|
| 97 | if not library or not ( is_admin or trans.app.security_agent.can_access_library( current_user_roles, library ) ): |
---|
| 98 | message = "Invalid library id ( %s ) specified." % str( library_id ) |
---|
| 99 | status = 'error' |
---|
| 100 | else: |
---|
| 101 | # If use_panels is True, the library is being accessed via an external link |
---|
| 102 | # which did not originate from within the Galaxy instance, and the library will |
---|
| 103 | # be displayed correctly with the mast head. |
---|
| 104 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 105 | created_ldda_ids = params.get( 'created_ldda_ids', '' ) |
---|
| 106 | hidden_folder_ids = util.listify( params.get( 'hidden_folder_ids', '' ) ) |
---|
| 107 | if created_ldda_ids and not message: |
---|
| 108 | message = "%d datasets are uploading in the background to the library '%s' (each is selected). " % \ |
---|
| 109 | ( len( created_ldda_ids.split( ',' ) ), library.name ) |
---|
| 110 | message += "Don't navigate away from Galaxy or use the browser's \"stop\" or \"reload\" buttons (on this tab) until the " |
---|
| 111 | message += "message \"This job is running\" is cleared from the \"Information\" column below for each selected dataset." |
---|
| 112 | status = "info" |
---|
| 113 | comptypes_t = comptypes |
---|
| 114 | if trans.app.config.nginx_x_archive_files_base: |
---|
| 115 | comptypes_t = ['ngxzip'] |
---|
| 116 | for comptype in trans.app.config.disable_library_comptypes: |
---|
| 117 | # TODO: do this once, not every time (we're gonna raise an |
---|
| 118 | # exception every time after the first time) |
---|
| 119 | try: |
---|
| 120 | comptypes_t.remove( comptype ) |
---|
| 121 | except: |
---|
| 122 | pass |
---|
| 123 | return trans.fill_template( '/library/common/browse_library.mako', |
---|
| 124 | cntrller=cntrller, |
---|
| 125 | use_panels=use_panels, |
---|
| 126 | library=library, |
---|
| 127 | created_ldda_ids=created_ldda_ids, |
---|
| 128 | hidden_folder_ids=hidden_folder_ids, |
---|
| 129 | show_deleted=show_deleted, |
---|
| 130 | comptypes=comptypes_t, |
---|
| 131 | current_user_roles=current_user_roles, |
---|
| 132 | message=message, |
---|
| 133 | status=status ) |
---|
| 134 | return trans.response.send_redirect( web.url_for( use_panels=use_panels, |
---|
| 135 | controller=cntrller, |
---|
| 136 | action='browse_libraries', |
---|
| 137 | default_action=params.get( 'default_action', None ), |
---|
| 138 | message=util.sanitize_text( message ), |
---|
| 139 | status=status ) ) |
---|
| 140 | @web.expose |
---|
| 141 | def library_info( self, trans, cntrller, **kwd ): |
---|
| 142 | params = util.Params( kwd ) |
---|
| 143 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 144 | status = params.get( 'status', 'done' ) |
---|
| 145 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 146 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 147 | is_admin = trans.user_is_admin() and cntrller == 'library_admin' |
---|
| 148 | current_user_roles = trans.get_current_user_roles() |
---|
| 149 | library_id = params.get( 'id', None ) |
---|
| 150 | try: |
---|
| 151 | library = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( library_id ) ) |
---|
| 152 | except: |
---|
| 153 | library = None |
---|
| 154 | self._check_access( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 155 | if params.get( 'library_info_button', False ): |
---|
| 156 | self._check_modify( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 157 | old_name = library.name |
---|
| 158 | new_name = util.restore_text( params.get( 'name', 'No name' ) ) |
---|
| 159 | if not new_name: |
---|
| 160 | message = 'Enter a valid name' |
---|
| 161 | status='error' |
---|
| 162 | else: |
---|
| 163 | new_description = util.restore_text( params.get( 'description', '' ) ) |
---|
| 164 | new_synopsis = util.restore_text( params.get( 'synopsis', '' ) ) |
---|
| 165 | if new_synopsis in [ None, 'None' ]: |
---|
| 166 | new_synopsis = '' |
---|
| 167 | library.name = new_name |
---|
| 168 | library.description = new_description |
---|
| 169 | library.synopsis = new_synopsis |
---|
| 170 | # Rename the root_folder |
---|
| 171 | library.root_folder.name = new_name |
---|
| 172 | library.root_folder.description = new_description |
---|
| 173 | trans.sa_session.add_all( ( library, library.root_folder ) ) |
---|
| 174 | trans.sa_session.flush() |
---|
| 175 | message = "Information updated for library '%s'." % library.name |
---|
| 176 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 177 | action='library_info', |
---|
| 178 | cntrller=cntrller, |
---|
| 179 | use_panels=use_panels, |
---|
| 180 | id=trans.security.encode_id( library.id ), |
---|
| 181 | show_deleted=show_deleted, |
---|
| 182 | message=util.sanitize_text( message ), |
---|
| 183 | status='done' ) ) |
---|
| 184 | # See if we have any associated templates |
---|
| 185 | info_association, inherited = library.get_info_association() |
---|
| 186 | widgets = library.get_template_widgets( trans ) |
---|
| 187 | widget_fields_have_contents = self.widget_fields_have_contents( widgets ) |
---|
| 188 | return trans.fill_template( '/library/common/library_info.mako', |
---|
| 189 | cntrller=cntrller, |
---|
| 190 | use_panels=use_panels, |
---|
| 191 | library=library, |
---|
| 192 | widgets=widgets, |
---|
| 193 | widget_fields_have_contents=widget_fields_have_contents, |
---|
| 194 | current_user_roles=current_user_roles, |
---|
| 195 | show_deleted=show_deleted, |
---|
| 196 | info_association=info_association, |
---|
| 197 | inherited=inherited, |
---|
| 198 | message=message, |
---|
| 199 | status=status ) |
---|
| 200 | @web.expose |
---|
| 201 | def library_permissions( self, trans, cntrller, **kwd ): |
---|
| 202 | params = util.Params( kwd ) |
---|
| 203 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 204 | status = params.get( 'status', 'done' ) |
---|
| 205 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 206 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 207 | is_admin = trans.user_is_admin() and cntrller == 'library_admin' |
---|
| 208 | current_user_roles = trans.get_current_user_roles() |
---|
| 209 | library_id = params.get( 'id', None ) |
---|
| 210 | try: |
---|
| 211 | library = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( library_id ) ) |
---|
| 212 | except: |
---|
| 213 | library = None |
---|
| 214 | self._check_access( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 215 | self._check_manage( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 216 | if params.get( 'update_roles_button', False ): |
---|
| 217 | # The user clicked the Save button on the 'Associate With Roles' form |
---|
| 218 | permissions = {} |
---|
| 219 | for k, v in trans.app.model.Library.permitted_actions.items(): |
---|
| 220 | in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( x ) for x in util.listify( params.get( k + '_in', [] ) ) ] |
---|
| 221 | permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles |
---|
| 222 | trans.app.security_agent.set_all_library_permissions( library, permissions ) |
---|
| 223 | trans.sa_session.refresh( library ) |
---|
| 224 | # Copy the permissions to the root folder |
---|
| 225 | trans.app.security_agent.copy_library_permissions( library, library.root_folder ) |
---|
| 226 | message = "Permissions updated for library '%s'." % library.name |
---|
| 227 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 228 | action='library_permissions', |
---|
| 229 | cntrller=cntrller, |
---|
| 230 | use_panels=use_panels, |
---|
| 231 | id=trans.security.encode_id( library.id ), |
---|
| 232 | show_deleted=show_deleted, |
---|
| 233 | message=util.sanitize_text( message ), |
---|
| 234 | status='done' ) ) |
---|
| 235 | roles = trans.app.security_agent.get_legitimate_roles( trans, library, cntrller ) |
---|
| 236 | return trans.fill_template( '/library/common/library_permissions.mako', |
---|
| 237 | cntrller=cntrller, |
---|
| 238 | use_panels=use_panels, |
---|
| 239 | library=library, |
---|
| 240 | current_user_roles=current_user_roles, |
---|
| 241 | roles=roles, |
---|
| 242 | show_deleted=show_deleted, |
---|
| 243 | message=message, |
---|
| 244 | status=status ) |
---|
| 245 | @web.expose |
---|
| 246 | def create_folder( self, trans, cntrller, parent_id, library_id, **kwd ): |
---|
| 247 | params = util.Params( kwd ) |
---|
| 248 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 249 | status = params.get( 'status', 'done' ) |
---|
| 250 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 251 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 252 | is_admin = trans.user_is_admin() and cntrller in ( 'library_admin', 'api' ) |
---|
| 253 | current_user_roles = trans.get_current_user_roles() |
---|
| 254 | try: |
---|
| 255 | parent_folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( trans.security.decode_id( parent_id ) ) |
---|
| 256 | except: |
---|
| 257 | parent_folder = None |
---|
| 258 | # Check the library which actually contains the user-supplied parent folder, not the user-supplied |
---|
| 259 | # library, which could be anything. |
---|
| 260 | if parent_folder: |
---|
| 261 | parent_library = parent_folder.parent_library |
---|
| 262 | self._check_access( trans, cntrller, is_admin, parent_folder, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 263 | self._check_add( trans, cntrller, is_admin, parent_folder, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 264 | if params.get( 'new_folder_button', False ) or cntrller == 'api': |
---|
| 265 | new_folder = trans.app.model.LibraryFolder( name=util.restore_text( params.name ), |
---|
| 266 | description=util.restore_text( params.description ) ) |
---|
| 267 | # We are associating the last used genome build with folders, so we will always |
---|
| 268 | # initialize a new folder with the first dbkey in util.dbnames which is currently |
---|
| 269 | # ? unspecified (?) |
---|
| 270 | new_folder.genome_build = util.dbnames.default_value |
---|
| 271 | parent_folder.add_folder( new_folder ) |
---|
| 272 | trans.sa_session.add( new_folder ) |
---|
| 273 | trans.sa_session.flush() |
---|
| 274 | # New folders default to having the same permissions as their parent folder |
---|
| 275 | trans.app.security_agent.copy_library_permissions( parent_folder, new_folder ) |
---|
| 276 | # If we're creating in the API, we're done |
---|
| 277 | if cntrller == 'api': |
---|
| 278 | return 200, dict( created=new_folder ) |
---|
| 279 | # If we have an inheritable template, redirect to the folder_info page so information |
---|
| 280 | # can be filled in immediately. |
---|
| 281 | widgets = [] |
---|
| 282 | info_association, inherited = new_folder.get_info_association() |
---|
| 283 | if info_association and ( not( inherited ) or info_association.inheritable ): |
---|
| 284 | widgets = new_folder.get_template_widgets( trans ) |
---|
| 285 | if info_association: |
---|
| 286 | message = "The new folder named '%s' has been added to the data library. " % new_folder.name |
---|
| 287 | message += "Additional information about this folder may be added using the inherited template." |
---|
| 288 | return trans.fill_template( '/library/common/folder_info.mako', |
---|
| 289 | cntrller=cntrller, |
---|
| 290 | use_panels=use_panels, |
---|
| 291 | folder=new_folder, |
---|
| 292 | library_id=library_id, |
---|
| 293 | widgets=widgets, |
---|
| 294 | current_user_roles=current_user_roles, |
---|
| 295 | show_deleted=show_deleted, |
---|
| 296 | info_association=info_association, |
---|
| 297 | inherited=inherited, |
---|
| 298 | message=message, |
---|
| 299 | status='done' ) |
---|
| 300 | # If not inheritable info_association, redirect to the library. |
---|
| 301 | message = "The new folder named '%s' has been added to the data library." % new_folder.name |
---|
| 302 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 303 | action='browse_library', |
---|
| 304 | cntrller=cntrller, |
---|
| 305 | use_panels=use_panels, |
---|
| 306 | id=library_id, |
---|
| 307 | show_deleted=show_deleted, |
---|
| 308 | message=util.sanitize_text( message ), |
---|
| 309 | status='done' ) ) |
---|
| 310 | # We do not render any template widgets on creation pages since saving the info_association |
---|
| 311 | # cannot occur before the associated item is saved. |
---|
| 312 | return trans.fill_template( '/library/common/new_folder.mako', |
---|
| 313 | cntrller=cntrller, |
---|
| 314 | use_panels=use_panels, |
---|
| 315 | library_id=library_id, |
---|
| 316 | folder=parent_folder, |
---|
| 317 | show_deleted=show_deleted, |
---|
| 318 | message=message, |
---|
| 319 | status=status ) |
---|
| 320 | @web.expose |
---|
| 321 | def folder_info( self, trans, cntrller, id, library_id, **kwd ): |
---|
| 322 | params = util.Params( kwd ) |
---|
| 323 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 324 | status = params.get( 'status', 'done' ) |
---|
| 325 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 326 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 327 | is_admin = trans.user_is_admin() and cntrller == 'library_admin' |
---|
| 328 | current_user_roles = trans.get_current_user_roles() |
---|
| 329 | try: |
---|
| 330 | folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( trans.security.decode_id( id ) ) |
---|
| 331 | except: |
---|
| 332 | folder = None |
---|
| 333 | self._check_access( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 334 | if params.get( 'rename_folder_button', False ): |
---|
| 335 | self._check_modify( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 336 | old_name = folder.name |
---|
| 337 | new_name = util.restore_text( params.name ) |
---|
| 338 | new_description = util.restore_text( params.description ) |
---|
| 339 | if not new_name: |
---|
| 340 | message = 'Enter a valid name' |
---|
| 341 | status='error' |
---|
| 342 | else: |
---|
| 343 | folder.name = new_name |
---|
| 344 | folder.description = new_description |
---|
| 345 | trans.sa_session.add( folder ) |
---|
| 346 | trans.sa_session.flush() |
---|
| 347 | message = "Information updated for folder '%s'." % folder.name |
---|
| 348 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 349 | action='folder_info', |
---|
| 350 | cntrller=cntrller, |
---|
| 351 | use_panels=use_panels, |
---|
| 352 | id=id, |
---|
| 353 | library_id=library_id, |
---|
| 354 | show_deleted=show_deleted, |
---|
| 355 | message=util.sanitize_text( message ), |
---|
| 356 | status='done' ) ) |
---|
| 357 | # See if we have any associated templates |
---|
| 358 | widgets = [] |
---|
| 359 | widget_fields_have_contents = False |
---|
| 360 | info_association, inherited = folder.get_info_association() |
---|
| 361 | if info_association and ( not( inherited ) or info_association.inheritable ): |
---|
| 362 | widgets = folder.get_template_widgets( trans ) |
---|
| 363 | widget_fields_have_contents = self.widget_fields_have_contents( widgets ) |
---|
| 364 | return trans.fill_template( '/library/common/folder_info.mako', |
---|
| 365 | cntrller=cntrller, |
---|
| 366 | use_panels=use_panels, |
---|
| 367 | folder=folder, |
---|
| 368 | library_id=library_id, |
---|
| 369 | widgets=widgets, |
---|
| 370 | widget_fields_have_contents=widget_fields_have_contents, |
---|
| 371 | current_user_roles=current_user_roles, |
---|
| 372 | show_deleted=show_deleted, |
---|
| 373 | info_association=info_association, |
---|
| 374 | inherited=inherited, |
---|
| 375 | message=message, |
---|
| 376 | status=status ) |
---|
| 377 | @web.expose |
---|
| 378 | def folder_permissions( self, trans, cntrller, id, library_id, **kwd ): |
---|
| 379 | params = util.Params( kwd ) |
---|
| 380 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 381 | status = params.get( 'status', 'done' ) |
---|
| 382 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 383 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 384 | is_admin = trans.user_is_admin() and cntrller == 'library_admin' |
---|
| 385 | current_user_roles = trans.get_current_user_roles() |
---|
| 386 | try: |
---|
| 387 | folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( trans.security.decode_id( id ) ) |
---|
| 388 | except: |
---|
| 389 | folder = None |
---|
| 390 | self._check_access( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 391 | self._check_manage( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 392 | if params.get( 'update_roles_button', False ): |
---|
| 393 | # The user clicked the Save button on the 'Associate With Roles' form |
---|
| 394 | permissions = {} |
---|
| 395 | for k, v in trans.app.model.Library.permitted_actions.items(): |
---|
| 396 | if k != 'LIBRARY_ACCESS': |
---|
| 397 | # LIBRARY_ACCESS is a special permission set only at the library level |
---|
| 398 | # and it is not inherited. |
---|
| 399 | in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( int( x ) ) for x in util.listify( params.get( k + '_in', [] ) ) ] |
---|
| 400 | permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles |
---|
| 401 | trans.app.security_agent.set_all_library_permissions( folder, permissions ) |
---|
| 402 | trans.sa_session.refresh( folder ) |
---|
| 403 | message = "Permissions updated for folder '%s'." % folder.name |
---|
| 404 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 405 | action='folder_permissions', |
---|
| 406 | cntrller=cntrller, |
---|
| 407 | use_panels=use_panels, |
---|
| 408 | id=trans.security.encode_id( folder.id ), |
---|
| 409 | library_id=library_id, |
---|
| 410 | show_deleted=show_deleted, |
---|
| 411 | message=util.sanitize_text( message ), |
---|
| 412 | status='done' ) ) |
---|
| 413 | # If the library is public all roles are legitimate, but if the library |
---|
| 414 | # is restricted, only those roles associated with the LIBRARY_ACCESS |
---|
| 415 | # permission are legitimate. |
---|
| 416 | roles = trans.app.security_agent.get_legitimate_roles( trans, folder.parent_library, cntrller ) |
---|
| 417 | return trans.fill_template( '/library/common/folder_permissions.mako', |
---|
| 418 | cntrller=cntrller, |
---|
| 419 | use_panels=use_panels, |
---|
| 420 | folder=folder, |
---|
| 421 | library_id=library_id, |
---|
| 422 | current_user_roles=current_user_roles, |
---|
| 423 | roles=roles, |
---|
| 424 | show_deleted=show_deleted, |
---|
| 425 | message=message, |
---|
| 426 | status=status ) |
---|
| 427 | @web.expose |
---|
| 428 | def ldda_edit_info( self, trans, cntrller, library_id, folder_id, id, **kwd ): |
---|
| 429 | params = util.Params( kwd ) |
---|
| 430 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 431 | status = params.get( 'status', 'done' ) |
---|
| 432 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 433 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 434 | is_admin = trans.user_is_admin() and cntrller == 'library_admin' |
---|
| 435 | current_user_roles = trans.get_current_user_roles() |
---|
| 436 | try: |
---|
| 437 | ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( id ) ) |
---|
| 438 | except: |
---|
| 439 | ldda = None |
---|
| 440 | self._check_access( trans, cntrller, is_admin, ldda, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 441 | self._check_modify( trans, cntrller, is_admin, ldda, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 442 | dbkey = params.get( 'dbkey', '?' ) |
---|
| 443 | if isinstance( dbkey, list ): |
---|
| 444 | dbkey = dbkey[0] |
---|
| 445 | file_formats = [ dtype_name for dtype_name, dtype_value in trans.app.datatypes_registry.datatypes_by_extension.iteritems() if dtype_value.allow_datatype_change ] |
---|
| 446 | file_formats.sort() |
---|
| 447 | # See if we have any associated templates |
---|
| 448 | widgets = [] |
---|
| 449 | info_association, inherited = ldda.get_info_association() |
---|
| 450 | if info_association and ( not( inherited ) or info_association.inheritable ): |
---|
| 451 | widgets = ldda.get_template_widgets( trans ) |
---|
| 452 | if params.get( 'change', False ): |
---|
| 453 | # The user clicked the Save button on the 'Change data type' form |
---|
| 454 | if ldda.datatype.allow_datatype_change and trans.app.datatypes_registry.get_datatype_by_extension( params.datatype ).allow_datatype_change: |
---|
| 455 | trans.app.datatypes_registry.change_datatype( ldda, params.datatype ) |
---|
| 456 | trans.sa_session.flush() |
---|
| 457 | message = "Data type changed for library dataset '%s'." % ldda.name |
---|
| 458 | status = 'done' |
---|
| 459 | else: |
---|
| 460 | message = "You are unable to change datatypes in this manner. Changing %s to %s is not allowed." % ( ldda.extension, params.datatype ) |
---|
| 461 | status = 'error' |
---|
| 462 | elif params.get( 'save', False ): |
---|
| 463 | # The user clicked the Save button on the 'Edit Attributes' form |
---|
| 464 | old_name = ldda.name |
---|
| 465 | new_name = util.restore_text( params.get( 'name', '' ) ) |
---|
| 466 | new_info = util.restore_text( params.get( 'info', '' ) ) |
---|
| 467 | new_message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 468 | if not new_name: |
---|
| 469 | message = 'Enter a valid name' |
---|
| 470 | status = 'error' |
---|
| 471 | else: |
---|
| 472 | ldda.name = new_name |
---|
| 473 | ldda.info = new_info |
---|
| 474 | ldda.message = new_message |
---|
| 475 | # The following for loop will save all metadata_spec items |
---|
| 476 | for name, spec in ldda.datatype.metadata_spec.items(): |
---|
| 477 | if spec.get("readonly"): |
---|
| 478 | continue |
---|
| 479 | optional = params.get( "is_" + name, None ) |
---|
| 480 | if optional and optional == 'true': |
---|
| 481 | # optional element... == 'true' actually means it is NOT checked (and therefore ommitted) |
---|
| 482 | setattr( ldda.metadata, name, None ) |
---|
| 483 | else: |
---|
| 484 | setattr( ldda.metadata, name, spec.unwrap( params.get ( name, None ) ) ) |
---|
| 485 | ldda.metadata.dbkey = dbkey |
---|
| 486 | ldda.datatype.after_setting_metadata( ldda ) |
---|
| 487 | trans.sa_session.flush() |
---|
| 488 | message = "Attributes updated for library dataset '%s'." % ldda.name |
---|
| 489 | status = 'done' |
---|
| 490 | elif params.get( 'detect', False ): |
---|
| 491 | # The user clicked the Auto-detect button on the 'Edit Attributes' form |
---|
| 492 | for name, spec in ldda.datatype.metadata_spec.items(): |
---|
| 493 | # We need to be careful about the attributes we are resetting |
---|
| 494 | if name not in [ 'name', 'info', 'dbkey' ]: |
---|
| 495 | if spec.get( 'default' ): |
---|
| 496 | setattr( ldda.metadata, name, spec.unwrap( spec.get( 'default' ) ) ) |
---|
| 497 | ldda.datatype.set_meta( ldda ) |
---|
| 498 | ldda.datatype.after_setting_metadata( ldda ) |
---|
| 499 | trans.sa_session.flush() |
---|
| 500 | message = "Information updated for library dataset '%s'." % ldda.name |
---|
| 501 | status = 'done' |
---|
| 502 | if "dbkey" in ldda.datatype.metadata_spec and not ldda.metadata.dbkey: |
---|
| 503 | # Copy dbkey into metadata, for backwards compatability |
---|
| 504 | # This looks like it does nothing, but getting the dbkey |
---|
| 505 | # returns the metadata dbkey unless it is None, in which |
---|
| 506 | # case it resorts to the old dbkey. Setting the dbkey |
---|
| 507 | # sets it properly in the metadata |
---|
| 508 | ldda.metadata.dbkey = ldda.dbkey |
---|
| 509 | return trans.fill_template( "/library/common/ldda_edit_info.mako", |
---|
| 510 | cntrller=cntrller, |
---|
| 511 | use_panels=use_panels, |
---|
| 512 | ldda=ldda, |
---|
| 513 | library_id=library_id, |
---|
| 514 | file_formats=file_formats, |
---|
| 515 | widgets=widgets, |
---|
| 516 | current_user_roles=current_user_roles, |
---|
| 517 | show_deleted=show_deleted, |
---|
| 518 | info_association=info_association, |
---|
| 519 | inherited=inherited, |
---|
| 520 | message=message, |
---|
| 521 | status=status ) |
---|
| 522 | @web.expose |
---|
| 523 | def ldda_info( self, trans, cntrller, library_id, folder_id, id, **kwd ): |
---|
| 524 | params = util.Params( kwd ) |
---|
| 525 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 526 | status = params.get( 'status', 'done' ) |
---|
| 527 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 528 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 529 | is_admin = trans.user_is_admin() and cntrller == 'library_admin' |
---|
| 530 | current_user_roles = trans.get_current_user_roles() |
---|
| 531 | try: |
---|
| 532 | ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( id ) ) |
---|
| 533 | except: |
---|
| 534 | ldda = None |
---|
| 535 | self._check_access( trans, cntrller, is_admin, ldda, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 536 | if is_admin: |
---|
| 537 | # Get all associated hdas and lddas that use the same disk file. |
---|
| 538 | associated_hdas = trans.sa_session.query( trans.model.HistoryDatasetAssociation ) \ |
---|
| 539 | .filter( and_( trans.model.HistoryDatasetAssociation.deleted == False, |
---|
| 540 | trans.model.HistoryDatasetAssociation.dataset_id == ldda.dataset_id ) ) \ |
---|
| 541 | .all() |
---|
| 542 | associated_lddas = trans.sa_session.query( trans.model.LibraryDatasetDatasetAssociation ) \ |
---|
| 543 | .filter( and_( trans.model.LibraryDatasetDatasetAssociation.deleted == False, |
---|
| 544 | trans.model.LibraryDatasetDatasetAssociation.dataset_id == ldda.dataset_id, |
---|
| 545 | trans.model.LibraryDatasetDatasetAssociation.id != ldda.id ) ) \ |
---|
| 546 | .all() |
---|
| 547 | else: |
---|
| 548 | associated_hdas = [] |
---|
| 549 | associated_lddas = [] |
---|
| 550 | # See if we have any associated templates |
---|
| 551 | widgets = [] |
---|
| 552 | widget_fields_have_contents = False |
---|
| 553 | info_association, inherited = ldda.get_info_association() |
---|
| 554 | if info_association and ( not( inherited ) or info_association.inheritable ): |
---|
| 555 | widgets = ldda.get_template_widgets( trans ) |
---|
| 556 | widget_fields_have_contents = self.widget_fields_have_contents( widgets ) |
---|
| 557 | return trans.fill_template( '/library/common/ldda_info.mako', |
---|
| 558 | cntrller=cntrller, |
---|
| 559 | use_panels=use_panels, |
---|
| 560 | ldda=ldda, |
---|
| 561 | library=ldda.library_dataset.folder.parent_library, |
---|
| 562 | associated_hdas=associated_hdas, |
---|
| 563 | associated_lddas=associated_lddas, |
---|
| 564 | show_deleted=show_deleted, |
---|
| 565 | widgets=widgets, |
---|
| 566 | widget_fields_have_contents=widget_fields_have_contents, |
---|
| 567 | current_user_roles=current_user_roles, |
---|
| 568 | info_association=info_association, |
---|
| 569 | inherited=inherited, |
---|
| 570 | message=message, |
---|
| 571 | status=status ) |
---|
| 572 | @web.expose |
---|
| 573 | def ldda_permissions( self, trans, cntrller, library_id, folder_id, id, **kwd ): |
---|
| 574 | params = util.Params( kwd ) |
---|
| 575 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 576 | status = params.get( 'status', 'done' ) |
---|
| 577 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 578 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 579 | ids = util.listify( id ) |
---|
| 580 | lddas = [] |
---|
| 581 | libraries = [] |
---|
| 582 | is_admin = trans.user_is_admin() and cntrller == 'library_admin' |
---|
| 583 | current_user_roles = trans.get_current_user_roles() |
---|
| 584 | for id in ids: |
---|
| 585 | try: |
---|
| 586 | ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( id ) ) |
---|
| 587 | except: |
---|
| 588 | ldda = None |
---|
| 589 | if ldda: |
---|
| 590 | library = ldda.library_dataset.folder.parent_library |
---|
| 591 | self._check_access( trans, cntrller, is_admin, ldda, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 592 | lddas.append( ldda ) |
---|
| 593 | libraries.append( library ) |
---|
| 594 | library = libraries[0] |
---|
| 595 | if filter( lambda x: x != library, libraries ): |
---|
| 596 | message = "Library datasets specified span multiple libraries." |
---|
| 597 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 598 | action='browse_library', |
---|
| 599 | id=library_id, |
---|
| 600 | cntrller=cntrller, |
---|
| 601 | use_panels=use_panels, |
---|
| 602 | message=util.sanitize_text( message ), |
---|
| 603 | status='error' ) ) |
---|
| 604 | # If access to the dataset is restricted, then use the roles associated with the DATASET_ACCESS permission to |
---|
| 605 | # determine the legitimate roles. If the dataset is public, see if access to the library is restricted. If |
---|
| 606 | # it is, use the roles associated with the LIBRARY_ACCESS permission to determine the legitimate roles. If both |
---|
| 607 | # the dataset and the library are public, all roles are legitimate. All of the datasets will have the same |
---|
| 608 | # permissions at this point. |
---|
| 609 | ldda = lddas[0] |
---|
| 610 | if trans.app.security_agent.dataset_is_public( ldda.dataset ): |
---|
| 611 | # The dataset is public, so check access to the library |
---|
| 612 | roles = trans.app.security_agent.get_legitimate_roles( trans, library, cntrller ) |
---|
| 613 | else: |
---|
| 614 | roles = trans.app.security_agent.get_legitimate_roles( trans, ldda.dataset, cntrller ) |
---|
| 615 | if params.get( 'update_roles_button', False ): |
---|
| 616 | a = trans.app.security_agent.get_action( trans.app.security_agent.permitted_actions.DATASET_ACCESS.action ) |
---|
| 617 | permissions, in_roles, error, message = \ |
---|
| 618 | trans.app.security_agent.derive_roles_from_access( trans, trans.app.security.decode_id( library_id ), cntrller, library=True, **kwd ) |
---|
| 619 | for ldda in lddas: |
---|
| 620 | # Set the DATASET permissions on the Dataset. |
---|
| 621 | if error: |
---|
| 622 | # Keep the original role associations for the DATASET_ACCESS permission on the ldda. |
---|
| 623 | permissions[ a ] = ldda.get_access_roles( trans ) |
---|
| 624 | trans.app.security_agent.set_all_dataset_permissions( ldda.dataset, permissions ) |
---|
| 625 | trans.sa_session.refresh( ldda.dataset ) |
---|
| 626 | # Set the LIBRARY permissions on the LibraryDataset. The LibraryDataset and |
---|
| 627 | # LibraryDatasetDatasetAssociation will be set with the same permissions. |
---|
| 628 | permissions = {} |
---|
| 629 | for k, v in trans.app.model.Library.permitted_actions.items(): |
---|
| 630 | if k != 'LIBRARY_ACCESS': |
---|
| 631 | # LIBRARY_ACCESS is a special permission set only at the library level and it is not inherited. |
---|
| 632 | in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( x ) for x in util.listify( kwd.get( k + '_in', [] ) ) ] |
---|
| 633 | permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles |
---|
| 634 | for ldda in lddas: |
---|
| 635 | trans.app.security_agent.set_all_library_permissions( ldda.library_dataset, permissions ) |
---|
| 636 | trans.sa_session.refresh( ldda.library_dataset ) |
---|
| 637 | # Set the LIBRARY permissions on the LibraryDatasetDatasetAssociation |
---|
| 638 | trans.app.security_agent.set_all_library_permissions( ldda, permissions ) |
---|
| 639 | trans.sa_session.refresh( ldda ) |
---|
| 640 | if error: |
---|
| 641 | status = 'error' |
---|
| 642 | else: |
---|
| 643 | if len( lddas ) == 1: |
---|
| 644 | message = "Permissions updated for dataset '%s'." % ldda.name |
---|
| 645 | else: |
---|
| 646 | message = 'Permissions updated for %d datasets.' % len( lddas ) |
---|
| 647 | status= 'done' |
---|
| 648 | return trans.fill_template( "/library/common/ldda_permissions.mako", |
---|
| 649 | cntrller=cntrller, |
---|
| 650 | use_panels=use_panels, |
---|
| 651 | lddas=lddas, |
---|
| 652 | library_id=library_id, |
---|
| 653 | roles=roles, |
---|
| 654 | show_deleted=show_deleted, |
---|
| 655 | message=message, |
---|
| 656 | status=status ) |
---|
| 657 | if len( ids ) > 1: |
---|
| 658 | # Ensure that the permissions across all library items are identical, otherwise we can't update them together. |
---|
| 659 | check_list = [] |
---|
| 660 | for ldda in lddas: |
---|
| 661 | permissions = [] |
---|
| 662 | # Check the library level permissions - the permissions on the LibraryDatasetDatasetAssociation |
---|
| 663 | # will always be the same as the permissions on the associated LibraryDataset. |
---|
| 664 | for library_permission in trans.app.security_agent.get_permissions( ldda.library_dataset ): |
---|
| 665 | if library_permission.action not in permissions: |
---|
| 666 | permissions.append( library_permission.action ) |
---|
| 667 | for dataset_permission in trans.app.security_agent.get_permissions( ldda.dataset ): |
---|
| 668 | if dataset_permission.action not in permissions: |
---|
| 669 | permissions.append( dataset_permission.action ) |
---|
| 670 | permissions.sort() |
---|
| 671 | if not check_list: |
---|
| 672 | check_list = permissions |
---|
| 673 | if permissions != check_list: |
---|
| 674 | message = 'The datasets you selected do not have identical permissions, so they can not be updated together' |
---|
| 675 | trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 676 | action='browse_library', |
---|
| 677 | cntrller=cntrller, |
---|
| 678 | use_panels=use_panels, |
---|
| 679 | id=library_id, |
---|
| 680 | show_deleted=show_deleted, |
---|
| 681 | message=util.sanitize_text( message ), |
---|
| 682 | status='error' ) ) |
---|
| 683 | # Display permission form, permissions will be updated for all lddas simultaneously. |
---|
| 684 | return trans.fill_template( "/library/common/ldda_permissions.mako", |
---|
| 685 | cntrller=cntrller, |
---|
| 686 | use_panels=use_panels, |
---|
| 687 | lddas=lddas, |
---|
| 688 | library_id=library_id, |
---|
| 689 | roles=roles, |
---|
| 690 | show_deleted=show_deleted, |
---|
| 691 | message=message, |
---|
| 692 | status=status ) |
---|
| 693 | @web.expose |
---|
| 694 | def upload_library_dataset( self, trans, cntrller, library_id, folder_id, **kwd ): |
---|
| 695 | params = util.Params( kwd ) |
---|
| 696 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 697 | status = params.get( 'status', 'done' ) |
---|
| 698 | ldda_message = util.restore_text( params.get( 'ldda_message', '' ) ) |
---|
| 699 | deleted = util.string_as_bool( params.get( 'deleted', False ) ) |
---|
| 700 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 701 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 702 | replace_id = params.get( 'replace_id', None ) |
---|
| 703 | replace_dataset = None |
---|
| 704 | upload_option = params.get( 'upload_option', 'upload_file' ) |
---|
| 705 | if params.get( 'files_0|space_to_tab', False ): |
---|
| 706 | space_to_tab = params.get( 'files_0|space_to_tab', '' ) |
---|
| 707 | else: |
---|
| 708 | space_to_tab = params.get( 'space_to_tab', '' ) |
---|
| 709 | link_data_only = params.get( 'link_data_only', '' ) |
---|
| 710 | dbkey = params.get( 'dbkey', '?' ) |
---|
| 711 | if isinstance( dbkey, list ): |
---|
| 712 | last_used_build = dbkey[0] |
---|
| 713 | else: |
---|
| 714 | last_used_build = dbkey |
---|
| 715 | roles = params.get( 'roles', '' ) |
---|
| 716 | is_admin = trans.user_is_admin() and cntrller in ( 'library_admin', 'api' ) |
---|
| 717 | current_user_roles = trans.get_current_user_roles() |
---|
| 718 | if replace_id not in [ None, 'None' ]: |
---|
| 719 | try: |
---|
| 720 | replace_dataset = trans.sa_session.query( trans.app.model.LibraryDataset ).get( trans.security.decode_id( replace_id ) ) |
---|
| 721 | except: |
---|
| 722 | replace_dataset = None |
---|
| 723 | self._check_access( trans, cntrller, is_admin, replace_dataset, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 724 | self._check_modify( trans, cntrller, is_admin, replace_dataset, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 725 | library = replace_dataset.folder.parent_library |
---|
| 726 | folder = replace_dataset.folder |
---|
| 727 | # The name is stored - by the time the new ldda is created, replace_dataset.name |
---|
| 728 | # will point to the new ldda, not the one it's replacing. |
---|
| 729 | replace_dataset_name = replace_dataset.name |
---|
| 730 | if not last_used_build: |
---|
| 731 | last_used_build = replace_dataset.library_dataset_dataset_association.dbkey |
---|
| 732 | # Don't allow multiple datasets to be uploaded when replacing a dataset with a new version |
---|
| 733 | upload_option = 'upload_file' |
---|
| 734 | else: |
---|
| 735 | folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( trans.security.decode_id( folder_id ) ) |
---|
| 736 | self._check_access( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 737 | self._check_add( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 738 | library = folder.parent_library |
---|
| 739 | if folder and last_used_build in [ 'None', None, '?' ]: |
---|
| 740 | last_used_build = folder.genome_build |
---|
| 741 | if params.get( 'runtool_btn', False ) or params.get( 'ajax_upload', False ) or cntrller == 'api': |
---|
| 742 | error = False |
---|
| 743 | if upload_option == 'upload_paths' and not trans.app.config.allow_library_path_paste: |
---|
| 744 | error = True |
---|
| 745 | message = '"allow_library_path_paste" is not defined in the Galaxy configuration file' |
---|
| 746 | elif roles: |
---|
| 747 | # Check to see if the user selected roles to associate with the DATASET_ACCESS permission |
---|
| 748 | # on the dataset that would cause accessibility issues. |
---|
| 749 | vars = dict( DATASET_ACCESS_in=roles ) |
---|
| 750 | permissions, in_roles, error, message = \ |
---|
| 751 | trans.app.security_agent.derive_roles_from_access( trans, library.id, cntrller, library=True, **vars ) |
---|
| 752 | if error: |
---|
| 753 | if cntrller == 'api': |
---|
| 754 | return 400, message |
---|
| 755 | trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 756 | action='upload_library_dataset', |
---|
| 757 | cntrller=cntrller, |
---|
| 758 | library_id=library_id, |
---|
| 759 | folder_id=folder_id, |
---|
| 760 | replace_id=replace_id, |
---|
| 761 | upload_option=upload_option, |
---|
| 762 | show_deleted=show_deleted, |
---|
| 763 | message=util.sanitize_text( message ), |
---|
| 764 | status='error' ) ) |
---|
| 765 | |
---|
| 766 | else: |
---|
| 767 | # See if we have any inherited templates. |
---|
| 768 | info_association, inherited = folder.get_info_association( inherited=True ) |
---|
| 769 | if info_association and info_association.inheritable: |
---|
| 770 | template_id = str( info_association.template.id ) |
---|
| 771 | widgets = folder.get_template_widgets( trans, get_contents=True ) |
---|
| 772 | processed_widgets = [] |
---|
| 773 | # The list of widgets may include an AddressField which we need to save if it is new |
---|
| 774 | for index, widget_dict in enumerate( widgets ): |
---|
| 775 | widget = widget_dict[ 'widget' ] |
---|
| 776 | if isinstance( widget, AddressField ): |
---|
| 777 | value = util.restore_text( params.get( 'field_%i' % index, '' ) ) |
---|
| 778 | if value == 'new': |
---|
| 779 | if self.field_param_values_ok( index, 'AddressField', **kwd ): |
---|
| 780 | # Save the new address |
---|
| 781 | address = trans.app.model.UserAddress( user=trans.user ) |
---|
| 782 | self.save_widget_field( trans, address, index, **kwd ) |
---|
| 783 | widget.value = str( address.id ) |
---|
| 784 | widget_dict[ 'widget' ] = widget |
---|
| 785 | processed_widgets.append( widget_dict ) |
---|
| 786 | # It is now critical to update the value of 'field_%i', replacing the string |
---|
| 787 | # 'new' with the new address id. This is necessary because the upload_dataset() |
---|
| 788 | # method below calls the handle_library_params() method, which does not parse the |
---|
| 789 | # widget fields, it instead pulls form values from kwd. See the FIXME comments in the |
---|
| 790 | # handle_library_params() method, and the CheckboxField code in the next conditional. |
---|
| 791 | kwd[ 'field_%i' % index ] = str( address.id ) |
---|
| 792 | else: |
---|
| 793 | # The invalid address won't be saved, but we cannot display error |
---|
| 794 | # messages on the upload form due to the ajax upload already occurring. |
---|
| 795 | # When we re-engineer the upload process ( currently under way ), we |
---|
| 796 | # will be able to check the form values before the ajax upload occurs |
---|
| 797 | # in the background. For now, we'll do nothing... |
---|
| 798 | pass |
---|
| 799 | elif isinstance( widget, CheckboxField ): |
---|
| 800 | # We need to check the value from kwd since util.Params would have munged the list if |
---|
| 801 | # the checkbox is checked. |
---|
| 802 | value = kwd.get( 'field_%i' % index, '' ) |
---|
| 803 | if CheckboxField.is_checked( value ): |
---|
| 804 | widget.value = 'true' |
---|
| 805 | widget_dict[ 'widget' ] = widget |
---|
| 806 | processed_widgets.append( widget_dict ) |
---|
| 807 | kwd[ 'field_%i' % index ] = 'true' |
---|
| 808 | else: |
---|
| 809 | processed_widgets.append( widget_dict ) |
---|
| 810 | widgets = processed_widgets |
---|
| 811 | else: |
---|
| 812 | template_id = 'None' |
---|
| 813 | widgets = [] |
---|
| 814 | created_outputs_dict = trans.webapp.controllers[ 'library_common' ].upload_dataset( trans, |
---|
| 815 | cntrller=cntrller, |
---|
| 816 | library_id=trans.security.encode_id( library.id ), |
---|
| 817 | folder_id=trans.security.encode_id( folder.id ), |
---|
| 818 | template_id=template_id, |
---|
| 819 | widgets=widgets, |
---|
| 820 | replace_dataset=replace_dataset, |
---|
| 821 | **kwd ) |
---|
| 822 | if created_outputs_dict: |
---|
| 823 | if cntrller == 'api': |
---|
| 824 | # created_outputs_dict can only ever be a string if cntrller == 'api' |
---|
| 825 | if type( created_outputs_dict ) == str: |
---|
| 826 | return 400, created_outputs_dict |
---|
| 827 | return 200, created_outputs_dict |
---|
| 828 | total_added = len( created_outputs_dict.keys() ) |
---|
| 829 | ldda_id_list = [ str( v.id ) for k, v in created_outputs_dict.items() ] |
---|
| 830 | created_ldda_ids=",".join( ldda_id_list ) |
---|
| 831 | if replace_dataset: |
---|
| 832 | message = "Added %d dataset versions to the library dataset '%s' in the folder '%s'." % ( total_added, replace_dataset_name, folder.name ) |
---|
| 833 | else: |
---|
| 834 | if not folder.parent: |
---|
| 835 | # Libraries have the same name as their root_folder |
---|
| 836 | message = "Added %d datasets to the library '%s' (each is selected). " % ( total_added, folder.name ) |
---|
| 837 | else: |
---|
| 838 | message = "Added %d datasets to the folder '%s' (each is selected). " % ( total_added, folder.name ) |
---|
| 839 | if cntrller == 'library_admin': |
---|
| 840 | message += "Click the Go button at the bottom of this page to edit the permissions on these datasets if necessary." |
---|
| 841 | status='done' |
---|
| 842 | else: |
---|
| 843 | # Since permissions on all LibraryDatasetDatasetAssociations must be the same at this point, we only need |
---|
| 844 | # to check one of them to see if the current user can manage permissions on them. |
---|
| 845 | check_ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( ldda_id_list[0] ) |
---|
| 846 | if trans.app.security_agent.can_manage_library_item( current_user_roles, check_ldda ): |
---|
| 847 | if replace_dataset: |
---|
| 848 | default_action = '' |
---|
| 849 | else: |
---|
| 850 | message += "Click the Go button at the bottom of this page to edit the permissions on these datasets if necessary." |
---|
| 851 | default_action = 'manage_permissions' |
---|
| 852 | else: |
---|
| 853 | default_action = 'add' |
---|
| 854 | trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 855 | action='browse_library', |
---|
| 856 | cntrller=cntrller, |
---|
| 857 | id=library_id, |
---|
| 858 | default_action=default_action, |
---|
| 859 | created_ldda_ids=created_ldda_ids, |
---|
| 860 | show_deleted=show_deleted, |
---|
| 861 | message=util.sanitize_text( message ), |
---|
| 862 | status='done' ) ) |
---|
| 863 | else: |
---|
| 864 | created_ldda_ids = '' |
---|
| 865 | message = "Upload failed" |
---|
| 866 | status='error' |
---|
| 867 | if cntrller == 'api': |
---|
| 868 | return 400, message |
---|
| 869 | response_code = 400 |
---|
| 870 | trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 871 | action='browse_library', |
---|
| 872 | cntrller=cntrller, |
---|
| 873 | id=library_id, |
---|
| 874 | created_ldda_ids=created_ldda_ids, |
---|
| 875 | show_deleted=show_deleted, |
---|
| 876 | message=util.sanitize_text( message ), |
---|
| 877 | status=status ) ) |
---|
| 878 | # Note: if the upload form was submitted due to refresh_on_change for a form field, we cannot re-populate |
---|
| 879 | # the field for the selected file ( files_0|file_data ) if the user selected one. This is because the value |
---|
| 880 | # attribute of the html input file type field is typically ignored by browsers as a security precaution. |
---|
| 881 | |
---|
| 882 | # See if we have any inherited templates. |
---|
| 883 | info_association, inherited = folder.get_info_association( inherited=True ) |
---|
| 884 | if info_association and info_association.inheritable: |
---|
| 885 | widgets = folder.get_template_widgets( trans, get_contents=True ) |
---|
| 886 | # Retain contents of widget fields when form was submitted via refresh_on_change. |
---|
| 887 | widgets = self.populate_widgets_from_kwd( trans, widgets, **kwd ) |
---|
| 888 | else: |
---|
| 889 | widgets = [] |
---|
| 890 | # Send list of data formats to the upload form so the "extension" select list can be populated dynamically |
---|
| 891 | file_formats = trans.app.datatypes_registry.upload_file_formats |
---|
| 892 | # Send list of genome builds to the form so the "dbkey" select list can be populated dynamically |
---|
| 893 | def get_dbkey_options( last_used_build ): |
---|
| 894 | for dbkey, build_name in util.dbnames: |
---|
| 895 | yield build_name, dbkey, ( dbkey==last_used_build ) |
---|
| 896 | dbkeys = get_dbkey_options( last_used_build ) |
---|
| 897 | # Send the current history to the form to enable importing datasets from history to library |
---|
| 898 | history = trans.get_history() |
---|
| 899 | trans.sa_session.refresh( history ) |
---|
| 900 | if upload_option == 'upload_file' and trans.app.config.nginx_upload_path: |
---|
| 901 | # If we're using nginx upload, override the form action - |
---|
| 902 | # url_for is intentionally not used on the base URL here - |
---|
| 903 | # nginx_upload_path is expected to include the proxy prefix if the |
---|
| 904 | # administrator intends for it to be part of the URL. |
---|
| 905 | action = trans.app.config.nginx_upload_path + '?nginx_redir=' + web.url_for( controller='library_common', action='upload_library_dataset' ) |
---|
| 906 | else: |
---|
| 907 | action = web.url_for( controller='library_common', action='upload_library_dataset' ) |
---|
| 908 | upload_option_select_list = self._build_upload_option_select_list( trans, upload_option ) |
---|
| 909 | roles_select_list = self._build_roles_select_list( trans, cntrller, library, util.listify( roles ) ) |
---|
| 910 | return trans.fill_template( '/library/common/upload.mako', |
---|
| 911 | cntrller=cntrller, |
---|
| 912 | upload_option_select_list=upload_option_select_list, |
---|
| 913 | upload_option=upload_option, |
---|
| 914 | action=action, |
---|
| 915 | library_id=library_id, |
---|
| 916 | folder_id=folder_id, |
---|
| 917 | replace_dataset=replace_dataset, |
---|
| 918 | file_formats=file_formats, |
---|
| 919 | dbkeys=dbkeys, |
---|
| 920 | last_used_build=last_used_build, |
---|
| 921 | roles_select_list=roles_select_list, |
---|
| 922 | history=history, |
---|
| 923 | widgets=widgets, |
---|
| 924 | space_to_tab=space_to_tab, |
---|
| 925 | link_data_only=link_data_only, |
---|
| 926 | show_deleted=show_deleted, |
---|
| 927 | ldda_message=ldda_message, |
---|
| 928 | message=message, |
---|
| 929 | status=status ) |
---|
| 930 | def upload_dataset( self, trans, cntrller, library_id, folder_id, replace_dataset=None, **kwd ): |
---|
| 931 | # Set up the traditional tool state/params |
---|
| 932 | tool_id = 'upload1' |
---|
| 933 | tool = trans.app.toolbox.tools_by_id[ tool_id ] |
---|
| 934 | state = tool.new_state( trans ) |
---|
| 935 | errors = tool.update_state( trans, tool.inputs_by_page[0], state.inputs, kwd ) |
---|
| 936 | tool_params = state.inputs |
---|
| 937 | dataset_upload_inputs = [] |
---|
| 938 | for input_name, input in tool.inputs.iteritems(): |
---|
| 939 | if input.type == "upload_dataset": |
---|
| 940 | dataset_upload_inputs.append( input ) |
---|
| 941 | # Library-specific params |
---|
| 942 | params = util.Params( kwd ) # is this filetoolparam safe? |
---|
| 943 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 944 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 945 | status = params.get( 'status', 'done' ) |
---|
| 946 | server_dir = util.restore_text( params.get( 'server_dir', '' ) ) |
---|
| 947 | if replace_dataset not in [ None, 'None' ]: |
---|
| 948 | replace_id = trans.security.encode_id( replace_dataset.id ) |
---|
| 949 | else: |
---|
| 950 | replace_id = None |
---|
| 951 | upload_option = params.get( 'upload_option', 'upload_file' ) |
---|
| 952 | response_code = 200 |
---|
| 953 | if upload_option == 'upload_directory': |
---|
| 954 | if server_dir in [ None, 'None', '' ]: |
---|
| 955 | response_code = 400 |
---|
| 956 | if cntrller == 'library_admin' or ( cntrller == 'api' and trans.user_is_admin ): |
---|
| 957 | import_dir = trans.app.config.library_import_dir |
---|
| 958 | import_dir_desc = 'library_import_dir' |
---|
| 959 | full_dir = os.path.join( import_dir, server_dir ) |
---|
| 960 | else: |
---|
| 961 | import_dir = trans.app.config.user_library_import_dir |
---|
| 962 | import_dir_desc = 'user_library_import_dir' |
---|
| 963 | if server_dir == trans.user.email: |
---|
| 964 | full_dir = os.path.join( import_dir, server_dir ) |
---|
| 965 | else: |
---|
| 966 | full_dir = os.path.join( import_dir, trans.user.email, server_dir ) |
---|
| 967 | if import_dir: |
---|
| 968 | message = 'Select a directory' |
---|
| 969 | else: |
---|
| 970 | response_code = 403 |
---|
| 971 | message = '"%s" is not defined in the Galaxy configuration file' % import_dir_desc |
---|
| 972 | elif upload_option == 'upload_paths': |
---|
| 973 | if not trans.app.config.allow_library_path_paste: |
---|
| 974 | response_code = 403 |
---|
| 975 | message = '"allow_library_path_paste" is not defined in the Galaxy configuration file' |
---|
| 976 | # Some error handling should be added to this method. |
---|
| 977 | try: |
---|
| 978 | # FIXME: instead of passing params here ( chiech have been process by util.Params(), the original kwd |
---|
| 979 | # should be passed so that complex objects that may have been included in the initial request remain. |
---|
| 980 | library_bunch = upload_common.handle_library_params( trans, params, folder_id, replace_dataset ) |
---|
| 981 | except: |
---|
| 982 | response_code = 500 |
---|
| 983 | message = "Unable to parse upload parameters, please report this error." |
---|
| 984 | # Proceed with (mostly) regular upload processing if we're still errorless |
---|
| 985 | if response_code == 200: |
---|
| 986 | precreated_datasets = upload_common.get_precreated_datasets( trans, tool_params, trans.app.model.LibraryDatasetDatasetAssociation, controller=cntrller ) |
---|
| 987 | if upload_option == 'upload_file': |
---|
| 988 | tool_params = upload_common.persist_uploads( tool_params ) |
---|
| 989 | uploaded_datasets = upload_common.get_uploaded_datasets( trans, cntrller, tool_params, precreated_datasets, dataset_upload_inputs, library_bunch=library_bunch ) |
---|
| 990 | elif upload_option == 'upload_directory': |
---|
| 991 | uploaded_datasets, response_code, message = self.get_server_dir_uploaded_datasets( trans, cntrller, params, full_dir, import_dir_desc, library_bunch, response_code, message ) |
---|
| 992 | elif upload_option == 'upload_paths': |
---|
| 993 | uploaded_datasets, response_code, message = self.get_path_paste_uploaded_datasets( trans, cntrller, params, library_bunch, response_code, message ) |
---|
| 994 | upload_common.cleanup_unused_precreated_datasets( precreated_datasets ) |
---|
| 995 | if upload_option == 'upload_file' and not uploaded_datasets: |
---|
| 996 | response_code = 400 |
---|
| 997 | message = 'Select a file, enter a URL or enter text' |
---|
| 998 | if response_code != 200: |
---|
| 999 | if cntrller == 'api': |
---|
| 1000 | return ( response_code, message ) |
---|
| 1001 | trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1002 | action='upload_library_dataset', |
---|
| 1003 | cntrller=cntrller, |
---|
| 1004 | library_id=library_id, |
---|
| 1005 | folder_id=folder_id, |
---|
| 1006 | replace_id=replace_id, |
---|
| 1007 | upload_option=upload_option, |
---|
| 1008 | show_deleted=show_deleted, |
---|
| 1009 | message=util.sanitize_text( message ), |
---|
| 1010 | status='error' ) ) |
---|
| 1011 | json_file_path = upload_common.create_paramfile( trans, uploaded_datasets ) |
---|
| 1012 | data_list = [ ud.data for ud in uploaded_datasets ] |
---|
| 1013 | return upload_common.create_job( trans, tool_params, tool, json_file_path, data_list, folder=library_bunch.folder ) |
---|
| 1014 | def make_library_uploaded_dataset( self, trans, cntrller, params, name, path, type, library_bunch, in_folder=None ): |
---|
| 1015 | library_bunch.replace_dataset = None # not valid for these types of upload |
---|
| 1016 | uploaded_dataset = util.bunch.Bunch() |
---|
| 1017 | # Remove compressed file extensions, if any |
---|
| 1018 | new_name = name |
---|
| 1019 | if new_name.endswith( '.gz' ): |
---|
| 1020 | new_name = new_name.rstrip( '.gz' ) |
---|
| 1021 | elif new_name.endswith( '.zip' ): |
---|
| 1022 | new_name = new_name.rstrip( '.zip' ) |
---|
| 1023 | uploaded_dataset.name = new_name |
---|
| 1024 | uploaded_dataset.path = path |
---|
| 1025 | uploaded_dataset.type = type |
---|
| 1026 | uploaded_dataset.ext = None |
---|
| 1027 | uploaded_dataset.file_type = params.file_type |
---|
| 1028 | uploaded_dataset.dbkey = params.dbkey |
---|
| 1029 | uploaded_dataset.space_to_tab = params.space_to_tab |
---|
| 1030 | if in_folder: |
---|
| 1031 | uploaded_dataset.in_folder = in_folder |
---|
| 1032 | uploaded_dataset.data = upload_common.new_upload( trans, cntrller, uploaded_dataset, library_bunch ) |
---|
| 1033 | if params.get( 'link_data_only', False ): |
---|
| 1034 | uploaded_dataset.link_data_only = True |
---|
| 1035 | uploaded_dataset.data.file_name = os.path.abspath( path ) |
---|
| 1036 | # Since we are not copying the file into Galaxy's managed |
---|
| 1037 | # default file location, the dataset should never be purgable. |
---|
| 1038 | uploaded_dataset.data.dataset.purgable = False |
---|
| 1039 | trans.sa_session.add_all( ( uploaded_dataset.data, uploaded_dataset.data.dataset ) ) |
---|
| 1040 | trans.sa_session.flush() |
---|
| 1041 | return uploaded_dataset |
---|
| 1042 | def get_server_dir_uploaded_datasets( self, trans, cntrller, params, full_dir, import_dir_desc, library_bunch, response_code, message ): |
---|
| 1043 | files = [] |
---|
| 1044 | try: |
---|
| 1045 | for entry in os.listdir( full_dir ): |
---|
| 1046 | # Only import regular files |
---|
| 1047 | path = os.path.join( full_dir, entry ) |
---|
| 1048 | if os.path.islink( full_dir ) and params.get( 'link_data_only', False ): |
---|
| 1049 | # If we're linking instead of copying and the |
---|
| 1050 | # sub-"directory" in the import dir is actually a symlink, |
---|
| 1051 | # dereference the symlink, but not any of its contents. |
---|
| 1052 | link_path = os.readlink( full_dir ) |
---|
| 1053 | if os.path.isabs( link_path ): |
---|
| 1054 | path = os.path.join( link_path, entry ) |
---|
| 1055 | else: |
---|
| 1056 | path = os.path.abspath( os.path.join( link_path, entry ) ) |
---|
| 1057 | elif os.path.islink( path ) and os.path.isfile( path ) and params.get( 'link_data_only', False ): |
---|
| 1058 | # If we're linking instead of copying and the "file" in the |
---|
| 1059 | # sub-directory of the import dir is actually a symlink, |
---|
| 1060 | # dereference the symlink (one dereference only, Vasili). |
---|
| 1061 | link_path = os.readlink( path ) |
---|
| 1062 | if os.path.isabs( link_path ): |
---|
| 1063 | path = link_path |
---|
| 1064 | else: |
---|
| 1065 | path = os.path.abspath( os.path.join( os.path.dirname( path ), link_path ) ) |
---|
| 1066 | if os.path.isfile( path ): |
---|
| 1067 | files.append( path ) |
---|
| 1068 | except Exception, e: |
---|
| 1069 | message = "Unable to get file list for configured %s, error: %s" % ( import_dir_desc, str( e ) ) |
---|
| 1070 | response_code = 500 |
---|
| 1071 | return None, response_code, message |
---|
| 1072 | if not files: |
---|
| 1073 | message = "The directory '%s' contains no valid files" % full_dir |
---|
| 1074 | response_code = 400 |
---|
| 1075 | return None, response_code, message |
---|
| 1076 | uploaded_datasets = [] |
---|
| 1077 | for file in files: |
---|
| 1078 | name = os.path.basename( file ) |
---|
| 1079 | uploaded_datasets.append( self.make_library_uploaded_dataset( trans, cntrller, params, name, file, 'server_dir', library_bunch ) ) |
---|
| 1080 | return uploaded_datasets, 200, None |
---|
| 1081 | def get_path_paste_uploaded_datasets( self, trans, cntrller, params, library_bunch, response_code, message ): |
---|
| 1082 | if params.get( 'filesystem_paths', '' ) == '': |
---|
| 1083 | message = "No paths entered in the upload form" |
---|
| 1084 | response_code = 400 |
---|
| 1085 | return None, response_code, message |
---|
| 1086 | preserve_dirs = True |
---|
| 1087 | if params.get( 'dont_preserve_dirs', False ): |
---|
| 1088 | preserve_dirs = False |
---|
| 1089 | # locate files |
---|
| 1090 | bad_paths = [] |
---|
| 1091 | uploaded_datasets = [] |
---|
| 1092 | for line in [ l.strip() for l in params.filesystem_paths.splitlines() if l.strip() ]: |
---|
| 1093 | path = os.path.abspath( line ) |
---|
| 1094 | if not os.path.exists( path ): |
---|
| 1095 | bad_paths.append( path ) |
---|
| 1096 | continue |
---|
| 1097 | # don't bother processing if we're just going to return an error |
---|
| 1098 | if not bad_paths: |
---|
| 1099 | if os.path.isfile( path ): |
---|
| 1100 | name = os.path.basename( path ) |
---|
| 1101 | uploaded_datasets.append( self.make_library_uploaded_dataset( trans, cntrller, params, name, path, 'path_paste', library_bunch ) ) |
---|
| 1102 | for basedir, dirs, files in os.walk( line ): |
---|
| 1103 | for file in files: |
---|
| 1104 | file_path = os.path.abspath( os.path.join( basedir, file ) ) |
---|
| 1105 | if preserve_dirs: |
---|
| 1106 | in_folder = os.path.dirname( file_path.replace( path, '', 1 ).lstrip( '/' ) ) |
---|
| 1107 | else: |
---|
| 1108 | in_folder = None |
---|
| 1109 | uploaded_datasets.append( self.make_library_uploaded_dataset( trans, |
---|
| 1110 | cntrller, |
---|
| 1111 | params, |
---|
| 1112 | file, |
---|
| 1113 | file_path, |
---|
| 1114 | 'path_paste', |
---|
| 1115 | library_bunch, |
---|
| 1116 | in_folder ) ) |
---|
| 1117 | if bad_paths: |
---|
| 1118 | message = "Invalid paths:<br><ul><li>%s</li></ul>" % "</li><li>".join( bad_paths ) |
---|
| 1119 | response_code = 400 |
---|
| 1120 | return None, response_code, message |
---|
| 1121 | return uploaded_datasets, 200, None |
---|
| 1122 | @web.expose |
---|
| 1123 | def add_history_datasets_to_library( self, trans, cntrller, library_id, folder_id, hda_ids='', **kwd ): |
---|
| 1124 | params = util.Params( kwd ) |
---|
| 1125 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 1126 | status = params.get( 'status', 'done' ) |
---|
| 1127 | ldda_message = util.restore_text( params.get( 'ldda_message', '' ) ) |
---|
| 1128 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 1129 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 1130 | replace_id = params.get( 'replace_id', None ) |
---|
| 1131 | replace_dataset = None |
---|
| 1132 | upload_option = params.get( 'upload_option', 'import_from_history' ) |
---|
| 1133 | if params.get( 'files_0|space_to_tab', False ): |
---|
| 1134 | space_to_tab = params.get( 'files_0|space_to_tab', '' ) |
---|
| 1135 | else: |
---|
| 1136 | space_to_tab = params.get( 'space_to_tab', '' ) |
---|
| 1137 | link_data_only = params.get( 'link_data_only', '' ) |
---|
| 1138 | dbkey = params.get( 'dbkey', '?' ) |
---|
| 1139 | if isinstance( dbkey, list ): |
---|
| 1140 | last_used_build = dbkey[0] |
---|
| 1141 | else: |
---|
| 1142 | last_used_build = dbkey |
---|
| 1143 | roles = params.get( 'roles', '' ) |
---|
| 1144 | is_admin = trans.user_is_admin() and cntrller in ( 'library_admin', 'api' ) |
---|
| 1145 | current_user_roles = trans.get_current_user_roles() |
---|
| 1146 | if replace_id not in [ None, 'None' ]: |
---|
| 1147 | try: |
---|
| 1148 | replace_dataset = trans.sa_session.query( trans.app.model.LibraryDataset ).get( trans.security.decode_id( replace_id ) ) |
---|
| 1149 | except: |
---|
| 1150 | replace_dataset = None |
---|
| 1151 | self._check_access( trans, cntrller, is_admin, replace_dataset, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1152 | self._check_modify( trans, cntrller, is_admin, replace_dataset, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1153 | library = replace_dataset.folder.parent_library |
---|
| 1154 | folder = replace_dataset.folder |
---|
| 1155 | last_used_build = replace_dataset.library_dataset_dataset_association.dbkey |
---|
| 1156 | else: |
---|
| 1157 | folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( trans.security.decode_id( folder_id ) ) |
---|
| 1158 | self._check_access( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1159 | self._check_add( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1160 | library = folder.parent_library |
---|
| 1161 | last_used_build = folder.genome_build |
---|
| 1162 | # See if the current history is empty |
---|
| 1163 | history = trans.get_history() |
---|
| 1164 | trans.sa_session.refresh( history ) |
---|
| 1165 | if not history.active_datasets: |
---|
| 1166 | message = 'Your current history is empty' |
---|
| 1167 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1168 | action='browse_library', |
---|
| 1169 | cntrller=cntrller, |
---|
| 1170 | id=library_id, |
---|
| 1171 | show_deleted=show_deleted, |
---|
| 1172 | message=util.sanitize_text( message ), |
---|
| 1173 | status='error' ) ) |
---|
| 1174 | if params.get( 'add_history_datasets_to_library_button', False ): |
---|
| 1175 | hda_ids = util.listify( hda_ids ) |
---|
| 1176 | if hda_ids: |
---|
| 1177 | dataset_names = [] |
---|
| 1178 | created_ldda_ids = '' |
---|
| 1179 | for hda_id in hda_ids: |
---|
| 1180 | try: |
---|
| 1181 | hda = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( trans.security.decode_id( hda_id ) ) |
---|
| 1182 | except: |
---|
| 1183 | hda = None |
---|
| 1184 | self._check_access( trans, cntrller, is_admin, hda, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1185 | if roles: |
---|
| 1186 | role_ids = roles.split( ',' ) |
---|
| 1187 | role_obj_list = [ trans.sa_session.query( trans.model.Role ).get( role_id ) for role_id in role_ids ] |
---|
| 1188 | else: |
---|
| 1189 | role_obj_list = [] |
---|
| 1190 | ldda = hda.to_library_dataset_dataset_association( trans, |
---|
| 1191 | target_folder=folder, |
---|
| 1192 | replace_dataset=replace_dataset, |
---|
| 1193 | roles=role_obj_list, |
---|
| 1194 | ldda_message=ldda_message ) |
---|
| 1195 | created_ldda_ids = '%s,%s' % ( created_ldda_ids, str( ldda.id ) ) |
---|
| 1196 | dataset_names.append( ldda.name ) |
---|
| 1197 | if not replace_dataset: |
---|
| 1198 | # If replace_dataset is None, the Library level permissions will be taken from the folder and applied to the new |
---|
| 1199 | # LDDA and LibraryDataset. |
---|
| 1200 | trans.app.security_agent.copy_library_permissions( folder, ldda ) |
---|
| 1201 | trans.app.security_agent.copy_library_permissions( folder, ldda.library_dataset ) |
---|
| 1202 | # Permissions must be the same on the LibraryDatasetDatasetAssociation and the associated LibraryDataset |
---|
| 1203 | trans.app.security_agent.copy_library_permissions( ldda.library_dataset, ldda ) |
---|
| 1204 | if created_ldda_ids: |
---|
| 1205 | created_ldda_ids = created_ldda_ids.lstrip( ',' ) |
---|
| 1206 | ldda_id_list = created_ldda_ids.split( ',' ) |
---|
| 1207 | total_added = len( ldda_id_list ) |
---|
| 1208 | if replace_dataset: |
---|
| 1209 | message = "Added %d dataset versions to the library dataset '%s' in the folder '%s'." % ( total_added, replace_dataset.name, folder.name ) |
---|
| 1210 | else: |
---|
| 1211 | if not folder.parent: |
---|
| 1212 | # Libraries have the same name as their root_folder |
---|
| 1213 | message = "Added %d datasets to the library '%s' (each is selected). " % ( total_added, folder.name ) |
---|
| 1214 | else: |
---|
| 1215 | message = "Added %d datasets to the folder '%s' (each is selected). " % ( total_added, folder.name ) |
---|
| 1216 | if cntrller == 'library_admin': |
---|
| 1217 | message += "Click the Go button at the bottom of this page to edit the permissions on these datasets if necessary." |
---|
| 1218 | else: |
---|
| 1219 | # Since permissions on all LibraryDatasetDatasetAssociations must be the same at this point, we only need |
---|
| 1220 | # to check one of them to see if the current user can manage permissions on them. |
---|
| 1221 | check_ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( ldda_id_list[0] ) |
---|
| 1222 | if trans.app.security_agent.can_manage_library_item( current_user_roles, check_ldda ): |
---|
| 1223 | if replace_dataset: |
---|
| 1224 | default_action = '' |
---|
| 1225 | else: |
---|
| 1226 | message += "Click the Go button at the bottom of this page to edit the permissions on these datasets if necessary." |
---|
| 1227 | default_action = 'manage_permissions' |
---|
| 1228 | else: |
---|
| 1229 | default_action = 'add' |
---|
| 1230 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1231 | action='browse_library', |
---|
| 1232 | cntrller=cntrller, |
---|
| 1233 | id=library_id, |
---|
| 1234 | created_ldda_ids=created_ldda_ids, |
---|
| 1235 | show_deleted=show_deleted, |
---|
| 1236 | message=util.sanitize_text( message ), |
---|
| 1237 | status='done' ) ) |
---|
| 1238 | else: |
---|
| 1239 | message = 'Select at least one dataset from the list of active datasets in your current history' |
---|
| 1240 | status = 'error' |
---|
| 1241 | upload_option = params.get( 'upload_option', 'import_from_history' ) |
---|
| 1242 | widgets = self._get_populated_widgets( folder ) |
---|
| 1243 | # Send list of data formats to the upload form so the "extension" select list can be populated dynamically |
---|
| 1244 | file_formats = trans.app.datatypes_registry.upload_file_formats |
---|
| 1245 | # Send list of genome builds to the form so the "dbkey" select list can be populated dynamically |
---|
| 1246 | def get_dbkey_options( last_used_build ): |
---|
| 1247 | for dbkey, build_name in util.dbnames: |
---|
| 1248 | yield build_name, dbkey, ( dbkey==last_used_build ) |
---|
| 1249 | dbkeys = get_dbkey_options( last_used_build ) |
---|
| 1250 | # Send the current history to the form to enable importing datasets from history to library |
---|
| 1251 | history = trans.get_history() |
---|
| 1252 | trans.sa_session.refresh( history ) |
---|
| 1253 | action = 'add_history_datasets_to_library' |
---|
| 1254 | upload_option_select_list = self._build_upload_option_select_list( trans, upload_option ) |
---|
| 1255 | roles_select_list = self._build_roles_select_list( trans, cntrller, library, util.listify( roles ) ) |
---|
| 1256 | return trans.fill_template( "/library/common/upload.mako", |
---|
| 1257 | cntrller=cntrller, |
---|
| 1258 | upload_option_select_list=upload_option_select_list, |
---|
| 1259 | upload_option=upload_option, |
---|
| 1260 | action=action, |
---|
| 1261 | library_id=library_id, |
---|
| 1262 | folder_id=folder_id, |
---|
| 1263 | replace_dataset=replace_dataset, |
---|
| 1264 | file_formats=file_formats, |
---|
| 1265 | dbkeys=dbkeys, |
---|
| 1266 | last_used_build=last_used_build, |
---|
| 1267 | roles_select_list=roles_select_list, |
---|
| 1268 | history=history, |
---|
| 1269 | widgets=widgets, |
---|
| 1270 | space_to_tab=space_to_tab, |
---|
| 1271 | link_data_only=link_data_only, |
---|
| 1272 | show_deleted=show_deleted, |
---|
| 1273 | ldda_message=ldda_message, |
---|
| 1274 | message=message, |
---|
| 1275 | status=status ) |
---|
| 1276 | def _build_roles_select_list( self, trans, cntrller, library, selected_role_ids=[] ): |
---|
| 1277 | # Get the list of legitimate roles to display on the upload form. If the library is public, |
---|
| 1278 | # all active roles are legitimate. If the library is restricted by the LIBRARY_ACCESS permission, only |
---|
| 1279 | # the set of all roles associated with users that have that permission are legitimate. |
---|
| 1280 | legitimate_roles = trans.app.security_agent.get_legitimate_roles( trans, library, cntrller ) |
---|
| 1281 | if legitimate_roles: |
---|
| 1282 | # Build the roles multi-select list using the list of legitimate roles, making sure to select any that |
---|
| 1283 | # were selected before refresh_on_change, if one occurred. |
---|
| 1284 | roles_select_list = SelectField( "roles", multiple="true", size="5" ) |
---|
| 1285 | for role in legitimate_roles: |
---|
| 1286 | selected = str( role.id ) in selected_role_ids |
---|
| 1287 | roles_select_list.add_option( text=role.name, value=str( role.id ), selected=selected ) |
---|
| 1288 | return roles_select_list |
---|
| 1289 | else: |
---|
| 1290 | return None |
---|
| 1291 | def _build_upload_option_select_list( self, trans, upload_option ): |
---|
| 1292 | # Build the upload_option select list |
---|
| 1293 | upload_refresh_on_change_values = [ option_value for option_value, option_label in trans.model.LibraryDataset.upload_options ] |
---|
| 1294 | upload_option_select_list = SelectField( 'upload_option', |
---|
| 1295 | refresh_on_change=True, |
---|
| 1296 | refresh_on_change_values=upload_refresh_on_change_values ) |
---|
| 1297 | for option_value, option_label in trans.model.LibraryDataset.upload_options: |
---|
| 1298 | upload_option_select_list.add_option( option_label, option_value, selected=option_value==upload_option ) |
---|
| 1299 | return upload_option_select_list |
---|
| 1300 | def _get_populated_widgets( self, folder ): |
---|
| 1301 | # See if we have any inherited templates. |
---|
| 1302 | info_association, inherited = folder.get_info_association( inherited=True ) |
---|
| 1303 | if info_association and info_association.inheritable: |
---|
| 1304 | widgets = folder.get_template_widgets( trans, get_contents=True ) |
---|
| 1305 | # Retain contents of widget fields when form was submitted via refresh_on_change. |
---|
| 1306 | return self.populate_widgets_from_kwd( trans, widgets, **kwd ) |
---|
| 1307 | else: |
---|
| 1308 | return [] |
---|
| 1309 | @web.expose |
---|
| 1310 | def download_dataset_from_folder( self, trans, cntrller, id, library_id=None, **kwd ): |
---|
| 1311 | """Catches the dataset id and displays file contents as directed""" |
---|
| 1312 | show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) ) |
---|
| 1313 | params = util.Params( kwd ) |
---|
| 1314 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 1315 | is_admin = trans.user_is_admin() and cntrller == 'library_admin' |
---|
| 1316 | current_user_roles = trans.get_current_user_roles() |
---|
| 1317 | try: |
---|
| 1318 | ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( id ) ) |
---|
| 1319 | except: |
---|
| 1320 | ldda = None |
---|
| 1321 | self._check_access( trans, cntrller, is_admin, ldda, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1322 | composite_extensions = trans.app.datatypes_registry.get_composite_extensions( ) |
---|
| 1323 | ext = ldda.extension |
---|
| 1324 | if ext in composite_extensions: |
---|
| 1325 | # is composite - must return a zip of contents and the html file itself - ugh - should be reversible at upload! |
---|
| 1326 | # use act_on_multiple_datasets( self, trans, cntrller, library_id, ldda_ids='', **kwd ) since it does what we need |
---|
| 1327 | kwd['do_action'] = 'zip' |
---|
| 1328 | return self.act_on_multiple_datasets( trans, cntrller, library_id, ldda_ids=[id,], **kwd ) |
---|
| 1329 | else: |
---|
| 1330 | mime = trans.app.datatypes_registry.get_mimetype_by_extension( ldda.extension.lower() ) |
---|
| 1331 | trans.response.set_content_type( mime ) |
---|
| 1332 | fStat = os.stat( ldda.file_name ) |
---|
| 1333 | trans.response.headers[ 'Content-Length' ] = int( fStat.st_size ) |
---|
| 1334 | valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' |
---|
| 1335 | fname = ldda.name |
---|
| 1336 | fname = ''.join( c in valid_chars and c or '_' for c in fname )[ 0:150 ] |
---|
| 1337 | trans.response.headers[ "Content-Disposition" ] = "attachment; filename=%s" % fname |
---|
| 1338 | try: |
---|
| 1339 | return open( ldda.file_name ) |
---|
| 1340 | except: |
---|
| 1341 | message = 'This dataset contains no content' |
---|
| 1342 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1343 | action='browse_library', |
---|
| 1344 | cntrller=cntrller, |
---|
| 1345 | use_panels=use_panels, |
---|
| 1346 | id=library_id, |
---|
| 1347 | show_deleted=show_deleted, |
---|
| 1348 | message=util.sanitize_text( message ), |
---|
| 1349 | status='error' ) ) |
---|
| 1350 | @web.expose |
---|
| 1351 | def library_dataset_info( self, trans, cntrller, id, library_id, **kwd ): |
---|
| 1352 | params = util.Params( kwd ) |
---|
| 1353 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 1354 | status = params.get( 'status', 'done' ) |
---|
| 1355 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 1356 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 1357 | is_admin = trans.user_is_admin() and cntrller == 'library_admin' |
---|
| 1358 | current_user_roles = trans.get_current_user_roles() |
---|
| 1359 | try: |
---|
| 1360 | library_dataset = trans.sa_session.query( trans.app.model.LibraryDataset ).get( trans.security.decode_id( id ) ) |
---|
| 1361 | except: |
---|
| 1362 | library_dataset = None |
---|
| 1363 | self._check_access( trans, cntrller, is_admin, library_dataset, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1364 | if params.get( 'edit_attributes_button', False ): |
---|
| 1365 | self._check_modify( trans, cntrller, is_admin, library_dataset, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1366 | old_name = library_dataset.name |
---|
| 1367 | new_name = util.restore_text( params.get( 'name', '' ) ) |
---|
| 1368 | new_info = util.restore_text( params.get( 'info', '' ) ) |
---|
| 1369 | if not new_name: |
---|
| 1370 | message = 'Enter a valid name' |
---|
| 1371 | status = 'error' |
---|
| 1372 | else: |
---|
| 1373 | library_dataset.name = new_name |
---|
| 1374 | library_dataset.info = new_info |
---|
| 1375 | trans.sa_session.add( library_dataset ) |
---|
| 1376 | trans.sa_session.flush() |
---|
| 1377 | message = "Information updated for library dataset '%s'." % library_dataset.name |
---|
| 1378 | status = 'done' |
---|
| 1379 | # See if we have any associated templates |
---|
| 1380 | widgets = [] |
---|
| 1381 | widget_fields_have_contents = False |
---|
| 1382 | info_association, inherited = library_dataset.library_dataset_dataset_association.get_info_association() |
---|
| 1383 | if info_association and ( not( inherited ) or info_association.inheritable ): |
---|
| 1384 | widgets = library_dataset.library_dataset_dataset_association.get_template_widgets( trans ) |
---|
| 1385 | widget_fields_have_contents = self.widget_fields_have_contents( widgets ) |
---|
| 1386 | return trans.fill_template( '/library/common/library_dataset_info.mako', |
---|
| 1387 | cntrller=cntrller, |
---|
| 1388 | use_panels=use_panels, |
---|
| 1389 | library_dataset=library_dataset, |
---|
| 1390 | library_id=library_id, |
---|
| 1391 | current_user_roles=current_user_roles, |
---|
| 1392 | info_association=info_association, |
---|
| 1393 | inherited=inherited, |
---|
| 1394 | widgets=widgets, |
---|
| 1395 | widget_fields_have_contents=widget_fields_have_contents, |
---|
| 1396 | show_deleted=show_deleted, |
---|
| 1397 | message=message, |
---|
| 1398 | status=status ) |
---|
| 1399 | @web.expose |
---|
| 1400 | def library_dataset_permissions( self, trans, cntrller, id, library_id, **kwd ): |
---|
| 1401 | params = util.Params( kwd ) |
---|
| 1402 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 1403 | status = params.get( 'status', 'done' ) |
---|
| 1404 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 1405 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 1406 | is_admin = trans.user_is_admin() and cntrller == 'library_admin' |
---|
| 1407 | current_user_roles = trans.get_current_user_roles() |
---|
| 1408 | try: |
---|
| 1409 | library_dataset = trans.sa_session.query( trans.app.model.LibraryDataset ).get( trans.security.decode_id( id ) ) |
---|
| 1410 | except: |
---|
| 1411 | library_dataset = None |
---|
| 1412 | self._check_access( trans, cntrller, is_admin, library_dataset, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1413 | self._check_manage( trans, cntrller, is_admin, library_dataset, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1414 | if params.get( 'update_roles_button', False ): |
---|
| 1415 | # The user clicked the Save button on the 'Associate With Roles' form |
---|
| 1416 | permissions = {} |
---|
| 1417 | for k, v in trans.app.model.Library.permitted_actions.items(): |
---|
| 1418 | if k != 'LIBRARY_ACCESS': |
---|
| 1419 | # LIBRARY_ACCESS is a special permission set only at the library level |
---|
| 1420 | # and it is not inherited. |
---|
| 1421 | in_roles = [ trans.sa_session.query( trans.app.model.Role ).get( x ) for x in util.listify( kwd.get( k + '_in', [] ) ) ] |
---|
| 1422 | permissions[ trans.app.security_agent.get_action( v.action ) ] = in_roles |
---|
| 1423 | # Set the LIBRARY permissions on the LibraryDataset |
---|
| 1424 | # NOTE: the LibraryDataset and LibraryDatasetDatasetAssociation will be set with the same permissions |
---|
| 1425 | trans.app.security_agent.set_all_library_permissions( library_dataset, permissions ) |
---|
| 1426 | trans.sa_session.refresh( library_dataset ) |
---|
| 1427 | # Set the LIBRARY permissions on the LibraryDatasetDatasetAssociation |
---|
| 1428 | trans.app.security_agent.set_all_library_permissions( library_dataset.library_dataset_dataset_association, permissions ) |
---|
| 1429 | trans.sa_session.refresh( library_dataset.library_dataset_dataset_association ) |
---|
| 1430 | message = "Permisisons updated for library dataset '%s'." % library_dataset.name |
---|
| 1431 | status = 'done' |
---|
| 1432 | roles = trans.app.security_agent.get_legitimate_roles( trans, library_dataset, cntrller ) |
---|
| 1433 | return trans.fill_template( '/library/common/library_dataset_permissions.mako', |
---|
| 1434 | cntrller=cntrller, |
---|
| 1435 | use_panels=use_panels, |
---|
| 1436 | library_dataset=library_dataset, |
---|
| 1437 | library_id=library_id, |
---|
| 1438 | roles=roles, |
---|
| 1439 | current_user_roles=current_user_roles, |
---|
| 1440 | show_deleted=show_deleted, |
---|
| 1441 | message=message, |
---|
| 1442 | status=status ) |
---|
| 1443 | @web.expose |
---|
| 1444 | def make_library_item_public( self, trans, cntrller, library_id, item_type, id, **kwd ): |
---|
| 1445 | params = util.Params( kwd ) |
---|
| 1446 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 1447 | status = params.get( 'status', 'done' ) |
---|
| 1448 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 1449 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 1450 | current_user_roles = trans.get_current_user_roles() |
---|
| 1451 | is_admin = trans.user_is_admin() and cntrller == 'library_admin' |
---|
| 1452 | if item_type == 'library': |
---|
| 1453 | library = trans.sa_session.query( trans.model.Library ).get( trans.security.decode_id( id ) ) |
---|
| 1454 | self._check_access( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1455 | self._check_manage( trans, cntrller, is_admin, library, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1456 | contents = util.string_as_bool( params.get( 'contents', 'False' ) ) |
---|
| 1457 | trans.app.security_agent.make_library_public( library, contents=contents ) |
---|
| 1458 | if contents: |
---|
| 1459 | message = "The data library (%s) and all it's contents have been made publicly accessible." % library.name |
---|
| 1460 | else: |
---|
| 1461 | message = "The data library (%s) has been made publicly accessible, but access to it's contents has been left unchanged." % library.name |
---|
| 1462 | elif item_type == 'folder': |
---|
| 1463 | folder = trans.sa_session.query( trans.model.LibraryFolder ).get( trans.security.decode_id( id ) ) |
---|
| 1464 | self._check_access( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1465 | self._check_manage( trans, cntrller, is_admin, folder, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1466 | trans.app.security_agent.make_folder_public( folder ) |
---|
| 1467 | message = "All of the contents of folder (%s) have been made publicly accessible." % folder.name |
---|
| 1468 | elif item_type == 'ldda': |
---|
| 1469 | ldda = trans.sa_session.query( trans.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( id ) ) |
---|
| 1470 | self._check_access( trans, cntrller, is_admin, ldda.library_dataset, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1471 | self._check_manage( trans, cntrller, is_admin, ldda.library_dataset, current_user_roles, use_panels, library_id, show_deleted ) |
---|
| 1472 | trans.app.security_agent.make_dataset_public( ldda.dataset ) |
---|
| 1473 | message = "The libary dataset (%s) has been made publicly accessible." % ldda.name |
---|
| 1474 | else: |
---|
| 1475 | message = "Invalid item_type (%s) received." % str( item_type ) |
---|
| 1476 | status = 'error' |
---|
| 1477 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1478 | action='browse_library', |
---|
| 1479 | cntrller=cntrller, |
---|
| 1480 | use_panels=use_panels, |
---|
| 1481 | id=library_id, |
---|
| 1482 | show_deleted=show_deleted, |
---|
| 1483 | message=util.sanitize_text( message ), |
---|
| 1484 | status=status ) ) |
---|
| 1485 | @web.expose |
---|
| 1486 | def act_on_multiple_datasets( self, trans, cntrller, library_id, ldda_ids='', **kwd ): |
---|
| 1487 | class NgxZip( object ): |
---|
| 1488 | def __init__( self, url_base ): |
---|
| 1489 | self.files = {} |
---|
| 1490 | self.url_base = url_base |
---|
| 1491 | def add( self, file, relpath ): |
---|
| 1492 | self.files[file] = relpath |
---|
| 1493 | def __str__( self ): |
---|
| 1494 | rval = '' |
---|
| 1495 | for fname, relpath in self.files.items(): |
---|
| 1496 | crc = '-' |
---|
| 1497 | size = os.stat( fname ).st_size |
---|
| 1498 | quoted_fname = urllib.quote_plus( fname, '/' ) |
---|
| 1499 | rval += '%s %i %s%s %s\r\n' % ( crc, size, self.url_base, quoted_fname, relpath ) |
---|
| 1500 | return rval |
---|
| 1501 | # Perform an action on a list of library datasets. |
---|
| 1502 | params = util.Params( kwd ) |
---|
| 1503 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 1504 | status = params.get( 'status', 'done' ) |
---|
| 1505 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 1506 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 1507 | action = params.get( 'do_action', None ) |
---|
| 1508 | lddas = [] |
---|
| 1509 | error = False |
---|
| 1510 | is_admin = trans.user_is_admin() and cntrller == 'library_admin' |
---|
| 1511 | current_user_roles = trans.get_current_user_roles() |
---|
| 1512 | if not ldda_ids: |
---|
| 1513 | error = True |
---|
| 1514 | message = 'You must select at least one dataset.' |
---|
| 1515 | elif not action: |
---|
| 1516 | error = True |
---|
| 1517 | message = 'You must select an action to perform on the selected datasets.' |
---|
| 1518 | else: |
---|
| 1519 | # Set up the list of lddas for later, and get permission checks out of the way so we don't have to do it in multiple places later. |
---|
| 1520 | ldda_ids = util.listify( ldda_ids ) |
---|
| 1521 | for ldda_id in ldda_ids: |
---|
| 1522 | try: |
---|
| 1523 | ldda = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( ldda_id ) ) |
---|
| 1524 | except: |
---|
| 1525 | ldda = None |
---|
| 1526 | if not ldda or ( not is_admin and not trans.app.security_agent.can_access_library_item( current_user_roles, ldda, trans.user ) ): |
---|
| 1527 | error = True |
---|
| 1528 | message = "Invalid library dataset id ( %s ) specified." % str( ldda_id ) |
---|
| 1529 | break |
---|
| 1530 | lddas.append( ldda ) |
---|
| 1531 | if action == 'import_to_history' or action == 'add': |
---|
| 1532 | if trans.get_history() is None: |
---|
| 1533 | # Must be a bot sending a request without having a history. |
---|
| 1534 | error = True |
---|
| 1535 | message = "You do not have a current history" |
---|
| 1536 | elif action == 'manage_permissions': |
---|
| 1537 | if not is_admin: |
---|
| 1538 | for ldda in lddas: |
---|
| 1539 | if not ( trans.app.security_agent.can_manage_library_item( current_user_roles, ldda ) and \ |
---|
| 1540 | trans.app.security_agent.can_manage_dataset( current_user_roles, ldda.dataset ) ): |
---|
| 1541 | error = True |
---|
| 1542 | message = "You are not authorized to manage permissions on library dataset '%s'." % ldda.name |
---|
| 1543 | break |
---|
| 1544 | elif action == 'delete': |
---|
| 1545 | if not is_admin: |
---|
| 1546 | for ldda in lddas: |
---|
| 1547 | if not trans.app.security_agent.can_modify_library_item( current_user_roles, ldda ): |
---|
| 1548 | error = True |
---|
| 1549 | message = "You are not authorized to modify library dataset '%s'." % ldda.name |
---|
| 1550 | break |
---|
| 1551 | if error: |
---|
| 1552 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1553 | action='browse_library', |
---|
| 1554 | cntrller=cntrller, |
---|
| 1555 | use_panels=use_panels, |
---|
| 1556 | id=library_id, |
---|
| 1557 | show_deleted=show_deleted, |
---|
| 1558 | message=util.sanitize_text( message ), |
---|
| 1559 | status='error' ) ) |
---|
| 1560 | if action == 'import_to_history' or action == 'add': |
---|
| 1561 | history = trans.get_history() |
---|
| 1562 | total_imported_lddas = 0 |
---|
| 1563 | message = '' |
---|
| 1564 | status = 'done' |
---|
| 1565 | for ldda in lddas: |
---|
| 1566 | if ldda.dataset.state in [ 'new', 'upload', 'queued', 'running', 'empty', 'discarded' ]: |
---|
| 1567 | message += "Cannot import dataset '%s' since its state is '%s'. " % ( ldda.name, ldda.dataset.state ) |
---|
| 1568 | status = 'error' |
---|
| 1569 | elif ldda.dataset.state in [ 'ok', 'error' ]: |
---|
| 1570 | hda = ldda.to_history_dataset_association( target_history=history, add_to_history=True ) |
---|
| 1571 | total_imported_lddas += 1 |
---|
| 1572 | if total_imported_lddas: |
---|
| 1573 | trans.sa_session.add( history ) |
---|
| 1574 | trans.sa_session.flush() |
---|
| 1575 | message += "%i dataset(s) have been imported into your history. " % total_imported_lddas |
---|
| 1576 | elif action == 'manage_permissions': |
---|
| 1577 | trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1578 | action='ldda_permissions', |
---|
| 1579 | cntrller=cntrller, |
---|
| 1580 | use_panels=use_panels, |
---|
| 1581 | library_id=library_id, |
---|
| 1582 | folder_id=trans.security.encode_id( lddas[0].library_dataset.folder.id ), |
---|
| 1583 | id=",".join( ldda_ids ), |
---|
| 1584 | show_deleted=show_deleted, |
---|
| 1585 | message=util.sanitize_text( message ), |
---|
| 1586 | status=status ) ) |
---|
| 1587 | elif action == 'delete': |
---|
| 1588 | for ldda in lddas: |
---|
| 1589 | # Do not delete the association, just delete the library_dataset. The |
---|
| 1590 | # cleanup_datasets.py script handles everything else. |
---|
| 1591 | ld = ldda.library_dataset |
---|
| 1592 | ld.deleted = True |
---|
| 1593 | trans.sa_session.add( ld ) |
---|
| 1594 | trans.sa_session.flush() |
---|
| 1595 | message = "The selected datasets have been removed from this data library" |
---|
| 1596 | elif action in ['zip','tgz','tbz','ngxzip']: |
---|
| 1597 | error = False |
---|
| 1598 | killme = string.punctuation + string.whitespace |
---|
| 1599 | trantab = string.maketrans(killme,'_'*len(killme)) |
---|
| 1600 | try: |
---|
| 1601 | outext = 'zip' |
---|
| 1602 | if action == 'zip': |
---|
| 1603 | # Can't use mkstemp - the file must not exist first |
---|
| 1604 | tmpd = tempfile.mkdtemp() |
---|
| 1605 | tmpf = os.path.join( tmpd, 'library_download.' + action ) |
---|
| 1606 | if ziptype == '64' and trans.app.config.upstream_gzip: |
---|
| 1607 | archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_STORED, True ) |
---|
| 1608 | elif ziptype == '64': |
---|
| 1609 | archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED, True ) |
---|
| 1610 | elif trans.app.config.upstream_gzip: |
---|
| 1611 | archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_STORED ) |
---|
| 1612 | else: |
---|
| 1613 | archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED ) |
---|
| 1614 | archive.add = lambda x, y: archive.write( x, y.encode('CP437') ) |
---|
| 1615 | elif action == 'tgz': |
---|
| 1616 | if trans.app.config.upstream_gzip: |
---|
| 1617 | archive = util.streamball.StreamBall( 'w|' ) |
---|
| 1618 | outext = 'tar' |
---|
| 1619 | else: |
---|
| 1620 | archive = util.streamball.StreamBall( 'w|gz' ) |
---|
| 1621 | outext = 'tgz' |
---|
| 1622 | elif action == 'tbz': |
---|
| 1623 | archive = util.streamball.StreamBall( 'w|bz2' ) |
---|
| 1624 | outext = 'tbz2' |
---|
| 1625 | elif action == 'ngxzip': |
---|
| 1626 | archive = NgxZip( trans.app.config.nginx_x_archive_files_base ) |
---|
| 1627 | except (OSError, zipfile.BadZipfile): |
---|
| 1628 | error = True |
---|
| 1629 | log.exception( "Unable to create archive for download" ) |
---|
| 1630 | message = "Unable to create archive for download, please report this error" |
---|
| 1631 | status = 'error' |
---|
| 1632 | except: |
---|
| 1633 | error = True |
---|
| 1634 | log.exception( "Unexpected error %s in create archive for download" % sys.exc_info()[0]) |
---|
| 1635 | message = "Unable to create archive for download, please report - %s" % sys.exc_info()[0] |
---|
| 1636 | status = 'error' |
---|
| 1637 | if not error: |
---|
| 1638 | composite_extensions = trans.app.datatypes_registry.get_composite_extensions( ) |
---|
| 1639 | seen = [] |
---|
| 1640 | for ldda in lddas: |
---|
| 1641 | if ldda.dataset.state in [ 'new', 'upload', 'queued', 'running', 'empty', 'discarded' ]: |
---|
| 1642 | continue |
---|
| 1643 | ext = ldda.extension |
---|
| 1644 | is_composite = ext in composite_extensions |
---|
| 1645 | path = "" |
---|
| 1646 | parent_folder = ldda.library_dataset.folder |
---|
| 1647 | while parent_folder is not None: |
---|
| 1648 | # Exclude the now-hidden "root folder" |
---|
| 1649 | if parent_folder.parent is None: |
---|
| 1650 | path = os.path.join( parent_folder.library_root[0].name, path ) |
---|
| 1651 | break |
---|
| 1652 | path = os.path.join( parent_folder.name, path ) |
---|
| 1653 | parent_folder = parent_folder.parent |
---|
| 1654 | path += ldda.name |
---|
| 1655 | while path in seen: |
---|
| 1656 | path += '_' |
---|
| 1657 | seen.append( path ) |
---|
| 1658 | zpath = os.path.split(path)[-1] # comes as base_name/fname |
---|
| 1659 | outfname,zpathext = os.path.splitext(zpath) |
---|
| 1660 | if is_composite: |
---|
| 1661 | # need to add all the components from the extra_files_path to the zip |
---|
| 1662 | if zpathext == '': |
---|
| 1663 | zpath = '%s.html' % zpath # fake the real nature of the html file |
---|
| 1664 | try: |
---|
| 1665 | archive.add(ldda.dataset.file_name,zpath) # add the primary of a composite set |
---|
| 1666 | except IOError: |
---|
| 1667 | error = True |
---|
| 1668 | log.exception( "Unable to add composite parent %s to temporary library download archive" % ldda.dataset.file_name) |
---|
| 1669 | message = "Unable to create archive for download, please report this error" |
---|
| 1670 | status = 'error' |
---|
| 1671 | continue |
---|
| 1672 | flist = glob.glob(os.path.join(ldda.dataset.extra_files_path,'*.*')) # glob returns full paths |
---|
| 1673 | for fpath in flist: |
---|
| 1674 | efp,fname = os.path.split(fpath) |
---|
| 1675 | if fname > '': |
---|
| 1676 | fname = fname.translate(trantab) |
---|
| 1677 | try: |
---|
| 1678 | archive.add( fpath,fname ) |
---|
| 1679 | except IOError: |
---|
| 1680 | error = True |
---|
| 1681 | log.exception( "Unable to add %s to temporary library download archive %s" % (fname,outfname)) |
---|
| 1682 | message = "Unable to create archive for download, please report this error" |
---|
| 1683 | status = 'error' |
---|
| 1684 | continue |
---|
| 1685 | else: # simple case |
---|
| 1686 | try: |
---|
| 1687 | archive.add( ldda.dataset.file_name, path ) |
---|
| 1688 | except IOError: |
---|
| 1689 | error = True |
---|
| 1690 | log.exception( "Unable to write %s to temporary library download archive" % ldda.dataset.file_name) |
---|
| 1691 | message = "Unable to create archive for download, please report this error" |
---|
| 1692 | status = 'error' |
---|
| 1693 | if not error: |
---|
| 1694 | lname = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( library_id ) ).name |
---|
| 1695 | fname = lname.replace( ' ', '_' ) + '_files' |
---|
| 1696 | if action == 'zip': |
---|
| 1697 | archive.close() |
---|
| 1698 | tmpfh = open( tmpf ) |
---|
| 1699 | # clean up now |
---|
| 1700 | try: |
---|
| 1701 | os.unlink( tmpf ) |
---|
| 1702 | os.rmdir( tmpd ) |
---|
| 1703 | except OSError: |
---|
| 1704 | error = True |
---|
| 1705 | log.exception( "Unable to remove temporary library download archive and directory" ) |
---|
| 1706 | message = "Unable to create archive for download, please report this error" |
---|
| 1707 | status = 'error' |
---|
| 1708 | if not error: |
---|
| 1709 | trans.response.set_content_type( "application/x-zip-compressed" ) |
---|
| 1710 | trans.response.headers[ "Content-Disposition" ] = "attachment; filename=%s.%s" % (fname,outext) |
---|
| 1711 | return tmpfh |
---|
| 1712 | elif action == 'ngxzip': |
---|
| 1713 | trans.response.set_content_type( "application/zip" ) |
---|
| 1714 | trans.response.headers[ "Content-Disposition" ] = "attachment; filename=%s.%s" % (fname,outext) |
---|
| 1715 | trans.response.headers[ "X-Archive-Files" ] = "zip" |
---|
| 1716 | return archive |
---|
| 1717 | else: |
---|
| 1718 | trans.response.set_content_type( "application/x-tar" ) |
---|
| 1719 | trans.response.headers[ "Content-Disposition" ] = "attachment; filename=%s.%s" % (fname,outext) |
---|
| 1720 | archive.wsgi_status = trans.response.wsgi_status() |
---|
| 1721 | archive.wsgi_headeritems = trans.response.wsgi_headeritems() |
---|
| 1722 | return archive.stream |
---|
| 1723 | else: |
---|
| 1724 | status = 'error' |
---|
| 1725 | message = 'Invalid action ( %s ) specified.' % action |
---|
| 1726 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1727 | action='browse_library', |
---|
| 1728 | cntrller=cntrller, |
---|
| 1729 | use_panels=use_panels, |
---|
| 1730 | id=library_id, |
---|
| 1731 | show_deleted=show_deleted, |
---|
| 1732 | message=util.sanitize_text( message ), |
---|
| 1733 | status=status ) ) |
---|
| 1734 | def get_item_and_stuff( self, trans, item_type, library_id, folder_id, ldda_id, is_admin ): |
---|
| 1735 | # Return an item, description, action and an id based on the item_type. |
---|
| 1736 | message = None |
---|
| 1737 | current_user_roles = trans.get_current_user_roles() |
---|
| 1738 | if item_type == 'library': |
---|
| 1739 | try: |
---|
| 1740 | item = trans.sa_session.query( trans.app.model.Library ).get( trans.security.decode_id( library_id ) ) |
---|
| 1741 | except: |
---|
| 1742 | item = None |
---|
| 1743 | item_desc = 'data library' |
---|
| 1744 | action = 'library_info' |
---|
| 1745 | id = library_id |
---|
| 1746 | elif item_type == 'folder': |
---|
| 1747 | try: |
---|
| 1748 | item = trans.sa_session.query( trans.app.model.LibraryFolder ).get( trans.security.decode_id( folder_id ) ) |
---|
| 1749 | except: |
---|
| 1750 | item = None |
---|
| 1751 | item_desc = 'folder' |
---|
| 1752 | action = 'folder_info' |
---|
| 1753 | id = folder_id |
---|
| 1754 | elif item_type == 'ldda': |
---|
| 1755 | try: |
---|
| 1756 | item = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ).get( trans.security.decode_id( ldda_id ) ) |
---|
| 1757 | except: |
---|
| 1758 | item = None |
---|
| 1759 | item_desc = 'dataset' |
---|
| 1760 | action = 'ldda_edit_info' |
---|
| 1761 | id = ldda_id |
---|
| 1762 | else: |
---|
| 1763 | item = None |
---|
| 1764 | message = "Invalid library item type ( %s )" % str( item_type ) |
---|
| 1765 | if not item or not ( is_admin or trans.app.security_agent.can_access_library_item( current_user_roles, item, trans.user ) ): |
---|
| 1766 | if message is None: |
---|
| 1767 | message = "Invalid %s id ( %s ) specified." % ( item_desc, str( id ) ) |
---|
| 1768 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1769 | action='browse_library', |
---|
| 1770 | cntrller='library', # cheating a bit here |
---|
| 1771 | id=library_id, |
---|
| 1772 | message=util.sanitize_text( message ), |
---|
| 1773 | status='error' ) ) |
---|
| 1774 | return item, item_desc, action, id |
---|
| 1775 | @web.expose |
---|
| 1776 | def add_template( self, trans, cntrller, item_type, library_id, folder_id=None, ldda_id=None, **kwd ): |
---|
| 1777 | # Template can only be added to a Library, Folder or LibraryDatasetDatasetAssociation. |
---|
| 1778 | forms = self.get_all_forms( trans, |
---|
| 1779 | filter=dict( deleted=False ), |
---|
| 1780 | form_type=trans.app.model.FormDefinition.types.LIBRARY_INFO_TEMPLATE ) |
---|
| 1781 | if not forms: |
---|
| 1782 | message = "There are no forms on which to base the template, so create a form and then add the template." |
---|
| 1783 | return trans.response.send_redirect( web.url_for( controller='forms', |
---|
| 1784 | action='create_request', |
---|
| 1785 | message=message, |
---|
| 1786 | status='done', |
---|
| 1787 | form_type=trans.app.model.FormDefinition.types.LIBRARY_INFO_TEMPLATE ) ) |
---|
| 1788 | params = util.Params( kwd ) |
---|
| 1789 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 1790 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 1791 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 1792 | action = '' |
---|
| 1793 | status = params.get( 'status', 'done' ) |
---|
| 1794 | is_admin = ( trans.user_is_admin() and cntrller == 'library_admin' ) |
---|
| 1795 | current_user_roles = trans.get_current_user_roles() |
---|
| 1796 | try: |
---|
| 1797 | item, item_desc, action, id = self.get_item_and_stuff( trans, item_type, library_id, folder_id, ldda_id, is_admin ) |
---|
| 1798 | except ValueError: |
---|
| 1799 | # At this point, the client has already redirected, so this is just here to prevent the unnecessary traceback |
---|
| 1800 | return None |
---|
| 1801 | if not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, item ) ): |
---|
| 1802 | message = "You are not authorized to modify %s '%s'." % ( item_desc, item.name ) |
---|
| 1803 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1804 | action='browse_library', |
---|
| 1805 | cntrller=cntrller, |
---|
| 1806 | id=library_id, |
---|
| 1807 | show_deleted=show_deleted, |
---|
| 1808 | message=util.sanitize_text( message ), |
---|
| 1809 | status='error' ) ) |
---|
| 1810 | # If the inheritable checkbox is checked, the param will be in the request |
---|
| 1811 | inheritable = CheckboxField.is_checked( params.get( 'inheritable', '' ) ) |
---|
| 1812 | if params.get( 'add_template_button', False ): |
---|
| 1813 | form_id = params.get( 'form_id', 'none' ) |
---|
| 1814 | if form_id not in [ None, 'None', 'none' ]: |
---|
| 1815 | form = trans.sa_session.query( trans.app.model.FormDefinition ).get( trans.security.decode_id( form_id ) ) |
---|
| 1816 | form_values = trans.app.model.FormValues( form, [] ) |
---|
| 1817 | trans.sa_session.add( form_values ) |
---|
| 1818 | trans.sa_session.flush() |
---|
| 1819 | if item_type == 'library': |
---|
| 1820 | assoc = trans.app.model.LibraryInfoAssociation( item, form, form_values, inheritable=inheritable ) |
---|
| 1821 | elif item_type == 'folder': |
---|
| 1822 | assoc = trans.app.model.LibraryFolderInfoAssociation( item, form, form_values, inheritable=inheritable ) |
---|
| 1823 | elif item_type == 'ldda': |
---|
| 1824 | assoc = trans.app.model.LibraryDatasetDatasetInfoAssociation( item, form, form_values ) |
---|
| 1825 | trans.sa_session.add( assoc ) |
---|
| 1826 | trans.sa_session.flush() |
---|
| 1827 | message = 'A template based on the form "%s" has been added to this %s.' % ( form.name, item_desc ) |
---|
| 1828 | trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1829 | action=action, |
---|
| 1830 | cntrller=cntrller, |
---|
| 1831 | use_panels=use_panels, |
---|
| 1832 | library_id=library_id, |
---|
| 1833 | folder_id=folder_id, |
---|
| 1834 | id=id, |
---|
| 1835 | show_deleted=show_deleted, |
---|
| 1836 | message=message, |
---|
| 1837 | status='done' ) ) |
---|
| 1838 | else: |
---|
| 1839 | message = "Select a form on which to base the template." |
---|
| 1840 | status = "error" |
---|
| 1841 | def generate_template_stuff( trans, forms, form_id ): |
---|
| 1842 | # Returns the following: |
---|
| 1843 | # - a list of template ids |
---|
| 1844 | # - a list of dictionaries whose keys are template ids and whose values are templates widgets. |
---|
| 1845 | # The dictionary built using the received forms param |
---|
| 1846 | # - a select list whose options are templates |
---|
| 1847 | template_ids = [ 'none' ] |
---|
| 1848 | widgets = [] |
---|
| 1849 | for form in forms: |
---|
| 1850 | template_ids.append( trans.security.encode_id( form.id ) ) |
---|
| 1851 | template_select_list = SelectField( 'form_id', |
---|
| 1852 | refresh_on_change=True, |
---|
| 1853 | refresh_on_change_values=template_ids[1:] ) |
---|
| 1854 | if form_id == 'none': |
---|
| 1855 | template_select_list.add_option( 'Select one', 'none', selected=True ) |
---|
| 1856 | decoded_form_id = None |
---|
| 1857 | else: |
---|
| 1858 | template_select_list.add_option( 'Select one', 'none' ) |
---|
| 1859 | decoded_form_id = trans.security.decode_id( form_id ) |
---|
| 1860 | for form in forms: |
---|
| 1861 | if decoded_form_id and decoded_form_id == form.id: |
---|
| 1862 | template_select_list.add_option( form.name, trans.security.encode_id( form.id ), selected=True ) |
---|
| 1863 | widgets = form.get_widgets( trans.user ) |
---|
| 1864 | else: |
---|
| 1865 | template_select_list.add_option( form.name, trans.security.encode_id( form.id ) ) |
---|
| 1866 | return template_ids, widgets, template_select_list |
---|
| 1867 | if params.get( 'refresh', False ): |
---|
| 1868 | template_ids, widgets, template_select_list = generate_template_stuff( trans, forms, kwd.get( 'form_id' ) ) |
---|
| 1869 | else: |
---|
| 1870 | template_ids, widgets, template_select_list = generate_template_stuff( trans, forms, 'none' ) |
---|
| 1871 | return trans.fill_template( '/library/common/select_template.mako', |
---|
| 1872 | cntrller=cntrller, |
---|
| 1873 | use_panels=use_panels, |
---|
| 1874 | item_name=item.name, |
---|
| 1875 | item_desc=item_desc, |
---|
| 1876 | item_type=item_type, |
---|
| 1877 | library_id=library_id, |
---|
| 1878 | folder_id=folder_id, |
---|
| 1879 | ldda_id=ldda_id, |
---|
| 1880 | template_ids=template_ids, |
---|
| 1881 | widgets=widgets, |
---|
| 1882 | template_select_list=template_select_list, |
---|
| 1883 | inheritable_checked=inheritable, |
---|
| 1884 | show_deleted=show_deleted, |
---|
| 1885 | message=message, |
---|
| 1886 | status=status ) |
---|
| 1887 | @web.expose |
---|
| 1888 | def manage_template_inheritance( self, trans, cntrller, item_type, library_id, folder_id=None, ldda_id=None, **kwd ): |
---|
| 1889 | params = util.Params( kwd ) |
---|
| 1890 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 1891 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 1892 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 1893 | status = params.get( 'status', 'done' ) |
---|
| 1894 | is_admin = ( trans.user_is_admin() and cntrller == 'library_admin' ) |
---|
| 1895 | current_user_roles = trans.get_current_user_roles() |
---|
| 1896 | try: |
---|
| 1897 | item, item_desc, action, id = self.get_item_and_stuff( trans, item_type, library_id, folder_id, ldda_id, is_admin ) |
---|
| 1898 | except ValueError: |
---|
| 1899 | return None |
---|
| 1900 | if not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, item ) ): |
---|
| 1901 | message = "You are not authorized to modify %s '%s'." % ( item_desc, item.name ) |
---|
| 1902 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1903 | action='browse_library', |
---|
| 1904 | cntrller=cntrller, |
---|
| 1905 | id=library_id, |
---|
| 1906 | show_deleted=show_deleted, |
---|
| 1907 | message=util.sanitize_text( message ), |
---|
| 1908 | status='error' ) ) |
---|
| 1909 | info_association, inherited = item.get_info_association( restrict=True ) |
---|
| 1910 | if info_association: |
---|
| 1911 | if info_association.inheritable: |
---|
| 1912 | message = "The template for this %s will no longer be inherited to contained folders and datasets." % item_desc |
---|
| 1913 | else: |
---|
| 1914 | message = "The template for this %s will now be inherited to contained folders and datasets." % item_desc |
---|
| 1915 | info_association.inheritable = not( info_association.inheritable ) |
---|
| 1916 | trans.sa_session.add( info_association ) |
---|
| 1917 | trans.sa_session.flush() |
---|
| 1918 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1919 | action=action, |
---|
| 1920 | cntrller=cntrller, |
---|
| 1921 | use_panels=use_panels, |
---|
| 1922 | library_id=library_id, |
---|
| 1923 | folder_id=folder_id, |
---|
| 1924 | id=id, |
---|
| 1925 | show_deleted=show_deleted, |
---|
| 1926 | message=util.sanitize_text( message ), |
---|
| 1927 | status='done' ) ) |
---|
| 1928 | @web.expose |
---|
| 1929 | def edit_template( self, trans, cntrller, item_type, library_id, folder_id=None, ldda_id=None, edited=False, **kwd ): |
---|
| 1930 | # Edit the template itself, keeping existing field contents, if any. |
---|
| 1931 | params = util.Params( kwd ) |
---|
| 1932 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 1933 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 1934 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 1935 | status = params.get( 'status', 'done' ) |
---|
| 1936 | is_admin = ( trans.user_is_admin() and cntrller == 'library_admin' ) |
---|
| 1937 | current_user_roles = trans.get_current_user_roles() |
---|
| 1938 | try: |
---|
| 1939 | item, item_desc, action, id = self.get_item_and_stuff( trans, item_type, library_id, folder_id, ldda_id, is_admin ) |
---|
| 1940 | except ValueError: |
---|
| 1941 | return None |
---|
| 1942 | if not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, item ) ): |
---|
| 1943 | message = "You are not authorized to modify %s '%s'." % ( item_desc, item.name ) |
---|
| 1944 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1945 | action='browse_library', |
---|
| 1946 | cntrller=cntrller, |
---|
| 1947 | id=library_id, |
---|
| 1948 | show_deleted=show_deleted, |
---|
| 1949 | message=util.sanitize_text( message ), |
---|
| 1950 | status='error' ) ) |
---|
| 1951 | # An info_association must exist at this point |
---|
| 1952 | info_association, inherited = item.get_info_association( restrict=True ) |
---|
| 1953 | template = info_association.template |
---|
| 1954 | info = info_association.info |
---|
| 1955 | form_values = trans.sa_session.query( trans.app.model.FormValues ).get( info.id ) |
---|
| 1956 | if edited: |
---|
| 1957 | # The form on which the template is based has been edited, so we need to update the |
---|
| 1958 | # info_association with the current form |
---|
| 1959 | fdc = trans.sa_session.query( trans.app.model.FormDefinitionCurrent ).get( template.form_definition_current_id ) |
---|
| 1960 | info_association.template = fdc.latest_form |
---|
| 1961 | trans.sa_session.add( info_association ) |
---|
| 1962 | trans.sa_session.flush() |
---|
| 1963 | message = "The template for this %s has been updated with your changes." % item_desc |
---|
| 1964 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 1965 | action=action, |
---|
| 1966 | cntrller=cntrller, |
---|
| 1967 | use_panels=use_panels, |
---|
| 1968 | library_id=library_id, |
---|
| 1969 | folder_id=folder_id, |
---|
| 1970 | id=id, |
---|
| 1971 | show_deleted=show_deleted, |
---|
| 1972 | message=util.sanitize_text( message ), |
---|
| 1973 | status='done' ) ) |
---|
| 1974 | # "template" is a FormDefinition, so since we're changing it, we need to use the latest version of it. |
---|
| 1975 | vars = dict( id=trans.security.encode_id( template.form_definition_current_id ), |
---|
| 1976 | response_redirect=web.url_for( controller='library_common', |
---|
| 1977 | action='edit_template', |
---|
| 1978 | cntrller=cntrller, |
---|
| 1979 | item_type=item_type, |
---|
| 1980 | library_id=library_id, |
---|
| 1981 | folder_id=folder_id, |
---|
| 1982 | ldda_id=ldda_id, |
---|
| 1983 | edited=True, |
---|
| 1984 | **kwd ) ) |
---|
| 1985 | return trans.response.send_redirect( web.url_for( controller='forms', action='edit', **vars ) ) |
---|
| 1986 | @web.expose |
---|
| 1987 | def edit_template_info( self, trans, cntrller, item_type, library_id, folder_id=None, ldda_id=None, **kwd ): |
---|
| 1988 | # Edit the contents of the template fields without altering the template itself. |
---|
| 1989 | params = util.Params( kwd ) |
---|
| 1990 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 1991 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 1992 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 1993 | status = params.get( 'status', 'done' ) |
---|
| 1994 | is_admin = ( trans.user_is_admin() and cntrller == 'library_admin' ) |
---|
| 1995 | current_user_roles = trans.get_current_user_roles() |
---|
| 1996 | try: |
---|
| 1997 | item, item_desc, action, id = self.get_item_and_stuff( trans, item_type, library_id, folder_id, ldda_id, is_admin ) |
---|
| 1998 | except ValueError: |
---|
| 1999 | return None |
---|
| 2000 | if not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, item ) ): |
---|
| 2001 | message = "You are not authorized to modify %s '%s'." % ( item_desc, item.name ) |
---|
| 2002 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 2003 | action='browse_library', |
---|
| 2004 | cntrller=cntrller, |
---|
| 2005 | id=library_id, |
---|
| 2006 | show_deleted=show_deleted, |
---|
| 2007 | message=util.sanitize_text( message ), |
---|
| 2008 | status='error' ) ) |
---|
| 2009 | # We need the type of each template field widget |
---|
| 2010 | widgets = item.get_template_widgets( trans ) |
---|
| 2011 | # The list of widgets may include an AddressField which we need to save if it is new |
---|
| 2012 | for index, widget_dict in enumerate( widgets ): |
---|
| 2013 | widget = widget_dict[ 'widget' ] |
---|
| 2014 | if isinstance( widget, AddressField ): |
---|
| 2015 | value = util.restore_text( params.get( 'field_%i' % index, '' ) ) |
---|
| 2016 | if value == 'new': |
---|
| 2017 | if params.get( 'edit_info_button', False ): |
---|
| 2018 | if self.field_param_values_ok( index, 'AddressField', **kwd ): |
---|
| 2019 | # Save the new address |
---|
| 2020 | address = trans.app.model.UserAddress( user=trans.user ) |
---|
| 2021 | self.save_widget_field( trans, address, index, **kwd ) |
---|
| 2022 | widget.value = str( address.id ) |
---|
| 2023 | else: |
---|
| 2024 | message = 'Required fields are missing contents.' |
---|
| 2025 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 2026 | action=action, |
---|
| 2027 | cntrller=cntrller, |
---|
| 2028 | use_panels=use_panels, |
---|
| 2029 | library_id=library_id, |
---|
| 2030 | folder_id=folder_id, |
---|
| 2031 | id=id, |
---|
| 2032 | show_deleted=show_deleted, |
---|
| 2033 | message=util.sanitize_text( message ), |
---|
| 2034 | status='error' ) ) |
---|
| 2035 | else: |
---|
| 2036 | # Form was submitted via refresh_on_change |
---|
| 2037 | widget.value = 'new' |
---|
| 2038 | elif value == unicode( 'none' ): |
---|
| 2039 | widget.value = '' |
---|
| 2040 | else: |
---|
| 2041 | widget.value = value |
---|
| 2042 | elif isinstance( widget, CheckboxField ): |
---|
| 2043 | # We need to check the value from kwd since util.Params would have munged the list if |
---|
| 2044 | # the checkbox is checked. |
---|
| 2045 | value = kwd.get( 'field_%i' % index, '' ) |
---|
| 2046 | if CheckboxField.is_checked( value ): |
---|
| 2047 | widget.value = 'true' |
---|
| 2048 | else: |
---|
| 2049 | widget.value = util.restore_text( params.get( 'field_%i' % index, '' ) ) |
---|
| 2050 | # Save updated template field contents |
---|
| 2051 | field_contents = self.clean_field_contents( widgets, **kwd ) |
---|
| 2052 | if field_contents: |
---|
| 2053 | # Since information templates are inherited, the template fields can be displayed on the information |
---|
| 2054 | # page for a folder or ldda when it has no info_association object. If the user has added |
---|
| 2055 | # field contents on an inherited template via a parent's info_association, we'll need to create a new |
---|
| 2056 | # form_values and info_association for the current object. The value for the returned inherited variable |
---|
| 2057 | # is not applicable at this level. |
---|
| 2058 | info_association, inherited = item.get_info_association( restrict=True ) |
---|
| 2059 | if info_association: |
---|
| 2060 | template = info_association.template |
---|
| 2061 | info = info_association.info |
---|
| 2062 | form_values = trans.sa_session.query( trans.app.model.FormValues ).get( info.id ) |
---|
| 2063 | # Update existing content only if it has changed |
---|
| 2064 | if form_values.content != field_contents: |
---|
| 2065 | form_values.content = field_contents |
---|
| 2066 | trans.sa_session.add( form_values ) |
---|
| 2067 | trans.sa_session.flush() |
---|
| 2068 | else: |
---|
| 2069 | # Inherit the next available info_association so we can get the template |
---|
| 2070 | info_association, inherited = item.get_info_association() |
---|
| 2071 | template = info_association.template |
---|
| 2072 | # Create a new FormValues object |
---|
| 2073 | form_values = trans.app.model.FormValues( template, field_contents ) |
---|
| 2074 | trans.sa_session.add( form_values ) |
---|
| 2075 | trans.sa_session.flush() |
---|
| 2076 | # Create a new info_association between the current library item and form_values |
---|
| 2077 | if item_type == 'folder': |
---|
| 2078 | # A LibraryFolder is a special case because if it inherited the template from it's parent, |
---|
| 2079 | # we want to set inheritable to True for it's info_association. This allows for the default |
---|
| 2080 | # inheritance to be False for each level in the Library hierarchy unless we're creating a new |
---|
| 2081 | # level in the hierarchy, in which case we'll inherit the "inheritable" setting from the parent |
---|
| 2082 | # level. |
---|
| 2083 | info_association = trans.app.model.LibraryFolderInfoAssociation( item, template, form_values, inheritable=inherited ) |
---|
| 2084 | trans.sa_session.add( info_association ) |
---|
| 2085 | trans.sa_session.flush() |
---|
| 2086 | elif item_type == 'ldda': |
---|
| 2087 | # TODO: Currently info_associations at teh ldda level are not inheritable to the associated LibraryDataset. |
---|
| 2088 | # We need to figure out if this is optimal. |
---|
| 2089 | info_association = trans.app.model.LibraryDatasetDatasetInfoAssociation( item, template, form_values ) |
---|
| 2090 | trans.sa_session.add( info_association ) |
---|
| 2091 | trans.sa_session.flush() |
---|
| 2092 | message = 'The information has been updated.' |
---|
| 2093 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 2094 | action=action, |
---|
| 2095 | cntrller=cntrller, |
---|
| 2096 | use_panels=use_panels, |
---|
| 2097 | library_id=library_id, |
---|
| 2098 | folder_id=folder_id, |
---|
| 2099 | id=id, |
---|
| 2100 | show_deleted=show_deleted, |
---|
| 2101 | message=util.sanitize_text( message ), |
---|
| 2102 | status='done' ) ) |
---|
| 2103 | @web.expose |
---|
| 2104 | def delete_template( self, trans, cntrller, item_type, library_id, id=None, folder_id=None, ldda_id=None, **kwd ): |
---|
| 2105 | # Only adding a new template to a library or folder is currently allowed. Editing an existing template is |
---|
| 2106 | # a future enhancement. |
---|
| 2107 | params = util.Params( kwd ) |
---|
| 2108 | show_deleted = util.string_as_bool( params.get( 'show_deleted', False ) ) |
---|
| 2109 | use_panels = util.string_as_bool( params.get( 'use_panels', False ) ) |
---|
| 2110 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 2111 | status = params.get( 'status', 'done' ) |
---|
| 2112 | is_admin = ( trans.user_is_admin() and cntrller == 'library_admin' ) |
---|
| 2113 | current_user_roles = trans.get_current_user_roles() |
---|
| 2114 | try: |
---|
| 2115 | item, item_desc, action, id = self.get_item_and_stuff( trans, item_type, library_id, folder_id, ldda_id, is_admin ) |
---|
| 2116 | except ValueError: |
---|
| 2117 | return None |
---|
| 2118 | if not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, item ) ): |
---|
| 2119 | message = "You are not authorized to modify %s '%s'." % ( item_desc, item.name ) |
---|
| 2120 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 2121 | action='browse_library', |
---|
| 2122 | cntrller=cntrller, |
---|
| 2123 | id=library_id, |
---|
| 2124 | show_deleted=show_deleted, |
---|
| 2125 | message=util.sanitize_text( message ), |
---|
| 2126 | status='error' ) ) |
---|
| 2127 | info_association, inherited = item.get_info_association() |
---|
| 2128 | if not info_association: |
---|
| 2129 | message = "There is no template for this %s" % item_type |
---|
| 2130 | status = 'error' |
---|
| 2131 | else: |
---|
| 2132 | info_association.deleted = True |
---|
| 2133 | trans.sa_session.add( info_association ) |
---|
| 2134 | trans.sa_session.flush() |
---|
| 2135 | message = 'The template for this %s has been deleted.' % item_type |
---|
| 2136 | status = 'done' |
---|
| 2137 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 2138 | action=action, |
---|
| 2139 | cntrller=cntrller, |
---|
| 2140 | use_panels=use_panels, |
---|
| 2141 | library_id=library_id, |
---|
| 2142 | folder_id=folder_id, |
---|
| 2143 | id=id, |
---|
| 2144 | show_deleted=show_deleted, |
---|
| 2145 | message=util.sanitize_text( message ), |
---|
| 2146 | status=status ) ) |
---|
| 2147 | @web.expose |
---|
| 2148 | def delete_library_item( self, trans, cntrller, library_id, item_id, item_type, **kwd ): |
---|
| 2149 | # This action will handle deleting all types of library items. State is saved for libraries and |
---|
| 2150 | # folders ( i.e., if undeleted, the state of contents of the library or folder will remain, so previously |
---|
| 2151 | # deleted / purged contents will have the same state ). When a library or folder has been deleted for |
---|
| 2152 | # the amount of time defined in the cleanup_datasets.py script, the library or folder and all of its |
---|
| 2153 | # contents will be purged. The association between this method and the cleanup_datasets.py script |
---|
| 2154 | # enables clean maintenance of libraries and library dataset disk files. This is also why the item_types |
---|
| 2155 | # are not any of the associations ( the cleanup_datasets.py script handles everything ). |
---|
| 2156 | show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) ) |
---|
| 2157 | item_types = { 'library': trans.app.model.Library, |
---|
| 2158 | 'folder': trans.app.model.LibraryFolder, |
---|
| 2159 | 'library_dataset': trans.app.model.LibraryDataset } |
---|
| 2160 | is_admin = ( trans.user_is_admin() and cntrller == 'library_admin' ) |
---|
| 2161 | current_user_roles = trans.get_current_user_roles() |
---|
| 2162 | if item_type not in item_types: |
---|
| 2163 | message = 'Bad item_type specified: %s' % str( item_type ) |
---|
| 2164 | status = 'error' |
---|
| 2165 | else: |
---|
| 2166 | if item_type == 'library_dataset': |
---|
| 2167 | item_desc = 'Dataset' |
---|
| 2168 | else: |
---|
| 2169 | item_desc = item_type.capitalize() |
---|
| 2170 | try: |
---|
| 2171 | library_item = trans.sa_session.query( item_types[ item_type ] ).get( trans.security.decode_id( item_id ) ) |
---|
| 2172 | except: |
---|
| 2173 | library_item = None |
---|
| 2174 | if not library_item or not ( is_admin or trans.app.security_agent.can_access_library_item( current_user_roles, library_item, trans.user ) ): |
---|
| 2175 | message = 'Invalid %s id ( %s ) specifield.' % ( item_desc, item_id ) |
---|
| 2176 | status = 'error' |
---|
| 2177 | elif not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, library_item ) ): |
---|
| 2178 | message = "You are not authorized to delete %s '%s'." % ( item_desc, library_item.name ) |
---|
| 2179 | status = 'error' |
---|
| 2180 | else: |
---|
| 2181 | library_item.deleted = True |
---|
| 2182 | trans.sa_session.add( library_item ) |
---|
| 2183 | trans.sa_session.flush() |
---|
| 2184 | message = util.sanitize_text( "%s '%s' has been marked deleted" % ( item_desc, library_item.name ) ) |
---|
| 2185 | status = 'done' |
---|
| 2186 | if item_type == 'library': |
---|
| 2187 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 2188 | action='browse_libraries', |
---|
| 2189 | message=message, |
---|
| 2190 | status=status ) ) |
---|
| 2191 | else: |
---|
| 2192 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 2193 | action='browse_library', |
---|
| 2194 | cntrller=cntrller, |
---|
| 2195 | id=library_id, |
---|
| 2196 | show_deleted=show_deleted, |
---|
| 2197 | message=message, |
---|
| 2198 | status=status ) ) |
---|
| 2199 | @web.expose |
---|
| 2200 | def undelete_library_item( self, trans, cntrller, library_id, item_id, item_type, **kwd ): |
---|
| 2201 | # This action will handle undeleting all types of library items |
---|
| 2202 | show_deleted = util.string_as_bool( kwd.get( 'show_deleted', False ) ) |
---|
| 2203 | item_types = { 'library': trans.app.model.Library, |
---|
| 2204 | 'folder': trans.app.model.LibraryFolder, |
---|
| 2205 | 'library_dataset': trans.app.model.LibraryDataset } |
---|
| 2206 | is_admin = ( trans.user_is_admin() and cntrller == 'library_admin' ) |
---|
| 2207 | current_user_roles = trans.get_current_user_roles() |
---|
| 2208 | if item_type not in item_types: |
---|
| 2209 | message = 'Bad item_type specified: %s' % str( item_type ) |
---|
| 2210 | status = ERROR |
---|
| 2211 | else: |
---|
| 2212 | if item_type == 'library_dataset': |
---|
| 2213 | item_desc = 'Dataset' |
---|
| 2214 | else: |
---|
| 2215 | item_desc = item_type.capitalize() |
---|
| 2216 | try: |
---|
| 2217 | library_item = trans.sa_session.query( item_types[ item_type ] ).get( trans.security.decode_id( item_id ) ) |
---|
| 2218 | except: |
---|
| 2219 | library_item = None |
---|
| 2220 | if not library_item or not ( is_admin or trans.app.security_agent.can_access_library_item( current_user_roles, library_item, trans.user ) ): |
---|
| 2221 | message = 'Invalid %s id ( %s ) specifield.' % ( item_desc, item_id ) |
---|
| 2222 | status = 'error' |
---|
| 2223 | elif library_item.purged: |
---|
| 2224 | message = '%s %s has been purged, so it cannot be undeleted' % ( item_desc, library_item.name ) |
---|
| 2225 | status = ERROR |
---|
| 2226 | elif not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, library_item ) ): |
---|
| 2227 | message = "You are not authorized to delete %s '%s'." % ( item_desc, library_item.name ) |
---|
| 2228 | status = 'error' |
---|
| 2229 | else: |
---|
| 2230 | library_item.deleted = False |
---|
| 2231 | trans.sa_session.add( library_item ) |
---|
| 2232 | trans.sa_session.flush() |
---|
| 2233 | message = util.sanitize_text( "%s '%s' has been marked undeleted" % ( item_desc, library_item.name ) ) |
---|
| 2234 | status = SUCCESS |
---|
| 2235 | if item_type == 'library': |
---|
| 2236 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 2237 | action='browse_libraries', |
---|
| 2238 | message=message, |
---|
| 2239 | status=status ) ) |
---|
| 2240 | else: |
---|
| 2241 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 2242 | action='browse_library', |
---|
| 2243 | cntrller=cntrller, |
---|
| 2244 | id=library_id, |
---|
| 2245 | show_deleted=show_deleted, |
---|
| 2246 | message=message, |
---|
| 2247 | status=status ) ) |
---|
| 2248 | def _check_access( self, trans, cntrller, is_admin, item, current_user_roles, use_panels, library_id, show_deleted ): |
---|
| 2249 | can_access = True |
---|
| 2250 | if isinstance( item, trans.model.HistoryDatasetAssociation ): |
---|
| 2251 | # Make sure the user has the DATASET_ACCESS permission on the history_dataset_association. |
---|
| 2252 | if not item: |
---|
| 2253 | message = "Invalid history dataset (%s) specified." % str( item ) |
---|
| 2254 | can_access = False |
---|
| 2255 | elif not trans.app.security_agent.can_access_dataset( current_user_roles, item.dataset ) and item.history.user==trans.user: |
---|
| 2256 | message = "You do not have permission to access the history dataset with id (%s)." % str( item.id ) |
---|
| 2257 | can_access = False |
---|
| 2258 | else: |
---|
| 2259 | # Make sure the user has the LIBRARY_ACCESS permission on the library item. |
---|
| 2260 | if not item: |
---|
| 2261 | message = "Invalid library item (%s) specified." % str( item ) |
---|
| 2262 | can_access = False |
---|
| 2263 | elif not ( is_admin or trans.app.security_agent.can_access_library_item( current_user_roles, item, trans.user ) ): |
---|
| 2264 | if isinstance( item, trans.model.Library ): |
---|
| 2265 | item_type = 'data library' |
---|
| 2266 | elif isinstance( item, trans.model.LibraryFolder ): |
---|
| 2267 | item_type = 'folder' |
---|
| 2268 | else: |
---|
| 2269 | item_type = '(unknown item type)' |
---|
| 2270 | message = "You do not have permission to access the %s with id (%s)." % ( item_type, str( item.id ) ) |
---|
| 2271 | can_access = False |
---|
| 2272 | if not can_access: |
---|
| 2273 | if cntrller == 'api': |
---|
| 2274 | return 400, message |
---|
| 2275 | if isinstance( item, trans.model.Library ): |
---|
| 2276 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 2277 | action='browse_libraries', |
---|
| 2278 | cntrller=cntrller, |
---|
| 2279 | use_panels=use_panels, |
---|
| 2280 | message=util.sanitize_text( message ), |
---|
| 2281 | status='error' ) ) |
---|
| 2282 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 2283 | action='browse_library', |
---|
| 2284 | cntrller=cntrller, |
---|
| 2285 | use_panels=use_panels, |
---|
| 2286 | id=library_id, |
---|
| 2287 | show_deleted=show_deleted, |
---|
| 2288 | message=util.sanitize_text( message ), |
---|
| 2289 | status='error' ) ) |
---|
| 2290 | def _check_add( self, trans, cntrller, is_admin, item, current_user_roles, use_panels, library_id, show_deleted ): |
---|
| 2291 | # Deny access if the user is not an admin and does not have the LIBRARY_ADD permission. |
---|
| 2292 | if not ( is_admin or trans.app.security_agent.can_add_library_item( current_user_roles, item ) ): |
---|
| 2293 | message = "You are not authorized to add an item to (%s)." % item.name |
---|
| 2294 | # Redirect to the real parent library since we know we have access to it. |
---|
| 2295 | if cntrller == 'api': |
---|
| 2296 | return 403, message |
---|
| 2297 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 2298 | action='browse_library', |
---|
| 2299 | cntrller=cntrller, |
---|
| 2300 | use_panels=use_panels, |
---|
| 2301 | id=library_id, |
---|
| 2302 | show_deleted=show_deleted, |
---|
| 2303 | message=util.sanitize_text( message ), |
---|
| 2304 | status='error' ) ) |
---|
| 2305 | def _check_manage( self, trans, cntrller, is_admin, item, current_user_roles, use_panels, library_id, show_deleted ): |
---|
| 2306 | if isinstance( item, trans.model.LibraryDataset ): |
---|
| 2307 | # Deny access if the user is not an admin and does not have the LIBRARY_MANAGE and DATASET_MANAGE_PERMISSIONS permissions. |
---|
| 2308 | if not ( is_admin or \ |
---|
| 2309 | ( trans.app.security_agent.can_manage_library_item( current_user_roles, item ) and |
---|
| 2310 | trans.app.security_agent.can_manage_dataset( current_user_roles, library_dataset.library_dataset_dataset_association.dataset ) ) ): |
---|
| 2311 | message = "You are not authorized to manage permissions on library dataset (%s)." % library_dataset.name |
---|
| 2312 | if cntrller == 'api': |
---|
| 2313 | return 403, message |
---|
| 2314 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 2315 | action='browse_library', |
---|
| 2316 | id=library_id, |
---|
| 2317 | cntrller=cntrller, |
---|
| 2318 | use_panels=use_panels, |
---|
| 2319 | message=util.sanitize_text( message ), |
---|
| 2320 | status='error' ) ) |
---|
| 2321 | # Deny access if the user is not an admin and does not have the LIBRARY_MANAGE permission. |
---|
| 2322 | if not ( is_admin or trans.app.security_agent.can_manage_library_item( current_user_roles, item ) ): |
---|
| 2323 | message = "You are not authorized to manage permissions on (%s)." % item.name |
---|
| 2324 | if cntrller == 'api': |
---|
| 2325 | return 403, message |
---|
| 2326 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 2327 | action='browse_library', |
---|
| 2328 | id=library_id, |
---|
| 2329 | cntrller=cntrller, |
---|
| 2330 | use_panels=use_panels, |
---|
| 2331 | message=util.sanitize_text( message ), |
---|
| 2332 | status='error' ) ) |
---|
| 2333 | def _check_modify( self, trans, cntrller, is_admin, item, current_user_roles, use_panels, library_id, show_deleted ): |
---|
| 2334 | # Deny modification if the user is not an admin and does not have the LIBRARY_MODIFY permission. |
---|
| 2335 | if not ( is_admin or trans.app.security_agent.can_modify_library_item( current_user_roles, item ) ): |
---|
| 2336 | message = "You are not authorized to modify (%s)." % item.name |
---|
| 2337 | if cntrller == 'api': |
---|
| 2338 | return 403, message |
---|
| 2339 | return trans.response.send_redirect( web.url_for( controller='library_common', |
---|
| 2340 | action='browse_library', |
---|
| 2341 | cntrller=cntrller, |
---|
| 2342 | id=library_id, |
---|
| 2343 | use_panels=use_panels, |
---|
| 2344 | show_deleted=show_deleted, |
---|
| 2345 | message=util.sanitize_text( message ), |
---|
| 2346 | status='error' ) ) |
---|
| 2347 | |
---|
| 2348 | # ---- Utility methods ------------------------------------------------------- |
---|
| 2349 | |
---|
| 2350 | def active_folders( trans, folder ): |
---|
| 2351 | # Much faster way of retrieving all active sub-folders within a given folder than the |
---|
| 2352 | # performance of the mapper. This query also eagerloads the permissions on each folder. |
---|
| 2353 | return trans.sa_session.query( trans.app.model.LibraryFolder ) \ |
---|
| 2354 | .filter_by( parent=folder, deleted=False ) \ |
---|
| 2355 | .options( eagerload_all( "actions" ) ) \ |
---|
| 2356 | .order_by( trans.app.model.LibraryFolder.table.c.name ) \ |
---|
| 2357 | .all() |
---|
| 2358 | def activatable_folders( trans, folder ): |
---|
| 2359 | return trans.sa_session.query( trans.app.model.LibraryFolder ) \ |
---|
| 2360 | .filter_by( parent=folder, purged=False ) \ |
---|
| 2361 | .options( eagerload_all( "actions" ) ) \ |
---|
| 2362 | .order_by( trans.app.model.LibraryFolder.table.c.name ) \ |
---|
| 2363 | .all() |
---|
| 2364 | def active_folders_and_lddas( trans, folder ): |
---|
| 2365 | folders = active_folders( trans, folder ) |
---|
| 2366 | # This query is much faster than the folder.active_library_datasets property |
---|
| 2367 | lddas = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ) \ |
---|
| 2368 | .filter_by( deleted=False ) \ |
---|
| 2369 | .join( "library_dataset" ) \ |
---|
| 2370 | .filter( trans.app.model.LibraryDataset.table.c.folder_id==folder.id ) \ |
---|
| 2371 | .order_by( trans.app.model.LibraryDatasetDatasetAssociation.table.c.name ) \ |
---|
| 2372 | .all() |
---|
| 2373 | return folders, lddas |
---|
| 2374 | def activatable_folders_and_lddas( trans, folder ): |
---|
| 2375 | folders = activatable_folders( trans, folder ) |
---|
| 2376 | # This query is much faster than the folder.activatable_library_datasets property |
---|
| 2377 | lddas = trans.sa_session.query( trans.app.model.LibraryDatasetDatasetAssociation ) \ |
---|
| 2378 | .join( "library_dataset" ) \ |
---|
| 2379 | .filter( trans.app.model.LibraryDataset.table.c.folder_id==folder.id ) \ |
---|
| 2380 | .join( "dataset" ) \ |
---|
| 2381 | .filter( trans.app.model.Dataset.table.c.deleted==False ) \ |
---|
| 2382 | .order_by( trans.app.model.LibraryDatasetDatasetAssociation.table.c.name ) \ |
---|
| 2383 | .all() |
---|
| 2384 | return folders, lddas |
---|
| 2385 | def branch_deleted( folder ): |
---|
| 2386 | # Return True if a folder belongs to a branch that has been deleted |
---|
| 2387 | if folder.deleted: |
---|
| 2388 | return True |
---|
| 2389 | if folder.parent: |
---|
| 2390 | return branch_deleted( folder.parent ) |
---|
| 2391 | return False |
---|
| 2392 | def get_containing_library_from_library_dataset( trans, library_dataset ): |
---|
| 2393 | """Given a library_dataset, get the containing library""" |
---|
| 2394 | folder = library_dataset.folder |
---|
| 2395 | while folder.parent: |
---|
| 2396 | folder = folder.parent |
---|
| 2397 | # We have folder set to the library's root folder, which has the same name as the library |
---|
| 2398 | for library in trans.sa_session.query( trans.model.Library ) \ |
---|
| 2399 | .filter( and_( trans.model.Library.table.c.deleted == False, |
---|
| 2400 | trans.model.Library.table.c.name == folder.name ) ): |
---|
| 2401 | # Just to double-check |
---|
| 2402 | if library.root_folder == folder: |
---|
| 2403 | return library |
---|
| 2404 | return None |
---|