Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/global sharing #2929

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
5a97b39
brought in first working ability to configure global read access by g…
rkboyce Apr 17, 2024
61dcae0
first working configuration of sharing using an authoring role
rkboyce Apr 22, 2024
8f46884
some fixes to global sharing after testing; moved the shared reader r…
rkboyce Apr 22, 2024
b99d5d5
started to implement the ability to hide the share-global buttons but…
rkboyce Apr 23, 2024
8396b4d
changed the 'shared artifact reader' role checked by Atlas to be the …
rkboyce May 6, 2024
0493316
added the configurable ability to restrict generation of a given coho…
rkboyce May 9, 2024
7e21378
feat: introduce a new permission instead of relying on a role
pieterlukasse May 10, 2024
649cc7e
fix: correct styling for sharing buttons on access modal ui
pieterlukasse May 14, 2024
0946559
fix: cleanup/remove unnecessary parts
pieterlukasse May 14, 2024
ca11cc3
Merge pull request #2 from uc-cdis/fix/final-global-sharing
rkboyce May 16, 2024
b24266b
fix: adjust permission name to "artifact:global:share:put"
pieterlukasse May 17, 2024
b162fd5
Merge pull request #3 from uc-cdis/fix/final-global-sharing_part2
rkboyce May 17, 2024
3bcffd5
fix: remove dead code
pieterlukasse Aug 23, 2024
058ace5
Merge pull request #7 from pieterlukasse/patch-1
rkboyce Sep 2, 2024
b8017b9
Merge branch 'OHDSI:master' into feature/global-sharing
rkboyce Sep 2, 2024
4872345
fix: better name for isPermittedGlobalShareArtifact
pieterlukasse May 17, 2024
01eca8c
Merge pull request #4 from uc-cdis/fix/owner_check_and_remove_dead_code
rkboyce Sep 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions js/components/security/access/configure-access-modal.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@
readRoleOptions: readRoleOptions,
readRoleSearch: readRoleSearch,
writeRoleOptions: writeRoleOptions,
writeRoleSearch: writeRoleSearch
writeRoleSearch: writeRoleSearch,
shareFlag: shareFlag,
grantGlobalReadAccess: grantGlobalReadAccess,
revokeGlobalReadAccess: revokeGlobalReadAccess,
}">
<loading data-bind="css: classes('loading-panel'), visible: isLoading()" params="status: ko.i18n('common.configureAccessModal.loadingAccessList', 'Loading access list...')"></loading>


<div data-bind="css: classes()">
<div data-bind="if: !isLoading()">
<div data-bind="css: classes('new-access')">
<label data-bind="css: classes('new-access-label'), text: ko.i18n('common.configureAccessModal.addWriteAccessToRole', 'Add WRITE access to role:')"></label>
<label data-bind="css: classes('new-access-label'), text: ko.i18n('common.configureAccessModal.addWriteAccessToRole', 'Grant WRITE access to role:')"></label>
<div class="input-group"
data-bind="css: classes({ element: 'new-access-btn-group', extra: ['new-access-btn-group'] })">
<input
Expand Down Expand Up @@ -48,8 +53,10 @@
</div>
</div>
</div>

<div>
<div data-bind="css: classes('new-access')">
<label data-bind="css: classes('new-access-label'), text: ko.i18n('common.configureAccessModal.addReadAccessToRole', 'Add READ access to role:')"></label>
<label data-bind="css: classes('new-access-label'), text: ko.i18n('common.configureAccessModal.addReadAccessToRole', 'Grant READ access to role:')"></label>
<div class="input-group"
data-bind="css: classes({ element: 'new-access-btn-group', extra: ['new-access-btn-group'] })">
<input
Expand Down Expand Up @@ -77,6 +84,33 @@
</div>
</div>
</div>


<div><br></div>
<!-- A BUTTON TO SHARE GLOBALLY -->
<div>
<label data-bind="css: classes('new-access-label'), text: ko.i18n('common.configureAccessModal.globalReadStatus', 'Status of global READ access:')"></label>
<div/>
<div class="btn-group" data-toggle="buttons">
<label data-bind="css: { active: shareFlag()},
click: function () { shareFlag(false); grantGlobalReadAccess();},
clickBubble: false,
text: ko.i18n('common.configureAccessModal.globalReadStatusNotGranted', 'Granted')
"
class="btn btn-primary",
/>
<label data-bind="css: { active: !shareFlag()},
click: function () { shareFlag(true); revokeGlobalReadAccess();},
clickBubble: false,
text: ko.i18n('common.configureAccessModal.globalReadStatusIsGranted', 'Not Granted')
"
class="btn btn-primary",
/>
</div>
</div>

<div><br></div>

