first implementation

This commit is contained in:
Oleg Zharkov
2021-02-12 17:25:02 +01:00
parent 41fe422e3e
commit 86ac9ca956
10 changed files with 308 additions and 108 deletions
@@ -461,7 +461,7 @@ export default {
else if (element.type === "folder") return `${this.root}library/folders/${element.id}`;
},
navigateToPermission(element) {
if (element.type === "file") window.location.replace(`${this.createContentLink(element)}/permissions`);
if (element.type === "file") this.$router.push({ path: `/permissions/${this.folder_id}/dataset/${element.id}` })
else if (element.type === "folder") this.$router.push({ path: `/permissions/${element.id}` });
},
getMessage(element) {
@@ -0,0 +1,148 @@
<template>
<div>
<div v-if="dataset">
<b-button variant="primary" :to="{ path: `/${this.folder_id}` }">
<font-awesome-icon icon="angle-double-left">1</font-awesome-icon>
</b-button>
<div>
<div class="header text-center">{{ dataset.name }}</div>
</div>
</div>
<LibraryPermissionsWarning :is_admin="is_admin" />
<hr class="my-4" />
<b-container fluid>
<h2 class="text-center">Library-related permissions</h2>
<PermissionsInputField
v-if="modify_item_roles"
:id="dataset_id"
:permission_type="manage_type"
:initial_value="modify_item_roles"
title="Roles that can modify the library item"
:apiRootUrl="apiRootUrl"
alert="User with <strong>any</strong> of these roles can modify name, metadata, and other information about this library item."
@input="setUserPermissionsPreferences"
/>
<hr class="my-4" />
<h2 class="text-center">Dataset-related permissions</h2>
<div class="alert alert-warning text-center">
Changes made below will affect <strong>every</strong> library item that was created from this dataset
and also every history this dataset is part of.
</div>
<PermissionsInputField
v-if="access_dataset_roles"
:id="dataset_id"
:permission_type="manage_type"
:initial_value="access_dataset_roles"
:apiRootUrl="apiRootUrl"
title="Roles that can access the dataset"
alert="User has to have <strong>all these roles</strong> in order to access this dataset.
Users without access permission <strong>cannot</strong> have other permissions on this dataset.
If there are no access roles set on the dataset it is considered <strong>unrestricted</strong>."
@input="setUserPermissionsPreferences"
/>
<PermissionsInputField
v-if="manage_dataset_roles"
:id="dataset_id"
:permission_type="manage_type"
:initial_value="manage_dataset_roles"
:apiRootUrl="apiRootUrl"
title="Roles that can manage permissions on the dataset"
alert="User with <strong>any</strong> of these roles can manage permissions of this dataset.
If you remove yourself you will lose the ability manage this dataset unless you are an admin."
@input="setUserPermissionsPreferences"
/>
</b-container>
</div>
</template>
<script>
import Vue from "vue";
import { getAppRoot } from "onload/loadConfig";
import BootstrapVue from "bootstrap-vue";
import { Services } from "./services";
import { Toast } from "ui/toast";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { getGalaxyInstance } from "app";
import PermissionsInputField from "./PermissionsInputField.vue";
import { initManageFolderIcons } from "components/LibraryFolder/icons";
import LibraryPermissionsWarning from "components/LibraryFolder/LibraryFolderPermissions/LibraryPermissionsWarning.vue";
import { extractRoles } from "./utils";
import "vue-multiselect/dist/vue-multiselect.min.css";
import VueObserveVisibility from "vue-observe-visibility";
Vue.use(VueObserveVisibility);
Vue.use(BootstrapVue);
initManageFolderIcons();
export default {
props: {
folder_id: {
type: String,
required: true,
},
dataset_id: {
type: String,
required: true,
},
},
components: {
PermissionsInputField,
LibraryPermissionsWarning,
FontAwesomeIcon,
},
data() {
return {
permissions: undefined,
dataset: undefined,
is_admin: undefined,
access_dataset_roles: undefined,
modify_item_roles: undefined,
manage_dataset_roles: undefined,
add_type: "add_type",
manage_type: "manage_type",
modify_type: "modify_type",
apiRootUrl: `${getAppRoot()}api/libraries/datasets`,
};
},
created() {
const Galaxy = getGalaxyInstance();
this.root = getAppRoot();
this.services = new Services({ root: this.root });
this.is_admin = Galaxy.user.attributes.is_admin;
this.services.getDatasetPermissions(this.dataset_id).then((fetched_permissions) => {
this.access_dataset_roles = extractRoles(fetched_permissions.access_dataset_roles);
this.modify_item_roles = extractRoles(fetched_permissions.modify_item_roles);
this.manage_dataset_roles = extractRoles(fetched_permissions.manage_dataset_roles);
});
this.services.getDataset(this.dataset_id).then((response) => {
this.dataset = response;
});
},
methods: {
getParentLink() {
return `${this.root}library/folders/${this.folder_id}`;
},
setUserPermissionsPreferences(ids, permission_type) {
switch (permission_type) {
case "manage_type":
this.manage_folder_role_list = ids;
break;
case "add_type":
this.add_library_item_role_list = ids;
break;
case "modify_type":
this.modify_folder_role_list = ids;
break;
}
},
},
};
</script>
<style scoped>
.header {
font-size: 45px;
}
</style>
@@ -9,77 +9,44 @@
<div class="header text-center">{{ folder.name }}</div>
</div>
</div>
<div>
<div class="text-center">
<b-alert show variant="warning" v-if="is_admin">
You are logged in as an <strong>administrator</strong> therefore you can manage any folder on
this Galaxy instance. Please make sure you understand the consequences.
</b-alert>
<b-alert show variant="warning" v-else>
You can assign any number of roles to any of the following permission types. However please read
carefully the implications of such actions.
</b-alert>
</div>
</div>
<LibraryPermissionsWarning :is_admin="is_admin" />
<hr class="my-4" />
<b-container fluid>
<div class="dataset_table">
<h2>Folder permissions</h2>
<h4>
Roles that can manage permissions on this folder
</h4>
<b-row>
<b-col>
<PermissionsInputField
v-if="manage_folder_role_list"
:folder_id="folder_id"
:permission_type="manage_type"
:initial_value="manage_folder_role_list"
@input="setUserPermissionsPreferences"
/></b-col>
<b-col>
<b-alert show variant="info">
User with <strong>any</strong> of these roles can manage permissions on this folder.
</b-alert>
</b-col>
</b-row>
<h4>
Roles that can add items to this folder
</h4>
<b-row>
<b-col>
<PermissionsInputField
v-if="add_library_item_role_list"
:folder_id="folder_id"
:permission_type="add_type"
:initial_value="add_library_item_role_list"
@input="setUserPermissionsPreferences"
/></b-col>
<b-col>
<b-alert class="p-3" show variant="info">
User with <strong>any</strong> of these roles can add items to this folder (folders and
datasets).
</b-alert>
</b-col>
</b-row>
<h4>
Roles that can modify this folder
</h4>
<b-row>
<b-col>
<PermissionsInputField
v-if="modify_folder_role_list"
:folder_id="folder_id"
:permission_type="modify_type"
:initial_value="modify_folder_role_list"
@input="setUserPermissionsPreferences"
/></b-col>
<b-col>
<b-alert show variant="info">
User with <strong>any</strong> of these roles can modify this folder (name, etc.).
</b-alert></b-col
>
</b-row>
<h2 class="text-center">Folder permissions</h2>
<PermissionsInputField
v-if="manage_folder_role_list"
:id="folder_id"
:permission_type="manage_type"
:initial_value="manage_folder_role_list"
:apiRootUrl="apiRootUrl"
alert="User with <strong>any</strong> of these roles can manage permissions on this folder."
title="Roles that can manage permissions on this folder"
@input="setUserPermissionsPreferences"
/>
<PermissionsInputField
v-if="add_library_item_role_list"
:id="folder_id"
:permission_type="add_type"
:initial_value="add_library_item_role_list"
:apiRootUrl="apiRootUrl"
title="Roles that can add items to this folder"
alert="User with <strong>any</strong> of these roles can add items to this folder (folders and
datasets)."
@input="setUserPermissionsPreferences"
/>
<PermissionsInputField
v-if="modify_folder_role_list"
:id="folder_id"
:permission_type="modify_type"
:initial_value="modify_folder_role_list"
:apiRootUrl="apiRootUrl"
title="Roles that can modify this folder"
alert="User with <strong>any</strong> of these roles can modify this folder (name, etc.)."
@input="setUserPermissionsPreferences"
/>
<button
data-toggle="tooltip"
data-placement="top"
@@ -106,12 +73,11 @@ import { Toast } from "ui/toast";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { getGalaxyInstance } from "app";
import PermissionsInputField from "./PermissionsInputField.vue";
import LibraryPermissionsWarning from "components/LibraryFolder/LibraryFolderPermissions/LibraryPermissionsWarning.vue";
import { extractRoles } from "./utils";
import { initManageFolderIcons } from "components/LibraryFolder/icons";
import "vue-multiselect/dist/vue-multiselect.min.css";
import VueObserveVisibility from "vue-observe-visibility";
Vue.use(VueObserveVisibility);
Vue.use(BootstrapVue);
initManageFolderIcons();
@@ -124,6 +90,7 @@ export default {
},
components: {
PermissionsInputField,
LibraryPermissionsWarning,
FontAwesomeIcon,
},
data() {
@@ -137,6 +104,7 @@ export default {
add_type: "add_type",
manage_type: "manage_type",
modify_type: "modify_type",
apiRootUrl: `${getAppRoot()}api/folders`,
};
},
created() {
@@ -145,9 +113,9 @@ export default {
this.services = new Services({ root: this.root });
this.is_admin = Galaxy.user.attributes.is_admin;
this.services.getFolderPermissions(this.folder_id).then((fetched_permissions) => {
this.add_library_item_role_list = this._serializeRoles(fetched_permissions.add_library_item_role_list);
this.manage_folder_role_list = this._serializeRoles(fetched_permissions.manage_folder_role_list);
this.modify_folder_role_list = this._serializeRoles(fetched_permissions.modify_folder_role_list);
this.add_library_item_role_list = extractRoles(fetched_permissions.add_library_item_role_list);
this.manage_folder_role_list = extractRoles(fetched_permissions.manage_folder_role_list);
this.modify_folder_role_list = extractRoles(fetched_permissions.modify_folder_role_list);
});
this.services.getFolder(this.folder_id).then((response) => {
this.folder = response;
@@ -187,15 +155,6 @@ export default {
}
);
},
_serializeRoles: function (role_list) {
const selected_roles = [];
role_list.forEach((item) => {
selected_roles.push({ name: item[0], id: item[1] });
});
return selected_roles;
},
},
};
</script>
@@ -0,0 +1,25 @@
<template>
<div>
<div class="text-center">
<b-alert show variant="warning" v-if="is_admin">
You are logged in as an <strong>administrator</strong> therefore you can manage any folder on
this Galaxy instance. Please make sure you understand the consequences.
</b-alert>
<b-alert show variant="warning" v-else>
You can assign any number of roles to any of the following permission types. However please read
carefully the implications of such actions.
</b-alert>
</div>
</div>
</template>
<script>
export default {
props: {
is_admin: {
type: Boolean,
required: true,
},
},
}
</script>
@@ -1,33 +1,56 @@
<template>
<div v-if="options && value">
<multiselect
v-model="value"
:options="fetched_options"
:clear-on-select="true"
:preserve-search="true"
:multiple="true"
label="name"
track-by="id"
@input="valueChanged"
@search-change="searchChanged"
:internal-search="false"
>
<template slot="afterList">
<div v-observe-visibility="reachedEndOfList" v-if="hasMorePages">
<span class="spinner fa fa-spinner fa-spin fa-1x" />
<div>
<h4>
{{ title }}
</h4>
<b-row>
<b-col>
<div v-if="options && value">
<multiselect
v-model="value"
:options="fetched_options"
:clear-on-select="true"
:preserve-search="true"
:multiple="true"
label="name"
track-by="id"
@input="valueChanged"
@search-change="searchChanged"
:internal-search="false"
>
<template slot="afterList">
<div v-observe-visibility="reachedEndOfList" v-if="hasMorePages">
<span class="spinner fa fa-spinner fa-spin fa-1x" />
</div>
</template>
</multiselect>
</div>
</template>
</multiselect>
</b-col>
<b-col>
<b-alert show variant="info">
<div v-html="alert" />
</b-alert>
</b-col>
</b-row>
</div>
</template>
<script>
import Vue from "vue";
import VueObserveVisibility from "vue-observe-visibility";
import Multiselect from "vue-multiselect";
import { Services } from "./services";
import "vue-multiselect/dist/vue-multiselect.min.css";
Vue.use(VueObserveVisibility);
export default {
props: {
folder_id: {
id: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
@@ -39,6 +62,14 @@ export default {
type: Array,
required: true,
},
apiRootUrl: {
type: String,
required: true,
},
alert: {
type: String,
required: true,
},
},
components: {
Multiselect,
@@ -70,7 +101,7 @@ export default {
methods: {
getSelectOptions(searchChanged = false) {
this.services
.getSelectOptions(this.folder_id, true, this.page, this.page_limit, this.searchValue)
.getSelectOptions(this.apiRootUrl, this.id, true, this.page, this.page_limit, this.searchValue)
.then((response) => {
this.options = response;
if (searchChanged) this.fetched_options = this.options.roles;
@@ -16,6 +16,24 @@ export class Services {
rethrowSimple(e);
}
}
async getDatasetPermissions(id) {
const url = `${this.root}api/libraries/datasets/${id}/permissions?scope=current`;
try {
const response = await axios.get(url);
return response.data;
} catch (e) {
rethrowSimple(e);
}
}
async getDataset(id) {
const url = `${this.root}api/libraries/datasets/${id}`;
try {
const response = await axios.get(url);
return response.data;
} catch (e) {
rethrowSimple(e);
}
}
async getFolder(id) {
const url = `${this.root}api/folders/${id}`;
try {
@@ -25,9 +43,9 @@ export class Services {
rethrowSimple(e);
}
}
async getSelectOptions(id, is_library_access, page, page_limit, searchQuery) {
async getSelectOptions(apiRootUrl, id, is_library_access, page, page_limit, searchQuery) {
searchQuery = searchQuery ? `&q=${searchQuery}` : "";
const url = `${this.root}api/folders/${id}/permissions?scope=available&is_library_access=${is_library_access}&page_limit=${page_limit}&page=${page}${searchQuery}`;
const url = `${apiRootUrl}/${id}/permissions?scope=available&is_library_access=${is_library_access}&page_limit=${page_limit}&page=${page}${searchQuery}`;
try {
const response = await axios.get(url);
return response.data;
@@ -35,6 +53,7 @@ export class Services {
rethrowSimple(e);
}
}
async setPermissions(id, add_ids, manage_ids, modify_ids, onSuccess, onError) {
var formData = new FormData();
formData.append(
@@ -0,0 +1,9 @@
// legacy code
export function extractRoles(role_list) {
const selected_roles = [];
role_list.forEach((item) => {
selected_roles.push({ name: item[0], id: item[1] });
});
return selected_roles;
}
@@ -2,8 +2,9 @@
import { getAppRoot } from "onload/loadConfig";
import Vue from "vue";
import VueRouter from "vue-router";
import LibraryFolderPermissions from "./LibraryFolderPermissions/LibraryFolderPermissions.vue";
import LibraryFolderPermissions from "components/LibraryFolder/LibraryFolderPermissions/LibraryFolderPermissions.vue";
import LibraryFolder from "components/LibraryFolder/LibraryFolder.vue";
import LibraryFolderDatasetPermissions from "components/LibraryFolder/LibraryFolderPermissions/LibraryFolderDatasetPermissions.vue";
Vue.use(VueRouter);
@@ -23,6 +24,12 @@ export default new VueRouter({
component: LibraryFolderPermissions,
props: true,
},
{
path: "/permissions/:folder_id/dataset/:dataset_id",
name: "LibraryFolder",
component: LibraryFolderDatasetPermissions,
props: true,
},
],
});
</script>
@@ -101,6 +101,7 @@ export const getAnalysisRouter = (Galaxy) => {
"(/)interactivetool_entry_points(/)list": "show_interactivetool_list",
"(/)library/folders(/)(:folder_id)": "show_library_folder",
"(/)library/folders/permissions(/)(:folder_id)": "show_library_folder",
"(/)library/folders/permissions(/)(:folder_id)(/)dataset(/)(:dataset_id)": "show_library_folder",
},
require_login: ["show_user", "show_user_form", "show_workflows", "show_cloud_auth", "show_external_ids"],
+1
View File
@@ -193,6 +193,7 @@ def app_pair(global_conf, load_app_kwds=None, wsgi_preflight=True, **kwargs):
webapp.add_client_route('/interactivetool_entry_points/list')
webapp.add_client_route('/library/folders/{folder_id}')
webapp.add_client_route('/library/folders/permissions/{folder_id}')
webapp.add_client_route('/library/folders/permissions/{folder_id}/dataset/{dataset_id}')
# ==== Done
# Indicate that all configuration settings have been provided