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

Inheritable config files. #897

Merged
merged 1 commit into from
Jul 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions girder/girder_large_image/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from girder.constants import AccessType
from girder.exceptions import ValidationException
from girder.models.file import File
from girder.models.folder import Folder
from girder.models.item import Item
from girder.models.notification import Notification
from girder.models.setting import Setting
Expand Down Expand Up @@ -286,6 +287,14 @@ def validateDefaultViewer(doc):
doc['value'] = str(doc['value']).strip()


@setting_utilities.validator(constants.PluginSettings.LARGE_IMAGE_CONFIG_FOLDER)
def validateFolder(doc):
if not doc.get('value', None):
doc['value'] = None
else:
Folder().load(doc['value'], force=True, exc=True)


# Defaults

# Defaults that have fixed values can just be added to the system defaults
Expand Down
1 change: 1 addition & 0 deletions girder/girder_large_image/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ class PluginSettings:
LARGE_IMAGE_MAX_THUMBNAIL_FILES = 'large_image.max_thumbnail_files'
LARGE_IMAGE_MAX_SMALL_IMAGE_SIZE = 'large_image.max_small_image_size'
LARGE_IMAGE_AUTO_USE_ALL_FILES = 'large_image.auto_use_all_files'
LARGE_IMAGE_CONFIG_FOLDER = 'large_image.config_folder'
37 changes: 28 additions & 9 deletions girder/girder_large_image/rest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
from girder.models.folder import Folder
from girder.models.group import Group
from girder.models.item import Item
from girder.models.setting import Setting

from .. import constants


def addSystemEndpoints(apiRoot):
Expand Down Expand Up @@ -96,10 +99,11 @@ def adjustConfigForUser(config, user):
)
@boundHandler()
def getYAMLConfigFile(self, folder, name):
addConfig = None
user = self.getCurrentUser()
last = False
while folder:
item = Item().findOne({'folderId': folder['_id'], 'name': name},
user=user, level=AccessType.READ)
item = Item().findOne({'folderId': folder['_id'], 'name': name})
if item:
for file in Item().childFiles(item):
if file['size'] > 10 * 1024 ** 2:
Expand All @@ -110,13 +114,28 @@ def getYAMLConfigFile(self, folder, name):
# combine and adjust config values based on current user
if isinstance(config, dict) and 'access' in config or 'group' in config:
config = adjustConfigForUser(config, user)
return config
if addConfig and isinstance(config, dict):
config = _mergeDictionaries(config, addConfig)
if not isinstance(config, dict) or config.get('__inherit__') is not True:
return config
config.pop('__inherit__')
addConfig = config
if last:
break
if folder['parentCollection'] != 'folder':
if folder['name'] == '.config':
break
folder = Folder().findOne({
'parentId': folder['parentId'],
'parentCollection': folder['parentCollection'],
'name': '.config'})
if folder['name'] != '.config':
folder = Folder().findOne({
'parentId': folder['parentId'],
'parentCollection': folder['parentCollection'],
'name': '.config'})
else:
last = 'setting'
if not folder or last == 'setting':
folderId = Setting().get(constants.PluginSettings.LARGE_IMAGE_CONFIG_FOLDER)
if not folderId:
break
folder = Folder().load(folderId, force=True)
last = True
else:
folder = Folder().load(folder['parentId'], user=user, level=AccessType.READ)
return addConfig
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ form#g-large-image-form(role="form")
| Details to show on item pages for admins and owners of the images.
input.input-sm.form-control.g-large-image-show-item-extra-admin(
type="text", value=settings['large_image.show_item_extra_admin'], placeholder=detailplaceholder, title=detailtitle)
.form-group
label(for="g-large-image-config-folder") Configuration Folder
p.g-large-image-description
| If a configuration folder is specified, configuration files stored there are used for the entire system if they are not overridden by local configuration files.
.input-group.input-group-sm
input#g-large-image-config-folder.form-control.input-sm(
type="text", value=settings['large_image.config_folder'] || '',
title="A folder to store configuration files.")
.input-group-btn
button.g-open-browser.btn.btn-default(type="button")
i.icon-folder-open
.form-group
label
| Maximum number of thumbnail files to save per item
Expand Down
46 changes: 43 additions & 3 deletions girder/girder_large_image/web_client/views/configView.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import $ from 'jquery';
import View from '@girder/core/views/View';

import PluginConfigBreadcrumbWidget from '@girder/core/views/widgets/PluginConfigBreadcrumbWidget';
import { restRequest } from '@girder/core/rest';
import { AccessType } from '@girder/core/constants';
import events from '@girder/core/events';
import { restRequest } from '@girder/core/rest';
import BrowserWidget from '@girder/core/views/widgets/BrowserWidget';
import PluginConfigBreadcrumbWidget from '@girder/core/views/widgets/PluginConfigBreadcrumbWidget';

