[2] | 1 | import tarfile |
---|
| 2 | from galaxy.web.base.controller import * |
---|
| 3 | from galaxy.webapps.community import model |
---|
| 4 | from galaxy.model.orm import * |
---|
| 5 | from galaxy.web.framework.helpers import time_ago, iff, grids |
---|
| 6 | from galaxy.web.form_builder import SelectField |
---|
| 7 | from galaxy.model.item_attrs import UsesItemRatings |
---|
| 8 | import logging |
---|
| 9 | log = logging.getLogger( __name__ ) |
---|
| 10 | |
---|
| 11 | # States for passing messages |
---|
| 12 | SUCCESS, INFO, WARNING, ERROR = "done", "info", "warning", "error" |
---|
| 13 | |
---|
| 14 | class ItemRatings( UsesItemRatings ): |
---|
| 15 | """Overrides rate_item method since we also allow for comments""" |
---|
| 16 | def rate_item( self, trans, user, item, rating, comment='' ): |
---|
| 17 | """ Rate an item. Return type is <item_class>RatingAssociation. """ |
---|
| 18 | item_rating = self.get_user_item_rating( trans.sa_session, user, item, webapp_model=trans.model ) |
---|
| 19 | if not item_rating: |
---|
| 20 | # User has not yet rated item; create rating. |
---|
| 21 | item_rating_assoc_class = self._get_item_rating_assoc_class( item, webapp_model=trans.model ) |
---|
| 22 | item_rating = item_rating_assoc_class() |
---|
| 23 | item_rating.user = trans.user |
---|
| 24 | item_rating.set_item( item ) |
---|
| 25 | item_rating.rating = rating |
---|
| 26 | item_rating.comment = comment |
---|
| 27 | trans.sa_session.add( item_rating ) |
---|
| 28 | trans.sa_session.flush() |
---|
| 29 | elif item_rating.rating != rating or item_rating.comment != comment: |
---|
| 30 | # User has previously rated item; update rating. |
---|
| 31 | item_rating.rating = rating |
---|
| 32 | item_rating.comment = comment |
---|
| 33 | trans.sa_session.flush() |
---|
| 34 | return item_rating |
---|
| 35 | |
---|
| 36 | class ToolListGrid( grids.Grid ): |
---|
| 37 | class NameColumn( grids.TextColumn ): |
---|
| 38 | def get_value( self, trans, grid, tool ): |
---|
| 39 | return tool.name |
---|
| 40 | class TypeColumn( grids.BooleanColumn ): |
---|
| 41 | def get_value( self, trans, grid, tool ): |
---|
| 42 | if tool.is_suite: |
---|
| 43 | return 'Suite' |
---|
| 44 | return 'Tool' |
---|
| 45 | class VersionColumn( grids.TextColumn ): |
---|
| 46 | def get_value( self, trans, grid, tool ): |
---|
| 47 | return tool.version |
---|
| 48 | class DescriptionColumn( grids.TextColumn ): |
---|
| 49 | def get_value( self, trans, grid, tool ): |
---|
| 50 | return tool.description |
---|
| 51 | class CategoryColumn( grids.TextColumn ): |
---|
| 52 | def get_value( self, trans, grid, tool ): |
---|
| 53 | rval = '<ul>' |
---|
| 54 | if tool.categories: |
---|
| 55 | for tca in tool.categories: |
---|
| 56 | rval += '<li><a href="browse_tools?operation=tools_by_category&id=%s&webapp=community">%s</a></li>' \ |
---|
| 57 | % ( trans.security.encode_id( tca.category.id ), tca.category.name ) |
---|
| 58 | else: |
---|
| 59 | rval += '<li>not set</li>' |
---|
| 60 | rval += '</ul>' |
---|
| 61 | return rval |
---|
| 62 | class ToolCategoryColumn( grids.GridColumn ): |
---|
| 63 | def filter( self, trans, user, query, column_filter ): |
---|
| 64 | """Modify query to filter by category.""" |
---|
| 65 | if column_filter == "All": |
---|
| 66 | pass |
---|
| 67 | return query.filter( model.Category.name == column_filter ) |
---|
| 68 | class UserColumn( grids.TextColumn ): |
---|
| 69 | def get_value( self, trans, grid, tool ): |
---|
| 70 | if tool.user: |
---|
| 71 | return tool.user.username |
---|
| 72 | return 'no user' |
---|
| 73 | class EmailColumn( grids.TextColumn ): |
---|
| 74 | def filter( self, trans, user, query, column_filter ): |
---|
| 75 | if column_filter == 'All': |
---|
| 76 | return query |
---|
| 77 | return query.filter( and_( model.Tool.table.c.user_id == model.User.table.c.id, |
---|
| 78 | model.User.table.c.email == column_filter ) ) |
---|
| 79 | # Grid definition |
---|
| 80 | title = "Tools" |
---|
| 81 | model_class = model.Tool |
---|
| 82 | template='/webapps/community/tool/grid.mako' |
---|
| 83 | default_sort_key = "name" |
---|
| 84 | columns = [ |
---|
| 85 | NameColumn( "Name", |
---|
| 86 | key="Tool.name", |
---|
| 87 | link=( lambda item: dict( operation="view_tool", id=item.id, webapp="community" ) ), |
---|
| 88 | attach_popup=False |
---|
| 89 | ), |
---|
| 90 | TypeColumn( "Type", |
---|
| 91 | key="suite", |
---|
| 92 | attach_popup=False ), |
---|
| 93 | VersionColumn( "Version", |
---|
| 94 | key="version", |
---|
| 95 | attach_popup=False, |
---|
| 96 | filterable="advanced" ), |
---|
| 97 | DescriptionColumn( "Description", |
---|
| 98 | key="description", |
---|
| 99 | attach_popup=False |
---|
| 100 | ), |
---|
| 101 | CategoryColumn( "Category", |
---|
| 102 | model_class=model.Category, |
---|
| 103 | key="Category.name", |
---|
| 104 | attach_popup=False ), |
---|
| 105 | UserColumn( "Uploaded By", |
---|
| 106 | model_class=model.User, |
---|
| 107 | link=( lambda item: dict( operation="tools_by_user", id=item.id, webapp="community" ) ), |
---|
| 108 | attach_popup=False, |
---|
| 109 | key="username" ), |
---|
| 110 | grids.CommunityRatingColumn( "Average Rating", |
---|
| 111 | key="rating" ), |
---|
| 112 | # Columns that are valid for filtering but are not visible. |
---|
| 113 | EmailColumn( "Email", |
---|
| 114 | model_class=model.User, |
---|
| 115 | key="email", |
---|
| 116 | visible=False ), |
---|
| 117 | ToolCategoryColumn( "Category", |
---|
| 118 | model_class=model.Category, |
---|
| 119 | key="Category.name", |
---|
| 120 | visible=False ) |
---|
| 121 | ] |
---|
| 122 | columns.append( grids.MulticolFilterColumn( "Search", |
---|
| 123 | cols_to_filter=[ columns[0], columns[1], columns[2] ], |
---|
| 124 | key="free-text-search", |
---|
| 125 | visible=False, |
---|
| 126 | filterable="standard" ) ) |
---|
| 127 | operations = [] |
---|
| 128 | standard_filters = [] |
---|
| 129 | default_filter = {} |
---|
| 130 | num_rows_per_page = 50 |
---|
| 131 | preserve_state = False |
---|
| 132 | use_paging = True |
---|
| 133 | def build_initial_query( self, trans, **kwd ): |
---|
| 134 | return trans.sa_session.query( self.model_class ) \ |
---|
| 135 | .join( model.User.table ) \ |
---|
| 136 | .join( model.ToolEventAssociation.table ) \ |
---|
| 137 | .join( model.Event.table ) \ |
---|
| 138 | .outerjoin( model.ToolCategoryAssociation.table ) \ |
---|
| 139 | .outerjoin( model.Category.table ) |
---|
| 140 | |
---|
| 141 | class CategoryListGrid( grids.Grid ): |
---|
| 142 | class NameColumn( grids.TextColumn ): |
---|
| 143 | def get_value( self, trans, grid, category ): |
---|
| 144 | return category.name |
---|
| 145 | class DescriptionColumn( grids.TextColumn ): |
---|
| 146 | def get_value( self, trans, grid, category ): |
---|
| 147 | return category.description |
---|
| 148 | class ToolsColumn( grids.TextColumn ): |
---|
| 149 | def get_value( self, trans, grid, category ): |
---|
| 150 | if category.tools: |
---|
| 151 | viewable_tools = 0 |
---|
| 152 | for tca in category.tools: |
---|
| 153 | viewable_tools += 1 |
---|
| 154 | return viewable_tools |
---|
| 155 | return 0 |
---|
| 156 | |
---|
| 157 | # Grid definition |
---|
| 158 | webapp = "community" |
---|
| 159 | title = "Categories" |
---|
| 160 | model_class = model.Category |
---|
| 161 | template='/webapps/community/category/grid.mako' |
---|
| 162 | default_sort_key = "name" |
---|
| 163 | columns = [ |
---|
| 164 | NameColumn( "Name", |
---|
| 165 | key="name", |
---|
| 166 | link=( lambda item: dict( operation="tools_by_category", id=item.id, webapp="community" ) ), |
---|
| 167 | attach_popup=False, |
---|
| 168 | filterable="advanced" |
---|
| 169 | ), |
---|
| 170 | DescriptionColumn( "Description", |
---|
| 171 | key="description", |
---|
| 172 | attach_popup=False, |
---|
| 173 | filterable="advanced" |
---|
| 174 | ), |
---|
| 175 | # Columns that are valid for filtering but are not visible. |
---|
| 176 | grids.DeletedColumn( "Deleted", |
---|
| 177 | key="deleted", |
---|
| 178 | visible=False, |
---|
| 179 | filterable="advanced" ), |
---|
| 180 | ToolsColumn( "Tools", |
---|
| 181 | model_class=model.Tool, |
---|
| 182 | attach_popup=False ) |
---|
| 183 | ] |
---|
| 184 | columns.append( grids.MulticolFilterColumn( "Search", |
---|
| 185 | cols_to_filter=[ columns[0], columns[1] ], |
---|
| 186 | key="free-text-search", |
---|
| 187 | visible=False, |
---|
| 188 | filterable="standard" ) ) |
---|
| 189 | |
---|
| 190 | # Override these |
---|
| 191 | global_actions = [] |
---|
| 192 | operations = [] |
---|
| 193 | standard_filters = [] |
---|
| 194 | num_rows_per_page = 50 |
---|
| 195 | preserve_state = False |
---|
| 196 | use_paging = True |
---|
| 197 | |
---|
| 198 | class CommonController( BaseController, ItemRatings ): |
---|
| 199 | @web.expose |
---|
| 200 | def edit_tool( self, trans, cntrller, **kwd ): |
---|
| 201 | params = util.Params( kwd ) |
---|
| 202 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 203 | status = params.get( 'status', 'done' ) |
---|
| 204 | id = params.get( 'id', None ) |
---|
| 205 | if not id: |
---|
| 206 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 207 | action='browse_tools', |
---|
| 208 | message='Select a tool to edit', |
---|
| 209 | status='error' ) ) |
---|
| 210 | tool = get_tool( trans, id ) |
---|
| 211 | can_edit = trans.app.security_agent.can_edit( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 212 | if not can_edit: |
---|
| 213 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 214 | action='browse_tools', |
---|
| 215 | message='You are not allowed to edit this tool', |
---|
| 216 | status='error' ) ) |
---|
| 217 | if params.get( 'edit_tool_button', False ): |
---|
| 218 | if params.get( 'in_categories', False ): |
---|
| 219 | in_categories = [ trans.sa_session.query( trans.app.model.Category ).get( x ) for x in util.listify( params.in_categories ) ] |
---|
| 220 | trans.app.security_agent.set_entity_category_associations( tools=[ tool ], categories=in_categories ) |
---|
| 221 | else: |
---|
| 222 | # There must not be any categories associated with the tool |
---|
| 223 | trans.app.security_agent.set_entity_category_associations( tools=[ tool ], categories=[] ) |
---|
| 224 | user_description = util.restore_text( params.get( 'user_description', '' ) ) |
---|
| 225 | if user_description: |
---|
| 226 | tool.user_description = user_description |
---|
| 227 | else: |
---|
| 228 | tool.user_description = '' |
---|
| 229 | trans.sa_session.add( tool ) |
---|
| 230 | trans.sa_session.flush() |
---|
| 231 | message = "Tool '%s' description and category associations have been saved" % tool.name |
---|
| 232 | return trans.response.send_redirect( web.url_for( controller='common', |
---|
| 233 | action='edit_tool', |
---|
| 234 | cntrller=cntrller, |
---|
| 235 | id=id, |
---|
| 236 | message=message, |
---|
| 237 | status='done' ) ) |
---|
| 238 | elif params.get( 'approval_button', False ): |
---|
| 239 | user_description = util.restore_text( params.get( 'user_description', '' ) ) |
---|
| 240 | if user_description: |
---|
| 241 | tool.user_description = user_description |
---|
| 242 | if params.get( 'in_categories', False ): |
---|
| 243 | in_categories = [ trans.sa_session.query( trans.app.model.Category ).get( x ) for x in util.listify( params.in_categories ) ] |
---|
| 244 | trans.app.security_agent.set_entity_category_associations( tools=[ tool ], categories=in_categories ) |
---|
| 245 | else: |
---|
| 246 | # There must not be any categories associated with the tool |
---|
| 247 | trans.app.security_agent.set_entity_category_associations( tools=[ tool ], categories=[] ) |
---|
| 248 | trans.sa_session.add( tool ) |
---|
| 249 | trans.sa_session.flush() |
---|
| 250 | # Move the state from NEW to WAITING |
---|
| 251 | event = trans.app.model.Event( state=trans.app.model.Tool.states.WAITING ) |
---|
| 252 | tea = trans.app.model.ToolEventAssociation( tool, event ) |
---|
| 253 | trans.sa_session.add_all( ( event, tea ) ) |
---|
| 254 | trans.sa_session.flush() |
---|
| 255 | message = "Tool '%s' has been submitted for approval and can no longer be modified" % ( tool.name ) |
---|
| 256 | return trans.response.send_redirect( web.url_for( controller='common', |
---|
| 257 | action='view_tool', |
---|
| 258 | cntrller=cntrller, |
---|
| 259 | id=id, |
---|
| 260 | message=message, |
---|
| 261 | status='done' ) ) |
---|
| 262 | else: |
---|
| 263 | # The user_description field is required when submitting for approval |
---|
| 264 | message = 'A user description is required prior to approval.' |
---|
| 265 | status = 'error' |
---|
| 266 | in_categories = [] |
---|
| 267 | out_categories = [] |
---|
| 268 | for category in get_categories( trans ): |
---|
| 269 | if category in [ x.category for x in tool.categories ]: |
---|
| 270 | in_categories.append( ( category.id, category.name ) ) |
---|
| 271 | else: |
---|
| 272 | out_categories.append( ( category.id, category.name ) ) |
---|
| 273 | if tool.is_rejected: |
---|
| 274 | # Include the comments regarding the reason for rejection |
---|
| 275 | reason_for_rejection = tool.latest_event.comment |
---|
| 276 | else: |
---|
| 277 | reason_for_rejection = '' |
---|
| 278 | can_approve_or_reject = trans.app.security_agent.can_approve_or_reject( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 279 | can_delete = trans.app.security_agent.can_delete( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 280 | can_download = trans.app.security_agent.can_download( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 281 | can_purge = trans.app.security_agent.can_purge( trans.user, trans.user_is_admin(), cntrller ) |
---|
| 282 | can_upload_new_version = trans.app.security_agent.can_upload_new_version( trans.user, tool ) |
---|
| 283 | can_view = trans.app.security_agent.can_view( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 284 | return trans.fill_template( '/webapps/community/tool/edit_tool.mako', |
---|
| 285 | cntrller=cntrller, |
---|
| 286 | tool=tool, |
---|
| 287 | id=id, |
---|
| 288 | in_categories=in_categories, |
---|
| 289 | out_categories=out_categories, |
---|
| 290 | can_approve_or_reject=can_approve_or_reject, |
---|
| 291 | can_delete=can_delete, |
---|
| 292 | can_download=can_download, |
---|
| 293 | can_edit=can_edit, |
---|
| 294 | can_purge=can_purge, |
---|
| 295 | can_upload_new_version=can_upload_new_version, |
---|
| 296 | can_view=can_view, |
---|
| 297 | reason_for_rejection=reason_for_rejection, |
---|
| 298 | message=message, |
---|
| 299 | status=status ) |
---|
| 300 | @web.expose |
---|
| 301 | def view_tool( self, trans, cntrller, **kwd ): |
---|
| 302 | params = util.Params( kwd ) |
---|
| 303 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 304 | status = params.get( 'status', 'done' ) |
---|
| 305 | id = params.get( 'id', None ) |
---|
| 306 | if not id: |
---|
| 307 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 308 | action='browse_tools', |
---|
| 309 | message='Select a tool to view', |
---|
| 310 | status='error' ) ) |
---|
| 311 | tool = get_tool( trans, id ) |
---|
| 312 | can_view = trans.app.security_agent.can_view( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 313 | if not can_view: |
---|
| 314 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 315 | action='browse_tools', |
---|
| 316 | message='You are not allowed to view this tool', |
---|
| 317 | status='error' ) ) |
---|
| 318 | avg_rating, num_ratings = self.get_ave_item_rating_data( trans.sa_session, tool, webapp_model=trans.model ) |
---|
| 319 | can_approve_or_reject = trans.app.security_agent.can_approve_or_reject( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 320 | can_delete = trans.app.security_agent.can_delete( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 321 | can_download = trans.app.security_agent.can_download( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 322 | can_edit = trans.app.security_agent.can_edit( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 323 | can_purge = trans.app.security_agent.can_purge( trans.user, trans.user_is_admin(), cntrller ) |
---|
| 324 | can_rate = trans.app.security_agent.can_rate( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 325 | can_upload_new_version = trans.app.security_agent.can_upload_new_version( trans.user, tool ) |
---|
| 326 | categories = [ tca.category for tca in tool.categories ] |
---|
| 327 | display_reviews = util.string_as_bool( params.get( 'display_reviews', False ) ) |
---|
| 328 | tool_file_contents = tarfile.open( tool.file_name, 'r' ).getnames() |
---|
| 329 | tra = self.get_user_item_rating( trans.sa_session, trans.user, tool, webapp_model=trans.model ) |
---|
| 330 | visible_versions = trans.app.security_agent.get_visible_versions( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 331 | if tool.is_rejected: |
---|
| 332 | # Include the comments regarding the reason for rejection |
---|
| 333 | reason_for_rejection = tool.latest_event.comment |
---|
| 334 | else: |
---|
| 335 | reason_for_rejection = '' |
---|
| 336 | return trans.fill_template( '/webapps/community/tool/view_tool.mako', |
---|
| 337 | avg_rating=avg_rating, |
---|
| 338 | categories=categories, |
---|
| 339 | can_approve_or_reject=can_approve_or_reject, |
---|
| 340 | can_delete=can_delete, |
---|
| 341 | can_download=can_download, |
---|
| 342 | can_edit=can_edit, |
---|
| 343 | can_purge=can_purge, |
---|
| 344 | can_rate=can_rate, |
---|
| 345 | can_upload_new_version=can_upload_new_version, |
---|
| 346 | can_view=can_view, |
---|
| 347 | cntrller=cntrller, |
---|
| 348 | display_reviews=display_reviews, |
---|
| 349 | num_ratings=num_ratings, |
---|
| 350 | reason_for_rejection=reason_for_rejection, |
---|
| 351 | tool=tool, |
---|
| 352 | tool_file_contents=tool_file_contents, |
---|
| 353 | tra=tra, |
---|
| 354 | visible_versions=visible_versions, |
---|
| 355 | message=message, |
---|
| 356 | status=status ) |
---|
| 357 | @web.expose |
---|
| 358 | def delete_tool( self, trans, cntrller, **kwd ): |
---|
| 359 | params = util.Params( kwd ) |
---|
| 360 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 361 | status = params.get( 'status', 'done' ) |
---|
| 362 | id = params.get( 'id', None ) |
---|
| 363 | if not id: |
---|
| 364 | message='Select a tool to delete' |
---|
| 365 | status='error' |
---|
| 366 | else: |
---|
| 367 | tool = get_tool( trans, id ) |
---|
| 368 | if not trans.app.security_agent.can_delete( trans.user, trans.user_is_admin(), cntrller, tool ): |
---|
| 369 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 370 | action='browse_tools', |
---|
| 371 | message='You are not allowed to delete this tool', |
---|
| 372 | status='error' ) ) |
---|
| 373 | # Create a new event |
---|
| 374 | event = trans.model.Event( state=trans.model.Tool.states.DELETED ) |
---|
| 375 | # Flush so we can get an event id |
---|
| 376 | trans.sa_session.add( event ) |
---|
| 377 | trans.sa_session.flush() |
---|
| 378 | # Associate the tool with the event |
---|
| 379 | tea = trans.model.ToolEventAssociation( tool=tool, event=event ) |
---|
| 380 | # Delete the tool, keeping state for categories, events and versions |
---|
| 381 | tool.deleted = True |
---|
| 382 | trans.sa_session.add_all( ( tool, tea ) ) |
---|
| 383 | trans.sa_session.flush() |
---|
| 384 | # TODO: What if the tool has versions, should they all be deleted? |
---|
| 385 | message = "Tool '%s' has been marked deleted" % tool.name |
---|
| 386 | status = 'done' |
---|
| 387 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 388 | action='browse_tools', |
---|
| 389 | message=message, |
---|
| 390 | status=status ) ) |
---|
| 391 | @web.expose |
---|
| 392 | def download_tool( self, trans, cntrller, **kwd ): |
---|
| 393 | params = util.Params( kwd ) |
---|
| 394 | id = params.get( 'id', None ) |
---|
| 395 | if not id: |
---|
| 396 | return trans.response.send_redirect( web.url_for( controller='tool', |
---|
| 397 | action='browse_tools', |
---|
| 398 | message='Select a tool to download', |
---|
| 399 | status='error' ) ) |
---|
| 400 | tool = get_tool( trans, id ) |
---|
| 401 | if not trans.app.security_agent.can_download( trans.user, trans.user_is_admin(), cntrller, tool ): |
---|
| 402 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 403 | action='browse_tools', |
---|
| 404 | message='You are not allowed to download this tool', |
---|
| 405 | status='error' ) ) |
---|
| 406 | trans.response.set_content_type( tool.mimetype ) |
---|
| 407 | trans.response.headers['Content-Length'] = int( os.stat( tool.file_name ).st_size ) |
---|
| 408 | trans.response.headers['Content-Disposition'] = 'attachment; filename=%s' % tool.download_file_name |
---|
| 409 | return open( tool.file_name ) |
---|
| 410 | @web.expose |
---|
| 411 | def upload_new_tool_version( self, trans, cntrller, **kwd ): |
---|
| 412 | params = util.Params( kwd ) |
---|
| 413 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 414 | status = params.get( 'status', 'done' ) |
---|
| 415 | id = params.get( 'id', None ) |
---|
| 416 | if not id: |
---|
| 417 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 418 | action='browse_tools', |
---|
| 419 | message='Select a tool to upload a new version', |
---|
| 420 | status='error' ) ) |
---|
| 421 | tool = get_tool( trans, id ) |
---|
| 422 | if not trans.app.security_agent.can_upload_new_version( trans.user, tool ): |
---|
| 423 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 424 | action='browse_tools', |
---|
| 425 | message='You are not allowed to upload a new version of this tool', |
---|
| 426 | status='error' ) ) |
---|
| 427 | return trans.response.send_redirect( web.url_for( controller='upload', |
---|
| 428 | action='upload', |
---|
| 429 | message=message, |
---|
| 430 | status=status, |
---|
| 431 | replace_id=id ) ) |
---|
| 432 | @web.expose |
---|
| 433 | @web.require_login( "view tool history" ) |
---|
| 434 | def view_tool_history( self, trans, cntrller, **kwd ): |
---|
| 435 | params = util.Params( kwd ) |
---|
| 436 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 437 | status = params.get( 'status', 'done' ) |
---|
| 438 | id = params.get( 'id', None ) |
---|
| 439 | if not id: |
---|
| 440 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 441 | action='browse_tools', |
---|
| 442 | message='Select a tool to view its history', |
---|
| 443 | status='error' ) ) |
---|
| 444 | tool = get_tool( trans, id ) |
---|
| 445 | can_view = trans.app.security_agent.can_view( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 446 | if not can_view: |
---|
| 447 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 448 | action='browse_tools', |
---|
| 449 | message="You are not allowed to view this tool's history", |
---|
| 450 | status='error' ) ) |
---|
| 451 | can_approve_or_reject = trans.app.security_agent.can_approve_or_reject( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 452 | can_edit = trans.app.security_agent.can_edit( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 453 | can_delete = trans.app.security_agent.can_delete( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 454 | can_download = trans.app.security_agent.can_download( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 455 | events = [ tea.event for tea in tool.events ] |
---|
| 456 | events = [ ( event.state, time_ago( event.update_time ), event.comment ) for event in events ] |
---|
| 457 | return trans.fill_template( '/webapps/community/common/view_tool_history.mako', |
---|
| 458 | cntrller=cntrller, |
---|
| 459 | events=events, |
---|
| 460 | tool=tool, |
---|
| 461 | can_approve_or_reject=can_approve_or_reject, |
---|
| 462 | can_edit=can_edit, |
---|
| 463 | can_delete=can_delete, |
---|
| 464 | can_download=can_download, |
---|
| 465 | can_view=can_view, |
---|
| 466 | message=message, |
---|
| 467 | status=status ) |
---|
| 468 | @web.expose |
---|
| 469 | @web.require_login( "rate tools" ) |
---|
| 470 | def rate_tool( self, trans, cntrller, **kwd ): |
---|
| 471 | """ Rate a tool and return updated rating data. """ |
---|
| 472 | params = util.Params( kwd ) |
---|
| 473 | message = util.restore_text( params.get( 'message', '' ) ) |
---|
| 474 | status = params.get( 'status', 'done' ) |
---|
| 475 | id = params.get( 'id', None ) |
---|
| 476 | if not id: |
---|
| 477 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 478 | action='browse_tools', |
---|
| 479 | message='Select a tool to rate', |
---|
| 480 | status='error' ) ) |
---|
| 481 | tool = get_tool( trans, id ) |
---|
| 482 | can_rate = trans.app.security_agent.can_rate( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 483 | if not can_rate: |
---|
| 484 | return trans.response.send_redirect( web.url_for( controller=cntrller, |
---|
| 485 | action='browse_tools', |
---|
| 486 | message="You are not allowed to rate this tool", |
---|
| 487 | status='error' ) ) |
---|
| 488 | if params.get( 'rate_button', False ): |
---|
| 489 | rating = int( params.get( 'rating', '0' ) ) |
---|
| 490 | comment = util.restore_text( params.get( 'comment', '' ) ) |
---|
| 491 | rating = self.rate_item( trans, trans.user, tool, rating, comment ) |
---|
| 492 | avg_rating, num_ratings = self.get_ave_item_rating_data( trans.sa_session, tool, webapp_model=trans.model ) |
---|
| 493 | can_approve_or_reject = trans.app.security_agent.can_approve_or_reject( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 494 | can_edit = trans.app.security_agent.can_edit( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 495 | can_delete = trans.app.security_agent.can_delete( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 496 | can_download = trans.app.security_agent.can_download( trans.user, trans.user_is_admin(), cntrller, tool ) |
---|
| 497 | display_reviews = util.string_as_bool( params.get( 'display_reviews', False ) ) |
---|
| 498 | tra = self.get_user_item_rating( trans.sa_session, trans.user, tool, webapp_model=trans.model ) |
---|
| 499 | return trans.fill_template( '/webapps/community/common/rate_tool.mako', |
---|
| 500 | cntrller=cntrller, |
---|
| 501 | tool=tool, |
---|
| 502 | avg_rating=avg_rating, |
---|
| 503 | can_approve_or_reject=can_approve_or_reject, |
---|
| 504 | can_edit=can_edit, |
---|
| 505 | can_delete=can_delete, |
---|
| 506 | can_download=can_download, |
---|
| 507 | can_rate=can_rate, |
---|
| 508 | display_reviews=display_reviews, |
---|
| 509 | num_ratings=num_ratings, |
---|
| 510 | tra=tra, |
---|
| 511 | message=message, |
---|
| 512 | status=status ) |
---|
| 513 | |
---|
| 514 | ## ---- Utility methods ------------------------------------------------------- |
---|
| 515 | |
---|
| 516 | def get_versions( item ): |
---|
| 517 | """Get all versions of item""" |
---|
| 518 | versions = [ item ] |
---|
| 519 | this_item = item |
---|
| 520 | while item.newer_version: |
---|
| 521 | versions.insert( 0, item.newer_version ) |
---|
| 522 | item = item.newer_version |
---|
| 523 | item = this_item |
---|
| 524 | while item.older_version: |
---|
| 525 | versions.append( item.older_version[ 0 ] ) |
---|
| 526 | item = item.older_version[ 0 ] |
---|
| 527 | return versions |
---|
| 528 | def get_categories( trans ): |
---|
| 529 | """Get all categories from the database""" |
---|
| 530 | return trans.sa_session.query( trans.model.Category ) \ |
---|
| 531 | .filter( trans.model.Category.table.c.deleted==False ) \ |
---|
| 532 | .order_by( trans.model.Category.table.c.name ).all() |
---|
| 533 | def get_category( trans, id ): |
---|
| 534 | """Get a category from the database""" |
---|
| 535 | return trans.sa_session.query( trans.model.Category ).get( trans.security.decode_id( id ) ) |
---|
| 536 | def get_tool( trans, id ): |
---|
| 537 | """Get a tool from the database""" |
---|
| 538 | return trans.sa_session.query( trans.model.Tool ).get( trans.security.decode_id( id ) ) |
---|
| 539 | def get_latest_versions_of_tools( trans ): |
---|
| 540 | """Get only the latest version of each tool from the database""" |
---|
| 541 | return trans.sa_session.query( trans.model.Tool ) \ |
---|
| 542 | .filter( trans.model.Tool.newer_version_id == None ) \ |
---|
| 543 | .order_by( trans.model.Tool.name ) |
---|
| 544 | def get_approved_tools( trans ): |
---|
| 545 | """Get the tools from the database whose state is APPROVED""" |
---|
| 546 | approved_tools = [] |
---|
| 547 | for tool in get_latest_versions_of_tools( trans ): |
---|
| 548 | if tool.state == trans.model.Tool.states.APPROVED: |
---|
| 549 | approved_tools.append( tool ) |
---|
| 550 | return approved_tools |
---|
| 551 | def get_event( trans, id ): |
---|
| 552 | """Get an event from the databse""" |
---|
| 553 | return trans.sa_session.query( trans.model.Event ).get( trans.security.decode_id( id ) ) |
---|
| 554 | def get_user( trans, id ): |
---|
| 555 | """Get a user from the database""" |
---|
| 556 | return trans.sa_session.query( trans.model.User ).get( trans.security.decode_id( id ) ) |
---|