</div>
</div>
</atlas-modal>
41 changes: 37 additions & 4 deletions js/components/security/access/configure-access-modal.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
define([
'knockout',
'text!./configure-access-modal.html',
'text!./configure-access-modal.html',
'components/Component',
'utils/CommonUtils',
'utils/AutoBind',
'less!./configure-access-modal.less',
'databindings',
], function (
ko,
view,
view,
Component,
commonUtils,
AutoBind
Expand All @@ -34,6 +34,8 @@ define([
this.readRoleSearch = ko.observable();
this.readRoleSearch.subscribe(str => this.loadReadRoleSuggestions(str));

this.shareFlag = ko.observable(true);

this.isOwnerFn = params.isOwnerFn;
this.grantAccessFn = params.grantAccessFn;
this.loadAccessListFn = params.loadAccessListFn;
Expand Down Expand Up @@ -109,7 +111,14 @@ define([
} catch (ex) {
console.log(ex);
}
this.isLoading(false);
this.isLoading(false);

// update shareFlag depending on if the shared artifacts reader role is in readAccessList
function testForGlobalRead(value, index, array) {
return value.id === 1; // the 'public' role that every use should have
rkboyce marked this conversation as resolved.
Show resolved Hide resolved
}
let tst = this.readAccessList().some(testForGlobalRead);
this.shareFlag(tst);
}

async grantAccess(perm_type) {
Expand All @@ -124,7 +133,6 @@ define([
const role = this.readRoleSuggestions().find(r => r.name === this.readRoleName());
await this.grantAccessFn(role.id,'READ');
await this._loadReadAccessList();
this.readRoleName('');
}
} catch (ex) {
console.log(ex);
Expand All @@ -142,6 +150,31 @@ define([
}
this.isLoading(false);
}


async grantGlobalReadAccess() {
this.isLoading(true);
try {
console.log('grantGlobalReadAccess function called to grant read permissions!! shareflag: ' + this.shareFlag());
await this.grantAccessFn('1','READ'); // 1 is the 'public' role, a SYSTEM role every user should have
await this.loadAccessList();
} catch (ex) {
console.log(ex);
}
this.isLoading(false);
}

async revokeGlobalReadAccess() {
this.isLoading(true);
try {
console.log('revokeGlobalReadAccess function called to REVOKE read permissions!! shareflag: ' + this.shareFlag());
await this.revokeAccessFn('1','READ'); // 1 is the 'public' role, a SYSTEM role every user should have
await this.loadAccessList();
} catch (ex) {
console.log(ex);
}
this.isLoading(false);
}
}

return commonUtils.build('configure-access-modal', ConfigureAccessModal, view);
Expand Down
12 changes: 3 additions & 9 deletions js/pages/cohort-definitions/cohort-definition-manager.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<button class="btn btn-primary"
data-bind="visible: !previewVersion(), title: ko.i18n('cohortDefinitions.cohortDefinitionManager.getLinkCohortTitle', 'Get a link to this cohort definition'), enable: !dirtyFlag().isDirty() && !isProcessing(), click: function () { $component.cohortLinkModalOpened(true) }"><i class="fa fa-link"></i></button>

<!-- ko if: enablePermissionManagement -->
<!-- ko if: (enablePermissionManagement() === true && userCanShare() === true) -->
<button class="btn btn-primary"
data-bind="title: ko.i18n('common.configureAccess', 'Configure access'), visible: isOwner() && !previewVersion(), click: () => isAccessModalShown(!isAccessModalShown())">
<i class="fa fa-lock"></i>
Expand Down Expand Up @@ -77,20 +77,14 @@
</li>

<li role="presentation"
data-bind="visible: !previewVersion(), css: { active: $component.tabMode() == 'samples' }, click: clickSampleTab">
<a data-bind="text: ko.i18n('cohortDefinitions.cohortDefinitionManager.tabs.samples', 'Samples')"></a>
data-bind="visible: !previewVersion(), css: { active: $component.tabMode() == 'samples' }, click: clickSampleTab">
<a data-bind="text: ko.i18n('cohortDefinitions.cohortDefinitionManager.tabs.samples', 'Samples')"></a>
</li>

<li role="presentation"
data-bind="visible: !previewVersion(), css: { active: $component.tabMode() == 'reporting' }, click: function() { $component.selectTab('reporting'); }">
<a data-bind="text: ko.i18n('cohortDefinitions.cohortDefinitionManager.tabs.reporting', 'Reporting')"></a>
</li>
<!--
<li role="presentation"
data-bind="visible: !previewVersion(), css: { active: $component.tabMode() == 'explore' }, click: function() { $component.selectTab('explore'); }">
<a data-bind="text: ko.i18n('cohortDefinitions.cohortDefinitionManager.tabs.explore', 'Explore')"></a>
</li>
-->
<li role="presentation"
data-bind="visible: !previewVersion(), css: { active: $component.tabMode() == 'export' }, click: () => { $component.selectTab('export'); refreshPrintFriendly(); }">
<a data-bind="text: ko.i18n('cohortDefinitions.cohortDefinitionManager.tabs.export', 'Export')"></a>
Expand Down
17 changes: 13 additions & 4 deletions js/pages/cohort-definitions/cohort-definition-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
'utilities/sql',
'components/conceptset/conceptset-list',
'components/name-validation',
'components/versions/versions'
'components/versions/versions',
], function (
$,
ko,
Expand Down Expand Up @@ -99,7 +99,7 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
globalConstants,
constants,
{ entityType },
conceptSetUtils,
conceptSetUtils,
) {
const includeKeys = ["UseEventEnd"];
function pruneJSON(key, value) {
Expand Down Expand Up @@ -198,7 +198,16 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
this.pollTimeoutId = null;
this.authApi = authApi;
this.config = config;
this.enablePermissionManagement = config.enablePermissionManagement;

this.enablePermissionManagement = ko.observable(config.enablePermissionManagement);
if (config.enablePermissionManagement) {
this.userCanShare = ko.observable(
!config.limitedPermissionManagement ||
authApi.isPermittedGlobalShareArtifact());
} else {
this.userCanShare = ko.observable(false);
}

this.relatedSourcecodesOptions = globalConstants.relatedSourcecodesOptions;
this.commonUtils = commonUtils;
this.isLoading = ko.observable(false);
Expand Down Expand Up @@ -914,7 +923,7 @@ define(['jquery', 'knockout', 'text!./cohort-definition-manager.html',
}

// METHODS

startPolling(cd, source) {
this.pollId = PollService.add({
callback: () => this.queryHeraclesJob(cd, source),
Expand Down
2 changes: 1 addition & 1 deletion js/pages/concept-sets/conceptset-manager.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<button type="button" class="btn btn-primary" data-bind="click: () => isTagsModalShown(!isTagsModalShown()), visible: canEdit() && !previewVersion(), css: { disabled: isProcessing() }, title: ko.i18n('common.tags', 'Tags')"><i class="fa fa-tags"></i></button>
<button type="button" class="btn btn-primary" data-bind="visible: !previewVersion(), click: optimize, css: { disabled: !canOptimize() || isProcessing() }, text: ko.i18n('cs.manager.optimize', 'Optimize')"></button>

<!-- ko if: enablePermissionManagement -->
<!-- ko if: (enablePermissionManagement() === true && userCanShare() === true) -->
<button class="btn btn-primary" data-bind="visible: !previewVersion() && isOwner(), click: () => isAccessModalShown(!isAccessModalShown()), title: ko.i18n('common.configureAccess', 'Configure access')">
<i class="fa fa-lock"></i>
</button>
Expand Down
11 changes: 10 additions & 1 deletion js/pages/concept-sets/conceptset-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,16 @@ define([
this.canCopy = ko.computed(() => {
return this.currentConceptSet() && this.currentConceptSet().id > 0;
});
this.enablePermissionManagement = config.enablePermissionManagement;

this.enablePermissionManagement = ko.observable(config.enablePermissionManagement);
if (config.enablePermissionManagement) {
this.userCanShare = ko.observable(
!config.limitedPermissionManagement ||
authApi.isPermittedGlobalShareArtifact());
} else {
this.userCanShare = ko.observable(false);
}

this.isSaving = ko.observable(false);
this.isDeleting = ko.observable(false);
this.isOptimizing = ko.observable(false);
Expand Down
19 changes: 18 additions & 1 deletion js/services/AuthAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,12 @@ define(function(require, exports) {
return isPermitted('cohortdefinition:' + id + ':copy:get');
}

var isPermittedGlobalShareArtifact = function() {
// special * permission (intended for admins) that allows the
// user to share any artifact with a "global reader role":
return isPermitted('artifact:global:share:put');
}

var isPermittedUpdateCohort = function(id) {
var permission = 'cohortdefinition:' + id + ':put';
return isPermitted(permission);
Expand All @@ -407,8 +413,18 @@ define(function(require, exports) {
}

var isPermittedGenerateCohort = function(cohortId, sourceKey) {
return isPermitted('cohortdefinition:' + cohortId + ':generate:' + sourceKey + ':get') &&
var v = isPermitted('cohortdefinition:' + cohortId + ':generate:' + sourceKey + ':get') &&
isPermitted('cohortdefinition:' + cohortId + ':info:get');

// By default, everyone can generate any artifact they have
// permission to read. If limitedPermissionManagement has
// been set to true, the default
// generate functionality is not desired. Rather, users will have to
// have a permission that allows them to update the specific cohort definition.
if (config.limitedPermissionManagement){
v = v && isPermitted('cohortdefinition:' + cohortId + ':put')
}
return v
}

var isPermittedReadCohortReport = function(cohortId, sourceKey) {
Expand Down Expand Up @@ -576,6 +592,7 @@ define(function(require, exports) {
isPermittedReadCohort: isPermittedReadCohort,
isPermittedCreateCohort: isPermittedCreateCohort,
isPermittedCopyCohort: isPermittedCopyCohort,
isPermittedGlobalShareArtifact: isPermittedGlobalShareArtifact,
isPermittedUpdateCohort: isPermittedUpdateCohort,
isPermittedDeleteCohort: isPermittedDeleteCohort,
isPermittedGenerateCohort: isPermittedGenerateCohort,
Expand Down
Loading