import ConfigViewTemplate from '../templates/largeImageConfig.pug';
import '../stylesheets/largeImageConfig.styl';
Expand Down Expand Up @@ -52,14 +54,47 @@ var ConfigView = View.extend({
}, {
key: 'large_image.show_item_extra_admin',
value: this.$('.g-large-image-show-item-extra-admin').val()
}, {
key: 'large_image.config_folder',
value: (this.$('#g-large-image-config-folder').val() || '').split(' ')[0]
}]);
}
},
'click .g-open-browser': '_openBrowser'
},
initialize: function () {
ConfigView.getSettings((settings) => {
this.settings = settings;
this.render();
});

this._browserWidgetView = new BrowserWidget({
parentView: this,
titleText: 'Configuration File Location',
helpText: 'Browse to a location to select it.',
submitText: 'Select Location',
validate: function (model) {
let isValid = $.Deferred();
if (!model || model.get('_modelType') !== 'folder') {
isValid.reject('Please select a folder.');
} else {
isValid.resolve();
}
return isValid.promise();
}
});
this.listenTo(this._browserWidgetView, 'g:saved', function (val) {
this.$('#g-large-image-config-folder').val(val.id);
restRequest({
url: `resource/${val.id}/path`,
method: 'GET',
data: { type: val.get('_modelType') }
}).done((result) => {
// Only add the resource path if the value wasn't altered
if (this.$('#g-large-image-config-folder').val() === val.id) {
this.$('#g-large-image-config-folder').val(`${val.id} (${result})`);
}
});
});
},

render: function () {
Expand Down Expand Up @@ -101,6 +136,11 @@ var ConfigView = View.extend({
resp.responseJSON.message
);
});
},

_openBrowser: function () {
console.log('A');
this._browserWidgetView.setElement($('#g-dialog-container')).render();
}
}, {
/* Class methods and objects */
Expand Down
65 changes: 64 additions & 1 deletion girder/test_girder/test_large_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ def testYAMLConfigFile(server, admin, user, fsAssetstore):
collection, 'folder A', parentType='collection',
creator=admin)
colFolderB = Folder().createFolder(
colFolderA, 'folder C', creator=admin)
colFolderA, 'folder B', creator=admin)
groupA = Group().createGroup('Group A', admin)

resp = server.request(
Expand Down Expand Up @@ -475,3 +475,66 @@ def testYAMLConfigFile(server, admin, user, fsAssetstore):
path='/folder/%s/yaml_config/sample.json' % str(colFolderB['_id']), user=admin)
assert utilities.respStatus(resp) == 200
assert resp.json['keyA'] == 'value6'


@pytest.mark.usefixtures('unbindLargeImage')
@pytest.mark.plugin('large_image')
def testYAMLConfigFileInherit(server, admin, user, fsAssetstore):
# Create some resources to use in the tests
collection = Collection().createCollection(
'collection A', admin)
colFolderA = Folder().createFolder(
collection, 'folder A', parentType='collection',
creator=admin)
colFolderB = Folder().createFolder(
colFolderA, 'folder B', creator=admin)
colFolderConfig = Folder().createFolder(
collection, '.config', parentType='collection',
creator=admin)
collectionB = Collection().createCollection(
'collection B', admin)
configFolder = Folder().createFolder(
collectionB, 'any', parentType='collection',
creator=admin)
Setting().set(constants.PluginSettings.LARGE_IMAGE_CONFIG_FOLDER, str(configFolder['_id']))
utilities.uploadText(
json.dumps({
'keyA': 'value1',
'keyB': 'value2',
'keyC': 'value3',
'__inherit__': True}),
admin, fsAssetstore, colFolderB, 'sample.json')
utilities.uploadText(
json.dumps({
'keyA': 'value4',
'keyD': 'value5',
'__inherit__': True}),
admin, fsAssetstore, colFolderConfig, 'sample.json')
resp = server.request(
path='/folder/%s/yaml_config/sample.json' % str(colFolderB['_id']), user=admin)
assert utilities.respStatus(resp) == 200
assert resp.json['keyA'] == 'value1'
assert resp.json['keyB'] == 'value2'
assert resp.json['keyC'] == 'value3'
assert resp.json['keyD'] == 'value5'
utilities.uploadText(
json.dumps({
'keyB': 'value6',
'keyE': 'value7'}),
admin, fsAssetstore, configFolder, 'sample.json')
resp = server.request(
path='/folder/%s/yaml_config/sample.json' % str(colFolderB['_id']), user=admin)
assert utilities.respStatus(resp) == 200
assert resp.json['keyA'] == 'value1'
assert resp.json['keyB'] == 'value2'
assert resp.json['keyC'] == 'value3'
assert resp.json['keyD'] == 'value5'
assert resp.json['keyE'] == 'value7'
Folder().remove(colFolderConfig, user=admin)
resp = server.request(
path='/folder/%s/yaml_config/sample.json' % str(colFolderB['_id']), user=admin)
assert utilities.respStatus(resp) == 200
assert resp.json['keyA'] == 'value1'
assert resp.json['keyB'] == 'value2'
assert resp.json['keyC'] == 'value3'
assert resp.json['keyE'] == 'value7'
Loading