ckan
ckan copied to clipboard
:construction_worker: IUserForm implementation :construction_worker:
Fixes #6070
This PR is still WIP and im hopping to finish it soon after the few things we would need to decide on.
Becase it was really tricky to separate the private and public data in same column, i decided to add separate one called, for now, plugin_data
(this was disscused some time ago)
However, I'm still figuring out an effective method to provide information which plugin is providing custom data so this solution is currently using public
namespace.
@ckan/core I would appreciate any suggestions or feedback.
@wardi thanks for the ValidatorFactory tip, now we can get the plugins name.
So i will need some suggestion about the naming of the plugin_data
I considered few options as plugin_fields
, extra fileds
, custom_data
but im not sure if those can be explainatory enough
For the option to keep the data in one column, when we will have multiple extensions implementing this interface, we would endup having following structure
"plugin_data": {
"example_plugin1": {
"private": {
"key1": "value1",
"key2": "value2"
},
"public": {
"key1": "value1",
"key2": "value2"
}
},
"example_plugin2": {
"private": {
"key1": "value1",
"key2": "value2"
},
"public": {
"key1": "value1",
"key2": "value2"
}
}
}
With this mixed public and private data per extension, i will have some questions and considerations
- How should validators be structured to handle both public and private data?
- How we will define the default schema ?
Any feedback and suggestions are appriciated
My suggestion comes from Ian's comment here
You are now exposing the whole plugin_data
on the model dictization stage. And, in addition, you have load_plugin_data
which can copy some of the plugin_data
items on the top level of the user dictionary. For example, if I have the plugin_data: {custom: {KEY: VALUE}}
and I patch show_user_schema
with {KEY: [load_plugin_data('custom')]}
, I'll get the following result:
user == {
"name": "sergey",
"KEY": "VALUE",
"plugin_data": {"custom": {"KEY": "VALUE"}}
}
You see, the whole plugin_data
is unconditionally shown and any attempt to use load_plugin_data
leads to data duplication.
Now we go back to Ian's idea. Imagine that the whole plugin_data
is never shown, i.e., it's always private. There are no private/public
sections inside plugin data - the whole plugin_data
attribute is hidden.
If you want to make something "public", you just add the load_plugin_data
validator to the show_user_schema
. As a result, a specific key from the private plugin_data
gets copied on the top-level of the user dictionary and becomes public.
And here comes that point that was unclear to you before. If you just do as I suggested before, you'll see that load_plugin_data
cannot pluck properties from plugin_data
. As you are removing plugin_data
on the dictization level to make it invisible, data.get("plugin_data")
line from the load_plugin_data
validator returns nothing.
To overcome this, you can move plugin_data
into context on dictization level:
def user_dictize(...):
...
context['plugin_data'] = result_dict.pop('plugin_data', {})
And then, inside the load_plugin_data
validator, you can access plugin_data
from the context(instead of data
):
def load_plugin_data(key, data, error, CONTEXT):
plugin_data = CONTEXT.get("plugin_data")
...
@wardi ive followed the other extras
implementations.