Merge pull request #4512 from martenson/improving-datalibraries

A round of data libraries improvements.
This commit is contained in:
John Chilton
2017-09-04 00:21:51 -04:00
committed by GitHub
22 changed files with 511 additions and 383 deletions
+1 -1
View File
@@ -101,7 +101,7 @@ lib/galaxy/webapps/galaxy/api/genomes.py
lib/galaxy/webapps/galaxy/api/histories.py
lib/galaxy/webapps/galaxy/api/__init__.py
lib/galaxy/webapps/galaxy/api/jobs.py
lib/galaxy/webapps/galaxy/api/lda_datasets.py
lib/galaxy/webapps/galaxy/api/library_datasets.py
lib/galaxy/webapps/galaxy/api/requests.py
lib/galaxy/webapps/galaxy/api/roles.py
lib/galaxy/webapps/galaxy/api/samples.py
@@ -16,8 +16,10 @@ var LibraryDatasetView = Backbone.View.extend({
model: null,
options: {
options: {},
defaults: {
edit_mode: false
},
events: {
@@ -25,13 +27,11 @@ var LibraryDatasetView = Backbone.View.extend({
"click .toolbtn_cancel_modifications" : "render",
"click .toolbtn-download-dataset" : "downloadDataset",
"click .toolbtn-import-dataset" : "importIntoHistory",
"click .toolbtn-share-dataset" : "shareDataset",
"click .btn-copy-link-to-clipboard" : "copyToClipboard",
"click .btn-make-private" : "makeDatasetPrivate",
"click .btn-remove-restrictions" : "removeDatasetRestrictions",
"click .toolbtn_save_permissions" : "savePermissions",
"click .toolbtn_save_modifications" : "comingSoon",
"click .toolbtn_save_modifications" : "saveModifications"
},
// genome select
@@ -134,7 +134,10 @@ var LibraryDatasetView = Backbone.View.extend({
$(".tooltip").remove();
var template = this.templateModifyDataset();
this.$el.html(template({item: this.model}));
this.renderSelectBoxes({genome_build: this.model.get('genome_build'), file_ext: this.model.get('file_ext') });
this.renderSelectBoxes({
genome_build: this.model.get('genome_build'),
file_ext: this.model.get('file_ext')
});
$(".peek").html(this.model.get("peek"));
$("#center [data-toggle]").tooltip();
},
@@ -245,10 +248,6 @@ var LibraryDatasetView = Backbone.View.extend({
});
},
shareDataset: function(){
mod_toastr.info('Feature coming soon.');
},
goBack: function(){
Galaxy.libraries.library_router.back();
},
@@ -457,8 +456,57 @@ var LibraryDatasetView = Backbone.View.extend({
}
},
comingSoon: function(){
mod_toastr.warning('Feature coming soon.');
/**
* Save the changes made to the library dataset.
*/
saveModifications: function(options){
var is_changed = false;
var ld = this.model;
var new_name = this.$el.find('.input_dataset_name').val();
if (typeof new_name !== 'undefined' && new_name !== ld.get('name') ){
if (new_name.length > 0){
ld.set("name", new_name);
is_changed = true;
} else{
mod_toastr.warning('Library dataset name has to be at least 1 character long.');
return;
}
}
var new_info = this.$el.find('.input_dataset_misc_info').val();
if (typeof new_info !== 'undefined' && new_info !== ld.get('misc_info') ){
ld.set("misc_info", new_info);
is_changed = true;
}
var new_genome_build = this.select_genome.$el.select2('data').id;
if (typeof new_genome_build !== 'undefined' && new_genome_build !== ld.get('genome_build') ){
ld.set("genome_build", new_genome_build);
is_changed = true;
}
var new_ext = this.select_extension.$el.select2('data').id;
if (typeof new_ext !== 'undefined' && new_ext !== ld.get('file_ext') ){
ld.set("file_ext", new_ext);
is_changed = true;
}
var dataset_view = this;
if (is_changed){
ld.save(null, {
patch: true,
success: function(ld) {
dataset_view.render()
mod_toastr.success('Changes to library dataset saved.');
},
error: function(model, response){
if (typeof response.responseJSON !== "undefined"){
mod_toastr.error(response.responseJSON.err_msg);
} else {
mod_toastr.error('An error occured while attempting to update the library dataset.');
}
}
});
} else {
dataset_view.render()
mod_toastr.info('Nothing has changed.');
}
},
copyToClipboard: function(){
@@ -523,42 +571,46 @@ var LibraryDatasetView = Backbone.View.extend({
},
/**
* Request all extensions and genomes from Galaxy
* and save them sorted in arrays.
* If needed request all extensions and/or genomes from Galaxy
* and save them in sorted arrays.
*/
fetchExtAndGenomes: function(){
var that = this;
mod_utils.get({
url : Galaxy.root + "api/datatypes?extension_only=False",
success : function( datatypes ) {
for (var key in datatypes) {
that.list_extensions.push({
id : datatypes[key].extension,
text : datatypes[key].extension,
description : datatypes[key].description,
description_url : datatypes[key].description_url
});
}
that.list_extensions.sort(function(a, b) {
return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
});
that.list_extensions.unshift(that.auto);
}
if (this.list_genomes.length == 0){
mod_utils.get({
url : Galaxy.root + "api/datatypes?extension_only=False",
success : function( datatypes ) {
for (var key in datatypes) {
that.list_extensions.push({
id : datatypes[key].extension,
text : datatypes[key].extension,
description : datatypes[key].description,
description_url : datatypes[key].description_url
});
}
that.list_extensions.sort(function(a, b) {
return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
});
that.list_extensions.unshift(that.auto);
}
});
mod_utils.get({
url : Galaxy.root + "api/genomes",
}
if (this.list_extensions.length == 0){
mod_utils.get({
url : Galaxy.root + "api/genomes",
success : function( genomes ) {
for (var key in genomes ) {
that.list_genomes.push({
id : genomes[key][1],
text : genomes[key][0]
});
}
that.list_genomes.sort(function(a, b) {
return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
});
}
});
for (var key in genomes ) {
that.list_genomes.push({
id : genomes[key][1],
text : genomes[key][0]
});
}
that.list_genomes.sort(function(a, b) {
return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
});
}
});
}
},
renderSelectBoxes: function(options){
@@ -566,6 +618,7 @@ var LibraryDatasetView = Backbone.View.extend({
// See this.fetchExtAndGenomes()
// TODO switch to common resources:
// https://trello.com/c/dIUE9YPl/1933-ui-common-resources-and-data-into-galaxy-object
var that = this;
var current_genome = '?';
var current_ext = 'auto';
if (typeof options !== 'undefined'){
@@ -576,17 +629,16 @@ var LibraryDatasetView = Backbone.View.extend({
current_ext = options.file_ext;
}
}
var that = this;
this.select_genome = new mod_select.View( {
css: 'dataset-genome-select',
data: that.list_genomes,
container: that.$el.find( '#dataset_genome_select' ),
container: that.$el.find('#dataset_genome_select'),
value: current_genome
} );
this.select_extension = new mod_select.View({
css: 'dataset-extension-select',
data: that.list_extensions,
container: that.$el.find( '#dataset_extension_select' ),
container: that.$el.find('#dataset_extension_select'),
value: current_ext
});
},
@@ -711,13 +763,13 @@ var LibraryDatasetView = Backbone.View.extend({
'<% } %>',
'<% if (item.get("misc_blurb")) { %>',
'<tr>',
'<th scope="row">Miscellaneous blurb</th>',
'<th scope="row">Misc. blurb</th>',
'<td scope="row"><%= _.escape(item.get("misc_blurb")) %></td>',
'</tr>',
'<% } %>',
'<% if (item.get("misc_info")) { %>',
'<tr>',
'<th scope="row">Miscellaneous information</th>',
'<th scope="row">Misc. info</th>',
'<td scope="row"><%= _.escape(item.get("misc_info")) %></td>',
'</tr>',
'<% } %>',
@@ -902,7 +954,6 @@ var LibraryDatasetView = Backbone.View.extend({
'</ol>',
'<div class="dataset_table">',
'<p>For full editing options please import the dataset to history and use "Edit attributes" on it.</p>',
'<table class="grid table table-striped table-condensed">',
'<tr>',
'<th class="dataset-first-column" scope="row" id="id_row" data-id="<%= _.escape(item.get("ldda_id")) %>">Name</th>',
@@ -956,12 +1007,12 @@ var LibraryDatasetView = Backbone.View.extend({
'<td scope="row"><%= _.escape(item.get("message")) %></td>',
'</tr>',
'<tr>',
'<th scope="row">Miscellaneous information</th>',
'<td scope="row"><%= _.escape(item.get("misc_info")) %></td>',
'<th scope="row">Misc. blurb</th>',
'<td scope="row"><%= _.escape(item.get("misc_blurb")) %></td>',
'</tr>',
'<tr>',
'<th scope="row">Miscellaneous blurb</th>',
'<td scope="row"><%= _.escape(item.get("misc_blurb")) %></td>',
'<th scope="row">Misc. information</th>',
'<td><input class="input_dataset_misc_info form-control" type="text" placeholder="info" value="<%= _.escape(item.get("misc_info")) %>"></td>',
'</tr>',
//TODO: add functionality to modify tags here
'<% if (item.get("tags")) { %>',
@@ -37,8 +37,6 @@ var FolderView = Backbone.View.extend({
success: function() {
if (that.options.show_permissions){
that.showPermissions();
} else {
that.render();
}
},
error: function(model, response){
@@ -51,19 +49,6 @@ var FolderView = Backbone.View.extend({
});
},
render: function(options){
$(".tooltip").remove();
this.options = _.extend(this.options, options);
var template = this.templateFolder();
this.$el.html(template({item: this.model}));
$(".peek").html(this.model.get("peek"));
$("#center [data-toggle]").tooltip();
},
shareFolder: function(){
mod_toastr.info('Feature coming soon.');
},
goBack: function(){
Galaxy.libraries.library_router.back();
},
@@ -165,18 +150,6 @@ var FolderView = Backbone.View.extend({
return select_options;
},
comingSoon: function(){
mod_toastr.warning('Feature coming soon.');
},
copyToClipboard: function(){
var href = Backbone.history.location.href;
if (href.lastIndexOf('/permissions') !== -1){
href = href.substr(0, href.lastIndexOf('/permissions'));
}
window.prompt("Copy to clipboard: Ctrl+C, Enter", href);
},
/**
* Extract the role ids from Select2 elements's 'data'
*/
@@ -206,57 +179,6 @@ var FolderView = Backbone.View.extend({
})
},
templateFolder : function(){
return _.template([
'<div class="library_style_container">',
'<div id="library_toolbar">',
'<button data-toggle="tooltip" data-placement="top" title="Modify library item" class="btn btn-default toolbtn_modify_dataset primary-button" type="button">',
'<span class="fa fa-pencil"/>',
'&nbsp;Modify',
'</button>',
'<a href="#folders/<%- item.get("folder_id") %>/datasets/<%- item.id %>/permissions">',
'<button data-toggle="tooltip" data-placement="top" title="Manage permissions" class="btn btn-default toolbtn_change_permissions primary-button" type="button">',
'<span class="fa fa-group"/>',
'&nbsp;Permissions',
'</button>',
'</a>',
'<button data-toggle="tooltip" data-placement="top" title="Share dataset" class="btn btn-default toolbtn-share-dataset primary-button" type="button">',
'<span class="fa fa-share"/>',
'&nbsp;Share',
'</span>',
'</button>',
'</div>',
'<p>',
'This dataset is unrestricted so everybody can access it. Just share the URL of this page. ',
'<button data-toggle="tooltip" data-placement="top" title="Copy to clipboard" class="btn btn-default btn-copy-link-to-clipboard primary-button" type="button">',
'<span class="fa fa-clipboard"/>',
'&nbsp;To Clipboard',
'</button> ',
'</p>',
'<div class="dataset_table">',
'<table class="grid table table-striped table-condensed">',
'<tr>',
'<th scope="row" id="id_row" data-id="<%= _.escape(item.get("ldda_id")) %>">',
'Name',
'</th>',
'<td>',
'<%= _.escape(item.get("name")) %>',
'</td>',
'</tr>',
'<% if (item.get("file_ext")) { %>',
'<tr>',
'<th scope="row">Data type</th>',
'<td>',
'<%= _.escape(item.get("file_ext")) %>',
'</td>',
'</tr>',
'<% } %>',
'</table>',
'</div>',
'</div>'
].join(''));
},
templateFolderPermissions : function(){
return _.template([
'<div class="library_style_container">',
@@ -375,7 +375,7 @@ var FolderToolbarView = Backbone.View.extend({
var folder_name = self.options.full_path[self.options.full_path.length - 1][1]
self.modal.show({
closing_events : true,
title : 'Adding datasets from your history to folder ' + folder_name,
title : 'Adding datasets from your history to ' + folder_name,
body : template_modal({histories: self.histories.models}),
buttons : {
'Add' : function() {self.addAllDatasetsFromHistory();},
@@ -721,6 +721,12 @@ var FolderToolbarView = Backbone.View.extend({
var history_contents_template = self.templateHistoryContents();
self.histories.get(history_id).set({'contents' : history_contents});
self.modal.$el.find('#selected_history_content').html(history_contents_template({history_contents: history_contents.models.reverse()}));
self.modal.$el.find('.history-import-select-all').bind("click", function(){
$('#selected_history_content [type=checkbox]').prop('checked', true);
});
self.modal.$el.find('.history-import-unselect-all').bind("click", function(){
$('#selected_history_content [type=checkbox]').prop('checked', false);
});
},
error: function(model, response){
if (typeof response.responseJSON !== "undefined"){
@@ -745,9 +751,9 @@ var FolderToolbarView = Backbone.View.extend({
} else {
this.modal.disableButton( 'Add' );
checked_hdas.each(function(){
var hid = $( this.parentElement ).data( 'id' );
var hid = $( this.parentElement.parentElement ).data( 'id' );
if ( hid ) {
var item_type = $( this.parentElement ).data( 'name' );
var item_type = $( this.parentElement.parentElement ).data( 'name' );
history_item_ids.push( hid );
history_item_types.push( item_type );
}
@@ -1162,7 +1168,7 @@ var FolderToolbarView = Backbone.View.extend({
'<span class="fa fa-info-circle"></span>',
'&nbsp;Details',
'</button>',
'<span class="help-button" data-toggle="tooltip" data-placement="top" title="Visit Libraries Wiki">',
'<span class="help-button" data-toggle="tooltip" data-placement="top" title="See this screen annotated">',
'<a href="https://galaxyproject.org/data-libraries/screen/folder-contents/" target="_blank">',
'<button class="primary-button" type="button">',
'<span class="fa fa-question-circle"></span>',
@@ -1413,27 +1419,42 @@ var FolderToolbarView = Backbone.View.extend({
'<ul>',
'<% _.each(history_contents, function(history_item) { %>',
'<% if (history_item.get("deleted") != true ) { %>',
'<% var item_name = history_item.get("name") %>',
'<% if (history_item.get("type") === "collection") { %>',
'<% var collection_type = history_item.get("collection_type") %>',
'<% if (collection_type === "list") { %>',
'<li data-id="<%= _.escape(history_item.get("id")) %>" data-name="<%= _.escape(history_item.get("type")) %>">',
'<input style="margin: 0;" type="checkbox"> <%= _.escape(history_item.get("hid")) %>: <%= _.escape(history_item.get("name")) %> (Dataset Collection)',
'<label>',
'<label title="<%= _.escape(item_name) %>">',
'<input style="margin: 0;" type="checkbox"> <%= _.escape(history_item.get("hid")) %>: ',
'<%= item_name.length > 75 ? _.escape("...".concat(item_name.substr(-75))) : _.escape(item_name) %> (Dataset Collection)',
'</label>',
'</li>',
'<% } else { %>',
'<li><input style="margin: 0;" type="checkbox" onclick="return false;" disabled="disabled">',
'<span title="You can convert this collection into a collection of type list using the Collection Tools">',
' <%= _.escape(history_item.get("hid")) %>: <%= _.escape(history_item.get("name")) %> (Dataset Collection of type <%= _.escape(collection_type) %> not supported.)',
'<%= _.escape(history_item.get("hid")) %>: ',
'<%= item_name.length > 75 ? _.escape("...".concat(item_name.substr(-75))) : _.escape(item_name) %> (Dataset Collection of type <%= _.escape(collection_type) %> not supported.)',
'</span>',
'</li>',
'<% } %>',
'<% } else if (history_item.get("visible") === true && history_item.get("state") === "ok") { %>',
'<li data-id="<%= _.escape(history_item.get("id")) %>" data-name="<%= _.escape(history_item.get("type")) %>">',
'<input style="margin: 0;" type="checkbox"> <%= _.escape(history_item.get("hid")) %>: <%= _.escape(history_item.get("name")) %>',
'<label title="<%= _.escape(item_name) %>">',
'<input style="margin: 0;" type="checkbox"> <%= _.escape(history_item.get("hid")) %>: ',
'<%= item_name.length > 75 ? _.escape("...".concat(item_name.substr(-75))) : _.escape(item_name) %>',
'</label>',
'</li>',
'<% } %>',
'<% } %>',
'<% }); %>',
'</ul>'
'</ul>',
'<button title="Select all datasets" type="button" class="button primary-button history-import-select-all">',
'Select all',
'</button>',
'<button title="Select all datasets" type="button" class="button primary-button history-import-unselect-all">',
'Unselect all',
'</button>'
].join(''));
},
@@ -37,8 +37,6 @@ var LibraryView = Backbone.View.extend({
success: function() {
if (that.options.show_permissions){
that.showPermissions();
} else {
that.render();
}
},
error: function(model, response){
@@ -51,18 +49,6 @@ var LibraryView = Backbone.View.extend({
});
},
render: function(options){
$(".tooltip").remove();
this.options = _.extend(this.options, options);
var template = this.templateLibrary();
this.$el.html(template({item: this.model}));
$("#center [data-toggle]").tooltip();
},
shareDataset: function(){
mod_toastr.info('Feature coming soon.');
},
goBack: function(){
Galaxy.libraries.library_router.back();
},
@@ -175,18 +161,6 @@ var LibraryView = Backbone.View.extend({
return select_options;
},
comingSoon: function(){
mod_toastr.warning('Feature coming soon.');
},
copyToClipboard: function(){
var href = Backbone.history.location.href;
if (href.lastIndexOf('/permissions') !== -1){
href = href.substr(0, href.lastIndexOf('/permissions'));
}
window.prompt("Copy to clipboard: Ctrl+C, Enter", href);
},
makeDatasetPrivate: function(){
var self = this;
$.post( Galaxy.root + "api/libraries/datasets/" + self.id + "/permissions?action=make_private").done(function(fetched_permissions) {
@@ -237,56 +211,6 @@ var LibraryView = Backbone.View.extend({
})
},
templateLibrary : function(){
return _.template([
'<div class="library_style_container">',
'<div id="library_toolbar">',
'<button data-toggle="tooltip" data-placement="top" title="Modify library item" class="btn btn-default toolbtn_modify_dataset primary-button" type="button">',
'<span class="fa fa-pencil"/>',
'&nbsp;Modify',
'</button>',
'<a href="#folders/<%- item.get("folder_id") %>/datasets/<%- item.id %>/permissions">',
'<button data-toggle="tooltip" data-placement="top" title="Manage permissions" class="btn btn-default toolbtn_change_permissions primary-button" type="button">',
'<span class="fa fa-group"/>',
'&nbsp;Permissions',
'</button>',
'</a>',
'<button data-toggle="tooltip" data-placement="top" title="Share dataset" class="btn btn-default toolbtn-share-dataset primary-button" type="button">',
'<span class="fa fa-share"/>',
'&nbsp;Share',
'</button>',
'</div>',
'<p>',
'This dataset is unrestricted so everybody can access it. Just share the URL of this page. ',
'<button data-toggle="tooltip" data-placement="top" title="Copy to clipboard" class="btn btn-default btn-copy-link-to-clipboard primary-button" type="button">',
'<span class="fa fa-clipboard"/>',
'&nbsp;To Clipboard',
'</button> ',
'</p>',
'<div class="dataset_table">',
'<table class="grid table table-striped table-condensed">',
'<tr>',
'<th scope="row" id="id_row" data-id="<%= _.escape(item.get("ldda_id")) %>">',
'Name',
'</th>',
'<td>',
'<%= _.escape(item.get("name")) %>',
'</td>',
'</tr>',
'<% if (item.get("file_ext")) { %>',
'<tr>',
'<th scope="row">Data type</th>',
'<td>',
'<%= _.escape(item.get("file_ext")) %>',
'</td>',
'</tr>',
'<% } %>',
'</table>',
'</div>',
'</div>',
].join(''));
},
templateLibraryPermissions : function(){
return _.template([
'<div class="library_style_container">',
@@ -210,7 +210,7 @@ var LibraryToolbarView = Backbone.View.extend({
'<button id="create_new_library_btn" class="primary-button btn-xs" type="button"><span class="fa fa-plus"></span> New Library</button>',
'</span>',
'<% } %>',
'<span class="help-button" data-toggle="tooltip" data-placement="top" title="Visit Libraries Wiki">',
'<span class="help-button" data-toggle="tooltip" data-placement="top" title="See this screen annotated">',
'<a href="https://galaxyproject.org/data-libraries/screen/list-of-libraries/" target="_blank">',
'<button class="primary-button" type="button"><span class="fa fa-question-circle"></span> Help</button>',
'</a>',
+2 -2
View File
@@ -150,8 +150,8 @@ class LibraryManager(object):
:param check_accessible: flag whether to check that user can access library
:type check_accessible: bool
:returns: the original folder
:rtype: LibraryFolder
:returns: the original library
:rtype: Library
"""
# all libraries are accessible to an admin
if trans.user_is_admin():
+234
View File
@@ -0,0 +1,234 @@
"""Manager and Serializer for library datasets."""
import logging
from galaxy import util
from galaxy.exceptions import InternalServerError
from galaxy.exceptions import ItemAccessibilityException
from galaxy.exceptions import InsufficientPermissionsException
from galaxy.exceptions import ObjectNotFound
from galaxy.exceptions import RequestParameterInvalidException
from galaxy.managers import tags
from galaxy.util import validation
log = logging.getLogger(__name__)
class LibraryDatasetsManager(object):
"""Interface/service object for interacting with library datasets."""
def __init__(self, app):
self.app = app
self.tag_manager = tags.GalaxyTagManager(app.model.context)
def get(self, trans, decoded_library_dataset_id, check_accessible=True):
"""
Get the library dataset from the DB.
:param decoded_library_dataset_id: decoded library dataset id
:type decoded_library_dataset_id: int
:param check_accessible: flag whether to check that user can access item
:type check_accessible: bool
:returns: the requested library dataset
:rtype: galaxy.model.LibraryDataset
"""
try:
ld = trans.sa_session.query(trans.app.model.LibraryDataset).filter(trans.app.model.LibraryDataset.table.c.id == decoded_library_dataset_id).one()
except Exception as e:
raise InternalServerError('Error loading from the database.' + str(e))
ld = self.secure(trans, ld, check_accessible)
return ld
def update(self, trans, ld, payload):
"""
Update the given library dataset - the latest linked ldda.
Updating older lddas (versions) is not supported.
:param ld: library dataset to change
:type ld: LibraryDataset
:param check_ownership: flag whether to check that user owns the item
:type check_ownership: bool
:param check_accessible: flag whether to check that user can access item
:type check_accessible: bool
:returns: the changed library dataset
:rtype: galaxy.model.LibraryDataset
:raises: ItemAccessibilityException, InsufficientPermissionsException
"""
current_user_roles = trans.get_current_user_roles()
self.check_modifiable(trans, ld)
if ld.deleted is True:
raise ItemAccessibilityException("You cannot update a deleted library dataset. Undelete it first.")
if not (trans.user_is_admin or trans.app.security_agent.can_modify_library_item(current_user_roles, ld)):
raise InsufficientPermissionsException('You do not have proper permission to modify this library dataset.')
# we are going to operate on the actual latest ldda
ldda = ld.library_dataset_dataset_association
payload = self._validate_and_parse_update_payload(payload)
self._set_from_dict(trans, ldda, payload)
return ld
def _set_from_dict(self, trans, ldda, new_data):
changed = False
new_name = new_data.get('name', None)
if new_name is not None and new_name != ldda.name:
ldda.name = new_name
changed = True
new_misc_info = new_data.get('misc_info', None)
if new_misc_info is not None and new_misc_info != ldda.info:
ldda.info = new_misc_info
changed = True
new_file_ext = new_data.get('file_ext', None)
if new_file_ext is not None and new_file_ext != ldda.extension:
ldda.extension = new_file_ext
# TODO trigger set metadata here
changed = True
new_genome_build = new_data.get('genome_build', None)
if new_genome_build is not None and new_genome_build != ldda.dbkey:
ldda.dbkey = new_genome_build
changed = True
if changed:
trans.sa_session.add(ldda)
trans.sa_session.flush()
return changed
def _validate_and_parse_update_payload(self, payload):
MINIMUM_STRING_LENGTH = 1
validated_payload = {}
for key, val in payload.items():
if val is None:
continue
if key in ('name'):
if len(val) < MINIMUM_STRING_LENGTH:
raise RequestParameterInvalidException('%s must have at least length of %s' % (key, MINIMUM_STRING_LENGTH))
val = validation.validate_and_sanitize_basestring(key, val)
validated_payload[key] = val
if key in ('misc_info'):
val = validation.validate_and_sanitize_basestring(key, val)
validated_payload[key] = val
if key in ('file_ext'):
datatype = self.app.datatypes_registry.get_datatype_by_extension(val)
if datatype is None:
raise RequestParameterInvalidException('This Galaxy does not recognize the datatype of: %s' % (val))
validated_payload[key] = val
if key in ('genome_build'):
if len(val) < MINIMUM_STRING_LENGTH:
raise RequestParameterInvalidException('%s must have at least length of %s' % (key, MINIMUM_STRING_LENGTH))
val = validation.validate_and_sanitize_basestring(key, val)
validated_payload[key] = val
return validated_payload
def secure(self, trans, ld, check_accessible=True, check_ownership=False):
"""
Check if library dataset is accessible to current user or the user is an admin.
:param ld: library dataset
:type ld: galaxy.model.LibraryDataset
:param check_accessible: flag whether to check that user can access library dataset
:type check_accessible: bool
:returns: the original library dataset
:rtype: galaxy.model.LibraryDataset
"""
if trans.user_is_admin():
# all operations are available to an admin
return ld
if check_accessible:
ld = self.check_accessible(trans, ld)
return ld
def check_accessible(self, trans, ld):
"""
Check whether the current user has permissions to access library dataset.
:param ld: library dataset
:type ld: galaxy.model.LibraryDataset
:returns: the original library dataset
:rtype: galaxy.model.LibraryDataset
:raises: ObjectNotFound
"""
if not trans.app.security_agent.can_access_library_item(trans.get_current_user_roles(), ld, trans.user):
raise ObjectNotFound('Library dataset with the id provided was not found.')
elif ld.deleted:
raise ObjectNotFound('Library dataset with the id provided is deleted.')
else:
return ld
def check_modifiable(self, trans, ld):
"""
Check whether the current user has permissions to modify library dataset.
:param ld: library dataset
:type ld: galaxy.model.LibraryDataset
:returns: the original library dataset
:rtype: galaxy.model.LibraryDataset
:raises: ObjectNotFound
"""
if trans.user_is_admin():
# all operations are available to an admin
return ld
if not trans.app.security_agent.can_modify_library_item(trans.get_current_user_roles(), ld):
raise InsufficientPermissionsException('You do not have proper permission to modify this library dataset.')
elif ld.deleted:
raise ObjectNotFound('Library dataset with the id provided is deleted.')
else:
return ld
def serialize(self, trans, ld):
"""Serialize the library dataset into a dictionary."""
current_user_roles = trans.get_current_user_roles()
# Build the full path for breadcrumb purposes.
full_path = self._build_path(trans, ld.folder)
dataset_item = (trans.security.encode_id(ld.id), ld.name)
full_path.insert(0, dataset_item)
full_path = full_path[::-1]
# Find expired versions of the library dataset
expired_ldda_versions = []
for expired_ldda in ld.expired_datasets:
expired_ldda_versions.append((trans.security.encode_id(expired_ldda.id), expired_ldda.name))
rval = trans.security.encode_all_ids(ld.to_dict())
if len(expired_ldda_versions) > 0:
rval['has_versions'] = True
rval['expired_versions'] = expired_ldda_versions
rval['deleted'] = ld.deleted
rval['folder_id'] = 'F' + rval['folder_id']
rval['full_path'] = full_path
rval['file_size'] = util.nice_size(int(ld.library_dataset_dataset_association.get_size()))
rval['date_uploaded'] = ld.library_dataset_dataset_association.create_time.strftime("%Y-%m-%d %I:%M %p")
rval['can_user_modify'] = trans.app.security_agent.can_modify_library_item(current_user_roles, ld) or trans.user_is_admin()
rval['is_unrestricted'] = trans.app.security_agent.dataset_is_public(ld.library_dataset_dataset_association.dataset)
rval['tags'] = self.tag_manager.get_tags_str(ld.library_dataset_dataset_association.tags)
# Manage dataset permission is always attached to the dataset itself, not the the ld or ldda to maintain consistency
rval['can_user_manage'] = trans.app.security_agent.can_manage_dataset(current_user_roles, ld.library_dataset_dataset_association.dataset) or trans.user_is_admin()
return rval
def _build_path(self, trans, folder):
"""
Search the path upwards recursively and load the whole route of
names and ids for breadcrumb building purposes.
:param folder: current folder for navigating up
:param type: Galaxy LibraryFolder
:returns: list consisting of full path to the library
:type: list
"""
path_to_root = []
if folder.parent_id is None:
# We are almost in root
path_to_root.append(('F' + trans.security.encode_id(folder.id), folder.name))
else:
# We add the current folder and traverse up one folder.
path_to_root.append(('F' + trans.security.encode_id(folder.id), folder.name))
upper_folder = trans.sa_session.query(trans.app.model.LibraryFolder).get(folder.parent_id)
path_to_root.extend(self._build_path(trans, upper_folder))
return path_to_root
+1 -1
View File
@@ -31,7 +31,7 @@ log = logging.getLogger(__name__)
class WorkflowsManager(object):
""" Handle CRUD type operaitons related to workflows. More interesting
""" Handle CRUD type operations related to workflows. More interesting
stuff regarding workflow execution, step sorting, etc... can be found in
the galaxy.workflow module.
"""
@@ -1,6 +1,4 @@
"""
API operations on the library datasets.
"""
"""API operations on the library datasets."""
import glob
import logging
import os
@@ -16,7 +14,8 @@ from galaxy import exceptions
from galaxy import util
from galaxy import web
from galaxy.exceptions import ObjectNotFound
from galaxy.managers import folders, roles, tags
from galaxy.managers import base as managers_base
from galaxy.managers import folders, library_datasets, roles
from galaxy.tools.actions import upload_common
from galaxy.tools.parameters import populate_state
from galaxy.util.streamball import StreamBall
@@ -31,81 +30,47 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
def __init__(self, app):
super(LibraryDatasetsController, self).__init__(app)
self.app = app
self.folder_manager = folders.FolderManager()
self.role_manager = roles.RoleManager(app)
self.ld_manager = library_datasets.LibraryDatasetsManager(app)
@expose_api_anonymous
def show(self, trans, id, **kwd):
"""
show( self, trans, id, **kwd )
* GET /api/libraries/datasets/{encoded_dataset_id}
Displays information about the dataset identified by the encoded ID.
Show the details of a library dataset.
:param id: the encoded id of the dataset to query
* GET /api/libraries/datasets/{encoded_dataset_id}
:param id: the encoded id of the library dataset to query
:type id: an encoded id string
:returns: detailed dataset information from base controller
:returns: detailed library dataset information
:rtype: dictionary
.. seealso:: :attr:`galaxy.web.base.controller.UsesLibraryMixinItems.get_library_dataset`
"""
try:
library_dataset = self.get_library_dataset(trans, id=id, check_ownership=False, check_accessible=True)
except Exception:
raise exceptions.ObjectNotFound('Requested library_dataset was not found.')
current_user_roles = trans.get_current_user_roles()
tag_manager = tags.GalaxyTagManager(trans.sa_session)
# Build the full path for breadcrumb purposes.
full_path = self._build_path(trans, library_dataset.folder)
dataset_item = (trans.security.encode_id(library_dataset.id), library_dataset.name)
full_path.insert(0, dataset_item)
full_path = full_path[::-1]
# Find expired versions of the library dataset
expired_ldda_versions = []
for expired_ldda in library_dataset.expired_datasets:
expired_ldda_versions.append((trans.security.encode_id(expired_ldda.id), expired_ldda.name))
rval = trans.security.encode_all_ids(library_dataset.to_dict())
if len(expired_ldda_versions) > 0:
rval['has_versions'] = True
rval['expired_versions'] = expired_ldda_versions
rval['deleted'] = library_dataset.deleted
rval['folder_id'] = 'F' + rval['folder_id']
rval['full_path'] = full_path
rval['file_size'] = util.nice_size(int(library_dataset.library_dataset_dataset_association.get_size()))
rval['date_uploaded'] = library_dataset.library_dataset_dataset_association.create_time.strftime("%Y-%m-%d %I:%M %p")
rval['can_user_modify'] = trans.app.security_agent.can_modify_library_item(current_user_roles, library_dataset) or trans.user_is_admin()
rval['is_unrestricted'] = trans.app.security_agent.dataset_is_public(library_dataset.library_dataset_dataset_association.dataset)
rval['tags'] = tag_manager.get_tags_str(library_dataset.library_dataset_dataset_association.tags)
# Manage dataset permission is always attached to the dataset itself, not the the ld or ldda to maintain consistency
rval['can_user_manage'] = trans.app.security_agent.can_manage_dataset(current_user_roles, library_dataset.library_dataset_dataset_association.dataset) or trans.user_is_admin()
return rval
ld = self.ld_manager.get(trans, managers_base.decode_id(self.app, id))
serialized = self.ld_manager.serialize(trans, ld)
return serialized
@expose_api_anonymous
def show_version(self, trans, encoded_dataset_id, encoded_ldda_id, **kwd):
"""
show_version( self, trans, encoded_dataset_id, encoded_ldda_id, **kwd ):
* GET /api/libraries/datasets/{encoded_dataset_id}/versions/{encoded_ldda_id}
Displays information about specific version of the library_dataset (i.e. ldda).
Display a specific version of a library dataset (i.e. ldda).
:param encoded_dataset_id: the encoded id of the dataset to query
* GET /api/libraries/datasets/{encoded_dataset_id}/versions/{encoded_ldda_id}
:param encoded_dataset_id: the encoded id of the related library dataset
:type encoded_dataset_id: an encoded id string
:param encoded_ldda_id: the encoded id of the ldda to query
:type encoded_ldda_id: an encoded id string
:rtype: dictionary
:returns: dict of ldda's details
:rtype: dictionary
:raises: ObjectNotFound
"""
try:
library_dataset = self.get_library_dataset(trans, id=encoded_dataset_id, check_ownership=False, check_accessible=True)
except Exception:
raise exceptions.ObjectNotFound('Requested library_dataset was not found.')
library_dataset = self.ld_manager.get(trans, managers_base.decode_id(self.app, encoded_dataset_id))
try:
ldda = self.get_library_dataset_dataset_association(trans, id=encoded_ldda_id, check_ownership=False, check_accessible=False)
@@ -121,10 +86,9 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
@expose_api
def show_roles(self, trans, encoded_dataset_id, **kwd):
"""
show_roles( self, trans, id, **kwd ):
Display information about current or available roles for a given dataset permission.
* GET /api/libraries/datasets/{encoded_dataset_id}/permissions
Displays information about current or available roles
for a given dataset permission.
:param encoded_dataset_id: the encoded id of the dataset to query
:type encoded_dataset_id: an encoded id string
@@ -132,16 +96,14 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
:param scope: either 'current' or 'available'
:type scope: string
:returns: either dict of current roles for all permission types
or dict of available roles to choose from (is the same for any permission type)
:rtype: dictionary
:returns: either dict of current roles for all permission types or
dict of available roles to choose from (is the same for any permission type)
"""
:raises: InsufficientPermissionsException
"""
current_user_roles = trans.get_current_user_roles()
try:
library_dataset = self.get_library_dataset(trans, id=encoded_dataset_id, check_ownership=False, check_accessible=False)
except Exception as e:
raise exceptions.ObjectNotFound('Requested dataset was not found.' + str(e))
library_dataset = self.ld_manager.get(trans, managers_base.decode_id(self.app, encoded_dataset_id))
dataset = library_dataset.library_dataset_dataset_association.dataset
# User has to have manage permissions permission in order to see the roles.
@@ -203,11 +165,29 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
return dict(access_dataset_roles=access_dataset_role_list, modify_item_roles=modify_item_role_list, manage_dataset_roles=manage_dataset_role_list)
@expose_api
def update(self, trans, encoded_dataset_id, payload=None, **kwd):
"""Update the given library dataset (the latest linked ldda).
* PATCH /api/libraries/datasets/{encoded_dataset_id}
:param encoded_dataset_id: the encoded id of the library dataset to update
:type encoded_dataset_id: an encoded id string
:returns: detailed library dataset information
:rtype: dictionary
"""
library_dataset = self.ld_manager.get(trans, managers_base.decode_id(self.app, encoded_dataset_id))
updated = self.ld_manager.update(trans, library_dataset, payload)
serialized = self.ld_manager.serialize(trans, updated)
return serialized
@expose_api
def update_permissions(self, trans, encoded_dataset_id, payload=None, **kwd):
"""
Set permissions of the given library dataset to the given role ids.
*POST /api/libraries/datasets/{encoded_dataset_id}/permissions
Set permissions of the given dataset to the given role ids.
:param encoded_dataset_id: the encoded id of the dataset to update permissions of
:type encoded_dataset_id: an encoded id string
@@ -222,6 +202,7 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
:param modify_ids[]: list of Role.id defining roles that should have modify permission on the library dataset item
:type modify_ids[]: string or list
:type: dictionary
:returns: dict of current roles for all available permission types
:rtype: dictionary
@@ -230,10 +211,8 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
"""
if payload:
kwd.update(payload)
try:
library_dataset = self.get_library_dataset(trans, id=encoded_dataset_id, check_ownership=False, check_accessible=False)
except Exception as e:
raise exceptions.ObjectNotFound('Requested dataset was not found.' + str(e))
library_dataset = self.ld_manager.get(trans, managers_base.decode_id(self.app, encoded_dataset_id))
# Some permissions are attached directly to the underlying dataset.
dataset = library_dataset.library_dataset_dataset_association.dataset
current_user_roles = trans.get_current_user_roles()
can_manage = trans.app.security_agent.can_manage_dataset(current_user_roles, dataset) or trans.user_is_admin()
@@ -266,7 +245,7 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
trans.app.security_agent.make_dataset_public(dataset)
else:
for role_id in new_access_roles_ids:
role = self.role_manager.get(trans, self.__decode_id(trans, role_id, 'role'))
role = self.role_manager.get(trans, managers_base.decode_id(self.app, role_id))
# Check whether role is in the set of allowed roles
valid_roles, total_roles = trans.app.security_agent.get_valid_roles(trans, dataset)
if role in valid_roles:
@@ -288,7 +267,7 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
active_access_roles = dataset.get_access_roles(trans)
for role_id in new_manage_roles_ids:
role = self.role_manager.get(trans, self.__decode_id(trans, role_id, 'role'))
role = self.role_manager.get(trans, managers_base.decode_id(self.app, role_id))
# Check whether role is in the set of access roles
if role in active_access_roles:
valid_manage_roles.append(role)
@@ -310,7 +289,7 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
active_access_roles = dataset.get_access_roles(trans)
for role_id in new_modify_roles_ids:
role = self.role_manager.get(trans, self.__decode_id(trans, role_id, 'role'))
role = self.role_manager.get(trans, managers_base.decode_id(self.app, role_id))
# Check whether role is in the set of access roles
if role in active_access_roles:
valid_modify_roles.append(role)
@@ -332,62 +311,59 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
@expose_api
def delete(self, trans, encoded_dataset_id, **kwd):
"""
delete( self, trans, encoded_dataset_id, **kwd ):
Mark the dataset deleted or undeleted.
* DELETE /api/libraries/datasets/{encoded_dataset_id}
Marks the dataset deleted or undeleted based on the value
of the undelete flag.
If the flag is not present it is considered False and the
item is marked deleted.
:param encoded_dataset_id: the encoded id of the dataset to change
:type encoded_dataset_id: an encoded id string
:param undelete: flag whether to undeleted instead of deleting
:type undelete: bool
:returns: dict containing information about the dataset
:rtype: dictionary
"""
undelete = util.string_as_bool(kwd.get('undelete', False))
try:
dataset = self.get_library_dataset(trans, id=encoded_dataset_id, check_ownership=False, check_accessible=False)
except Exception as e:
raise exceptions.ObjectNotFound('Requested dataset was not found.' + str(e))
library_dataset = self.ld_manager.get(trans, managers_base.decode_id(self.app, encoded_dataset_id))
current_user_roles = trans.get_current_user_roles()
allowed = trans.app.security_agent.can_modify_library_item(current_user_roles, dataset)
allowed = trans.app.security_agent.can_modify_library_item(current_user_roles, library_dataset)
if (not allowed) and (not trans.user_is_admin()):
raise exceptions.InsufficientPermissionsException('You do not have proper permissions to delete this dataset.')
if undelete:
dataset.deleted = False
library_dataset.deleted = False
else:
dataset.deleted = True
library_dataset.deleted = True
trans.sa_session.add(dataset)
trans.sa_session.add(library_dataset)
trans.sa_session.flush()
rval = trans.security.encode_all_ids(dataset.to_dict())
nice_size = util.nice_size(int(dataset.library_dataset_dataset_association.get_size()))
rval = trans.security.encode_all_ids(library_dataset.to_dict())
nice_size = util.nice_size(int(library_dataset.library_dataset_dataset_association.get_size()))
rval['file_size'] = nice_size
rval['update_time'] = dataset.update_time.strftime("%Y-%m-%d %I:%M %p")
rval['deleted'] = dataset.deleted
rval['update_time'] = library_dataset.update_time.strftime("%Y-%m-%d %I:%M %p")
rval['deleted'] = library_dataset.deleted
rval['folder_id'] = 'F' + rval['folder_id']
return rval
@expose_api
def load(self, trans, payload=None, **kwd):
"""
Load dataset(s) from the given source into the library.
* POST /api/libraries/datasets
Load dataset from the given source into the library.
Source can be:
user directory - root folder specified in galaxy.ini as "$user_library_import_dir"
example path: path/to/galaxy/$user_library_import_dir/user@example.com/{user can browse everything here}
the folder with the user login has to be created beforehand
(admin)import directory - root folder specified in galaxy ini as "$library_import_dir"
example path: path/to/galaxy/$library_import_dir/{admin can browse everything here}
(admin)any absolute or relative path - option allowed with "allow_library_path_paste" in galaxy.ini
:param payload: dictionary structure containing:
:param encoded_folder_id: the encoded id of the folder to import dataset(s) to
:type encoded_folder_id: an encoded id string
:param source: source the datasets should be loaded from
Source can be:
user directory - root folder specified in galaxy.ini as "$user_library_import_dir"
example path: path/to/galaxy/$user_library_import_dir/user@example.com/{user can browse everything here}
the folder with the user login has to be created beforehand
(admin)import directory - root folder specified in galaxy ini as "$library_import_dir"
example path: path/to/galaxy/$library_import_dir/{admin can browse everything here}
(admin)any absolute or relative path - option allowed with "allow_library_path_paste" in galaxy.ini
:type source: str
:param link_data: flag whether to link the dataset to data or copy it to Galaxy, defaults to copy
while linking is set to True all symlinks will be resolved _once_
@@ -402,8 +378,10 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
:param tag_using_filenames: flag whether to generate dataset tags from filenames
:type tag_using_filenames: bool
:type dictionary
:returns: dict containing information about the created upload job
:rtype: dictionary
:raises: RequestParameterMissingException, AdminRequiredException, ConfigDoesNotAllowException, RequestParameterInvalidException
InsufficientPermissionsException, ObjectNotFound
"""
@@ -510,10 +488,10 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
# TODO convert to expose_api
def download(self, trans, format, **kwd):
"""
download( self, trans, format, **kwd )
Download requested datasets (identified by encoded IDs) in requested format.
* GET /api/libraries/datasets/download/{format}
* POST /api/libraries/datasets/download/{format}
Downloads requested datasets (identified by encoded IDs) in requested format.
example: ``GET localhost:8080/api/libraries/datasets/download/tbz?ld_ids%255B%255D=a0d84b45643a2678&ld_ids%255B%255D=fe38c84dcd46c828``
@@ -526,8 +504,8 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
:param folder_ids[]: an array of encoded folder ids
:type folder_ids[]: an array
:rtype: file
:returns: either archive with the requested datasets packed inside or a single uncompressed dataset
:rtype: file
:raises: MessageException, ItemDeletionException, ItemAccessibilityException, HTTPBadRequest, OSError, IOError, ObjectNotFound
"""
@@ -636,7 +614,8 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
zpath = os.path.split(path)[-1] # comes as base_name/fname
outfname, zpathext = os.path.splitext(zpath)
if is_composite: # need to add all the components from the extra_files_path to the zip
if is_composite:
# need to add all the components from the extra_files_path to the zip
if zpathext == '':
zpath = '%s.html' % zpath # fake the real nature of the html file
try:
@@ -671,10 +650,9 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
log.exception("Requested dataset %s does not exist on the host.", fpath)
raise exceptions.ObjectNotFound("Requested dataset not found.")
except Exception as e:
log.exception("Unable to add %s to temporary library download archive %s", fname, outfname)
log.exception("Unable to add %s to temporary library download archive %s" % (fname, outfname))
raise exceptions.InternalServerError("Unable to add dataset to temporary library download archive . " + str(e))
else: # simple case
else:
try:
if format == 'zip':
archive.add(ldda.dataset.file_name, path)
@@ -724,39 +702,3 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin):
raise exceptions.InternalServerError("This dataset contains no content.")
else:
raise exceptions.RequestParameterInvalidException("Wrong format parameter specified")
def _build_path(self, trans, folder):
"""
Search the path upwards recursively and load the whole route of
names and ids for breadcrumb building purposes.
:param folder: current folder for navigating up
:param type: Galaxy LibraryFolder
:returns: list consisting of full path to the library
:type: list
"""
path_to_root = []
# We are almost in root
if folder.parent_id is None:
path_to_root.append(('F' + trans.security.encode_id(folder.id), folder.name))
else:
# We add the current folder and traverse up one folder.
path_to_root.append(('F' + trans.security.encode_id(folder.id), folder.name))
upper_folder = trans.sa_session.query(trans.app.model.LibraryFolder).get(folder.parent_id)
path_to_root.extend(self._build_path(trans, upper_folder))
return path_to_root
def __decode_id(self, trans, encoded_id, object_name=None):
"""
Try to decode the id.
:param object_name: Name of the object the id belongs to. (optional)
:type object_name: str
"""
try:
return trans.security.decode_id(encoded_id)
except TypeError:
raise exceptions.MalformedId('Malformed %s id specified, unable to decode.' % object_name if object_name is not None else '')
except ValueError:
raise exceptions.MalformedId('Wrong %s id specified, unable to decode.' % object_name if object_name is not None else '')
+17 -11
View File
@@ -651,43 +651,49 @@ def populate_api_routes(webapp, app):
webapp.mapper.connect('show_ld_item',
'/api/libraries/datasets/{id}',
controller='lda_datasets',
controller='library_datasets',
action='show',
conditions=dict(method=["GET"]))
webapp.mapper.connect('load_ld',
'/api/libraries/datasets/',
controller='lda_datasets',
controller='library_datasets',
action='load',
conditions=dict(method=["POST"]))
webapp.mapper.connect('show_version_of_ld_item',
'/api/libraries/datasets/{encoded_dataset_id}/versions/{encoded_ldda_id}',
controller='lda_datasets',
controller='library_datasets',
action='show_version',
conditions=dict(method=["GET"]))
webapp.mapper.connect('show_legitimate_lda_roles',
webapp.mapper.connect('update_ld',
'/api/libraries/datasets/{encoded_dataset_id}',
controller='library_datasets',
action='update',
conditions=dict(method=["PATCH"]))
webapp.mapper.connect('show_legitimate_ld_roles',
'/api/libraries/datasets/{encoded_dataset_id}/permissions',
controller='lda_datasets',
controller='library_datasets',
action='show_roles',
conditions=dict(method=["GET"]))
webapp.mapper.connect('update_lda_permissions',
webapp.mapper.connect('update_ld_permissions',
'/api/libraries/datasets/{encoded_dataset_id}/permissions',
controller='lda_datasets',
controller='library_datasets',
action='update_permissions',
conditions=dict(method=["POST"]))
webapp.mapper.connect('delete_lda_item',
webapp.mapper.connect('delete_ld_item',
'/api/libraries/datasets/{encoded_dataset_id}',
controller='lda_datasets',
controller='library_datasets',
action='delete',
conditions=dict(method=["DELETE"]))
webapp.mapper.connect('download_lda_items',
webapp.mapper.connect('download_ld_items',
'/api/libraries/datasets/download/{format}',
controller='lda_datasets',
controller='library_datasets',
action='download',
conditions=dict(method=["POST", "GET"]))
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
{"version":3,"file":"library-librarytoolbar-view.js","sources":["../../../src/mvc/library/library-librarytoolbar-view.js"],"names":["define","mod_toastr","mod_library_model","LibraryToolbarView","Backbone","View","extend","el","defaults","search_term","events","click #create_new_library_btn","click #include_deleted_chk","click #exclude_restricted_chk","click #lib_page_size_prompt","keyup .library-search-input","initialize","options","this","_","render","toolbar_template","templateToolBar","is_admin","is_anonym","Galaxy","user","isAdmin","isAnonymous","$el","html","admin_user","anon_user","find","checked","libraries","preferences","get","renderPaginator","paginator_template","templatePaginator","show_page","parseInt","page_count","total_libraries_count","libraries_shown","createLibraryFromModal","event","preventDefault","stopPropagation","self","modal","show","closing_events","title","body","templateNewLibraryInModal","buttons","Create","createNewLibrary","Close","hide","libraryDetails","serializeNewLibrary","validateNewLibrary","library","Library","save","success","libraryListView","collection","add","clearLibraryModal","error","model","response","responseJSON","err_msg","showPageSizePrompt","library_page_size","prompt","set","$","val","name","description","synopsis","includeDeletedChecked","target","with_deleted","fetchDeleted","excludeRestrictedChecked","without_restricted","searchLibraries","template","join"],"mappings":"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"}
{"version":3,"file":"library-librarytoolbar-view.js","sources":["../../../src/mvc/library/library-librarytoolbar-view.js"],"names":["define","mod_toastr","mod_library_model","LibraryToolbarView","Backbone","View","extend","el","defaults","search_term","events","click #create_new_library_btn","click #include_deleted_chk","click #exclude_restricted_chk","click #lib_page_size_prompt","keyup .library-search-input","initialize","options","this","_","render","toolbar_template","templateToolBar","is_admin","is_anonym","Galaxy","user","isAdmin","isAnonymous","$el","html","admin_user","anon_user","find","checked","libraries","preferences","get","renderPaginator","paginator_template","templatePaginator","show_page","parseInt","page_count","total_libraries_count","libraries_shown","createLibraryFromModal","event","preventDefault","stopPropagation","self","modal","show","closing_events","title","body","templateNewLibraryInModal","buttons","Create","createNewLibrary","Close","hide","libraryDetails","serializeNewLibrary","validateNewLibrary","library","Library","save","success","libraryListView","collection","add","clearLibraryModal","error","model","response","responseJSON","err_msg","showPageSizePrompt","library_page_size","prompt","set","$","val","name","description","synopsis","includeDeletedChecked","target","with_deleted","fetchDeleted","excludeRestrictedChecked","without_restricted","searchLibraries","template","join"],"mappings":"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"}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+28
View File
@@ -113,6 +113,34 @@ class LibrariesApiTestCase(api.ApiTestCase, TestsDatasets):
self._assert_status_code_is(create_response, 200)
self._assert_has_keys(create_response.json(), "name", "id")
def test_update_dataset_in_folder(self):
library = self.library_populator.new_private_library("ForUpdateDataset")
folder_response = self._create_folder(library)
self._assert_status_code_is(folder_response, 200)
folder_id = folder_response.json()[0]['id']
history_id = self.dataset_populator.new_history()
hda_id = self.dataset_populator.new_dataset(history_id, content="1 2 3")['id']
payload = {'from_hda_id': hda_id, 'create_type': 'file', 'folder_id': folder_id}
ld = self._post("libraries/%s/contents" % folder_id, payload)
data = {'name': 'updated_name', 'file_ext': 'fastq', 'misc_info': 'updated_info', 'genome_build': 'updated_genome_build'}
create_response = self._patch("libraries/datasets/%s" % ld.json()["id"], data=data)
self._assert_status_code_is(create_response, 200)
self._assert_has_keys(create_response.json(), "name", "file_ext", "misc_info", "genome_build")
def test_invalid_update_dataset_in_folder(self):
library = self.library_populator.new_private_library("ForInvalidUpdateDataset")
folder_response = self._create_folder(library)
self._assert_status_code_is(folder_response, 200)
folder_id = folder_response.json()[0]['id']
history_id = self.dataset_populator.new_history()
hda_id = self.dataset_populator.new_dataset(history_id, content="1 2 3")['id']
payload = {'from_hda_id': hda_id, 'create_type': 'file', 'folder_id': folder_id}
ld = self._post("libraries/%s/contents" % folder_id, payload)
data = {'file_ext': 'nonexisting_type'}
create_response = self._patch("libraries/datasets/%s" % ld.json()["id"], data=data)
self._assert_status_code_is(create_response, 400)
assert 'This Galaxy does not recognize the datatype of:' in create_response.json()['err_msg']
def test_create_datasets_in_library_from_collection(self):
library = self.library_populator.new_private_library("ForCreateDatasetsFromCollection")
folder_response = self._create_folder(library)