chore(schema): Add a belongsTo field in the schema.

The goal is to use this as a security measure, to check that the
updated properties belong the the "subject" when receiving sync
operations.
This commit is contained in:
Alexis Métaireau 2024-05-09 12:46:52 +02:00
parent 28a359e03f
commit 25ccdde0b0

View file

@ -1,22 +1,40 @@
import { translate } from './i18n.js' import { translate } from './i18n.js'
// Possible impacts /**
// ['ui', 'data', 'limit-bounds', 'datalayer-index', 'remote-data', 'background' 'sync'] * This SCHEMA defines metadata about properties.
*
* This is here in order to have a centered place where all properties are specified.
*
* Each property defines:
*
* - `type`: The type of the data
* - `impacts`: A list of impacts than happen when this property is updated, among
* 'ui', 'data', 'limit-bounds', 'datalayer-index', 'remote-data',
* 'background' 'sync'.
* - `belongsTo`: A list of conceptual objects this property belongs to, among
* 'map', 'feature', 'datalayer'.
*
* - Extra keys are being passed to the FormBuilder automatically.
*/
// This is sorted alphabetically // This is sorted alphabetically
export const SCHEMA = { export const SCHEMA = {
browsable: { browsable: {
impacts: ['ui'],
type: Boolean, type: Boolean,
impacts: ['ui'],
belongsTo: ['datalayer'],
}, },
captionBar: { captionBar: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
label: translate('Do you want to display a caption bar?'), label: translate('Do you want to display a caption bar?'),
default: false, default: false,
}, },
captionControl: { captionControl: {
type: Boolean, type: Boolean,
impacts: ['ui'],
belongsTo: ['map'],
nullable: true, nullable: true,
label: translate('Display the caption control'), label: translate('Display the caption control'),
default: true, default: true,
@ -24,12 +42,14 @@ export const SCHEMA = {
captionMenus: { captionMenus: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
label: translate('Do you want to display caption menus?'), label: translate('Do you want to display caption menus?'),
default: true, default: true,
}, },
color: { color: {
type: String, type: String,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'],
handler: 'ColorPicker', handler: 'ColorPicker',
label: translate('color'), label: translate('color'),
helpEntries: 'colorValue', helpEntries: 'colorValue',
@ -39,14 +59,17 @@ export const SCHEMA = {
choropleth: { choropleth: {
type: Object, type: Object,
impacts: ['data'], impacts: ['data'],
belongsTo: ['datalayer'],
}, },
cluster: { cluster: {
type: Object, type: Object,
impacts: ['data'], impacts: ['data'],
belongsTo: ['datalayer'],
}, },
dashArray: { dashArray: {
type: String, type: String,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer'],
label: translate('dash array'), label: translate('dash array'),
helpEntries: 'dashArray', helpEntries: 'dashArray',
inheritable: true, inheritable: true,
@ -54,6 +77,7 @@ export const SCHEMA = {
datalayersControl: { datalayersControl: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
nullable: true, nullable: true,
handler: 'DataLayersControl', handler: 'DataLayersControl',
label: translate('Display the data layers control'), label: translate('Display the data layers control'),
@ -62,6 +86,7 @@ export const SCHEMA = {
defaultView: { defaultView: {
type: String, type: String,
impacts: [], // no need to update the ui, only useful when loading the map impacts: [], // no need to update the ui, only useful when loading the map
belongsTo: ['map'],
label: translate('Default view'), label: translate('Default view'),
choices: [ choices: [
['center', translate('Saved center and zoom')], ['center', translate('Saved center and zoom')],
@ -74,27 +99,32 @@ export const SCHEMA = {
description: { description: {
type: 'Text', type: 'Text',
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map', 'datalayer'],
label: translate('description'), label: translate('description'),
helpEntries: 'textFormatting', helpEntries: 'textFormatting',
}, },
displayOnLoad: { displayOnLoad: {
type: Boolean, type: Boolean,
impacts: [], impacts: [],
belongsTo: ['datalayer'], // XXX ?
}, },
displayPopupFooter: { displayPopupFooter: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'], // XXX ?
label: translate('Do you want to display popup footer?'), label: translate('Do you want to display popup footer?'),
default: false, default: false,
}, },
easing: { easing: {
type: Boolean, type: Boolean,
impacts: [], impacts: [],
belongsTo: ['feature'], // XXX ?
default: false, default: false,
}, },
editinosmControl: { editinosmControl: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
nullable: true, nullable: true,
label: translate('Display the control to open OpenStreetMap editor'), label: translate('Display the control to open OpenStreetMap editor'),
default: null, default: null,
@ -102,6 +132,7 @@ export const SCHEMA = {
embedControl: { embedControl: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
nullable: true, nullable: true,
label: translate('Display the embed control'), label: translate('Display the embed control'),
default: true, default: true,
@ -109,10 +140,12 @@ export const SCHEMA = {
facetKey: { facetKey: {
type: String, type: String,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['datalayer'],
}, },
fill: { fill: {
type: Boolean, type: Boolean,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'],
label: translate('fill'), label: translate('fill'),
helpEntries: 'fill', helpEntries: 'fill',
inheritable: true, inheritable: true,
@ -121,6 +154,7 @@ export const SCHEMA = {
fillColor: { fillColor: {
type: String, type: String,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'],
handler: 'ColorPicker', handler: 'ColorPicker',
label: translate('fill color'), label: translate('fill color'),
helpEntries: 'fillColor', helpEntries: 'fillColor',
@ -129,6 +163,7 @@ export const SCHEMA = {
fillOpacity: { fillOpacity: {
type: Number, type: Number,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'],
min: 0.1, min: 0.1,
max: 1, max: 1,
step: 0.1, step: 0.1,
@ -139,16 +174,19 @@ export const SCHEMA = {
filterKey: { filterKey: {
type: String, type: String,
impacts: [], impacts: [],
belongsTo: ['map', 'datalayer', 'feature'], // XXX ?
}, },
fromZoom: { fromZoom: {
type: Number, type: Number,
impacts: [], // not needed impacts: [], // not needed
belongsTo: ['map'], // XXX ?
label: translate('From zoom'), label: translate('From zoom'),
helpText: translate('Optional.'), helpText: translate('Optional.'),
}, },
fullscreenControl: { fullscreenControl: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
nullable: true, nullable: true,
label: translate('Display the fullscreen control'), label: translate('Display the fullscreen control'),
default: true, default: true,
@ -156,10 +194,12 @@ export const SCHEMA = {
heat: { heat: {
type: Object, type: Object,
impacts: ['data'], impacts: ['data'],
belongsTo: ['datalayer'],
}, },
iconClass: { iconClass: {
type: String, type: String,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'],
label: translate('Icon shape'), label: translate('Icon shape'),
inheritable: true, inheritable: true,
choices: [ choices: [
@ -173,6 +213,7 @@ export const SCHEMA = {
iconOpacity: { iconOpacity: {
type: Number, type: Number,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'],
min: 0.1, min: 0.1,
max: 1, max: 1,
step: 0.1, step: 0.1,
@ -183,6 +224,7 @@ export const SCHEMA = {
iconUrl: { iconUrl: {
type: String, type: String,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'],
handler: 'IconUrl', handler: 'IconUrl',
label: translate('Icon symbol'), label: translate('Icon symbol'),
inheritable: true, inheritable: true,
@ -190,10 +232,12 @@ export const SCHEMA = {
inCaption: { inCaption: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: [], // XXX ?
}, },
interactive: { interactive: {
type: Boolean, type: Boolean,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'],
label: translate('Allow interactions'), label: translate('Allow interactions'),
helpEntries: 'interactive', helpEntries: 'interactive',
inheritable: true, inheritable: true,
@ -202,6 +246,7 @@ export const SCHEMA = {
labelDirection: { labelDirection: {
type: String, type: String,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'],
label: translate('Label direction'), label: translate('Label direction'),
inheritable: true, inheritable: true,
choices: [ choices: [
@ -216,12 +261,14 @@ export const SCHEMA = {
labelInteractive: { labelInteractive: {
type: Boolean, type: Boolean,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'],
label: translate('Labels are clickable'), label: translate('Labels are clickable'),
inheritable: true, inheritable: true,
}, },
labelKey: { labelKey: {
type: String, type: String,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'], // XXX ?
helpEntries: 'labelKey', helpEntries: 'labelKey',
placeholder: translate('Default: name'), placeholder: translate('Default: name'),
label: translate('Label key'), label: translate('Label key'),
@ -230,50 +277,59 @@ export const SCHEMA = {
licence: { licence: {
type: String, type: String,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map', 'datalayer'], // XXX ?
label: translate('licence'), label: translate('licence'),
}, },
limitBounds: { limitBounds: {
type: Object, type: Object,
impacts: ['limit-bounds'], impacts: ['limit-bounds'],
belongsTo: ['map'],
}, },
locateControl: { locateControl: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
nullable: true, nullable: true,
label: translate('Display the locate control'), label: translate('Display the locate control'),
}, },
longCredit: { longCredit: {
type: 'Text', type: 'Text',
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
label: translate('Long credits'), label: translate('Long credits'),
helpEntries: ['longCredit', 'textFormatting'], helpEntries: ['longCredit', 'textFormatting'],
}, },
measureControl: { measureControl: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
nullable: true, nullable: true,
label: translate('Display the measure control'), label: translate('Display the measure control'),
}, },
miniMap: { miniMap: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
label: translate('Do you want to display a minimap?'), label: translate('Do you want to display a minimap?'),
default: false, default: false,
}, },
moreControl: { moreControl: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
label: translate('Do you want to display the «more» control?'), label: translate('Do you want to display the «more» control?'),
default: true, default: true,
}, },
name: { name: {
type: String, type: String,
impacts: ['ui', 'data'], impacts: ['ui', 'data'],
belongsTo: ['map', 'datalayer', 'feature'],
label: translate('name'), label: translate('name'),
}, },
onLoadPanel: { onLoadPanel: {
type: String, type: String,
impacts: [], // This is what happens during the map instantiation impacts: [], // This is what happens during the map instantiation
belongsTo: ['map'],
label: translate('Do you want to display a panel on load?'), label: translate('Do you want to display a panel on load?'),
choices: [ choices: [
['none', translate('None')], ['none', translate('None')],
@ -287,6 +343,7 @@ export const SCHEMA = {
opacity: { opacity: {
type: Number, type: Number,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'],
min: 0.1, min: 0.1,
max: 1, max: 1,
step: 0.1, step: 0.1,
@ -296,6 +353,8 @@ export const SCHEMA = {
}, },
outlink: { outlink: {
type: String, type: String,
impacts: ['data'],
belongsTo: ['feature'],
label: translate('Link to…'), label: translate('Link to…'),
helpEntries: 'outlink', helpEntries: 'outlink',
placeholder: 'http://...', placeholder: 'http://...',
@ -303,7 +362,8 @@ export const SCHEMA = {
}, },
outlinkTarget: { outlinkTarget: {
type: String, type: String,
impacts: [], impacts: ['data'],
belongsTo: ['feature'],
label: translate('Open link in…'), label: translate('Open link in…'),
inheritable: true, inheritable: true,
default: 'blank', default: 'blank',
@ -316,22 +376,26 @@ export const SCHEMA = {
overlay: { overlay: {
type: Object, type: Object,
impacts: ['background'], impacts: ['background'],
belongsTo: ['map'],
}, },
permanentCredit: { permanentCredit: {
type: 'Text', type: 'Text',
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
label: translate('Permanent credits'), label: translate('Permanent credits'),
helpEntries: ['permanentCredit', 'textFormatting'], helpEntries: ['permanentCredit', 'textFormatting'],
}, },
permanentCreditBackground: { permanentCreditBackground: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
label: translate('Permanent credits background'), label: translate('Permanent credits background'),
default: true, default: true,
}, },
popupContentTemplate: { popupContentTemplate: {
type: 'Text', type: 'Text',
impacts: [], // not needed impacts: [], // not needed
belongsTo: ['map', 'datalayer', 'feature'],
label: translate('Popup content template'), label: translate('Popup content template'),
helpEntries: ['dynamicProperties', 'textFormatting'], helpEntries: ['dynamicProperties', 'textFormatting'],
placeholder: '# {name}', placeholder: '# {name}',
@ -341,6 +405,7 @@ export const SCHEMA = {
popupShape: { popupShape: {
type: String, type: String,
impacts: [], // not needed impacts: [], // not needed
belongsTo: ['map', 'datalayer', 'feature'], // XXX ?
label: translate('Popup shape'), label: translate('Popup shape'),
inheritable: true, inheritable: true,
choices: [ choices: [
@ -353,6 +418,7 @@ export const SCHEMA = {
popupTemplate: { popupTemplate: {
type: String, type: String,
impacts: [], // not needed impacts: [], // not needed
belongsTo: ['map', 'datalayer', 'feature'], // XXX ?
label: translate('Popup content style'), label: translate('Popup content style'),
inheritable: true, inheritable: true,
choices: [ choices: [
@ -367,21 +433,25 @@ export const SCHEMA = {
remoteData: { remoteData: {
type: Object, type: Object,
impacts: ['remote-data'], impacts: ['remote-data'],
belongsTo: ['datalayer'],
}, },
scaleControl: { scaleControl: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
label: translate('Do you want to display the scale control?'), label: translate('Do you want to display the scale control?'),
default: true, default: true,
}, },
scrollWheelZoom: { scrollWheelZoom: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
label: translate('Allow scroll wheel zoom?'), label: translate('Allow scroll wheel zoom?'),
}, },
searchControl: { searchControl: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
nullable: true, nullable: true,
label: translate('Display the search control'), label: translate('Display the search control'),
default: true, default: true,
@ -389,28 +459,33 @@ export const SCHEMA = {
shortCredit: { shortCredit: {
type: String, type: String,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
label: translate('Short credits'), label: translate('Short credits'),
helpEntries: ['shortCredit', 'textFormatting'], helpEntries: ['shortCredit', 'textFormatting'],
}, },
showLabel: { showLabel: {
type: Boolean, type: Boolean,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'],
nullable: true, nullable: true,
label: translate('Display label'), label: translate('Display label'),
inheritable: true, inheritable: true,
default: false, default: false,
}, },
slideshow: { slideshow: {
belongsTo: ['map'],
type: Object, type: Object,
impacts: ['ui'], impacts: ['ui'],
}, },
slugKey: { slugKey: {
type: String, type: String,
impacts: [], impacts: [],
belongsTo: ['map', 'datalayer', 'feature'], // XXX ?
}, },
smoothFactor: { smoothFactor: {
type: Number, type: Number,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'],
min: 0, min: 0,
max: 10, max: 10,
step: 0.5, step: 0.5,
@ -422,16 +497,19 @@ export const SCHEMA = {
sortKey: { sortKey: {
type: String, type: String,
impacts: ['datalayer-index', 'data'], impacts: ['datalayer-index', 'data'],
belongsTo: ['map', 'datalayer'],
}, },
starControl: { starControl: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
nullable: true, nullable: true,
label: translate('Display the star map button'), label: translate('Display the star map button'),
}, },
stroke: { stroke: {
type: Boolean, type: Boolean,
impacts: ['data'], impacts: ['data'],
belongsTo: ['map', 'datalayer', 'feature'],
label: translate('stroke'), label: translate('stroke'),
helpEntries: 'stroke', helpEntries: 'stroke',
inheritable: true, inheritable: true,
@ -440,6 +518,7 @@ export const SCHEMA = {
syncEnabled: { syncEnabled: {
type: Boolean, type: Boolean,
impacts: ['sync', 'ui'], impacts: ['sync', 'ui'],
belongsTo: ['map'],
label: translate('Enable real-time collaboration'), label: translate('Enable real-time collaboration'),
helpEntries: 'sync', helpEntries: 'sync',
default: false, default: false,
@ -447,26 +526,31 @@ export const SCHEMA = {
tilelayer: { tilelayer: {
type: Object, type: Object,
impacts: ['background'], impacts: ['background'],
belongsTo: ['map'],
}, },
tilelayersControl: { tilelayersControl: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
nullable: true, nullable: true,
label: translate('Display the tile layers control'), label: translate('Display the tile layers control'),
}, },
toZoom: { toZoom: {
type: Number, type: Number,
impacts: [], // not needed impacts: [], // not needed
belongsTo: ['map'],
label: translate('To zoom'), label: translate('To zoom'),
helpText: translate('Optional.'), helpText: translate('Optional.'),
}, },
type: { type: {
type: 'String', type: 'String',
impacts: ['data'], impacts: ['data'],
belongsTo: [], // XXX ?
}, },
weight: { weight: {
type: Number, type: Number,
impacts: ['data'], impacts: ['data'],
belongsTo: ['feature'], // XXX ?,
min: 1, min: 1,
max: 20, max: 20,
step: 1, step: 1,
@ -477,10 +561,12 @@ export const SCHEMA = {
zoom: { zoom: {
type: Number, type: Number,
impacts: [], // default zoom, doesn't need to be updated impacts: [], // default zoom, doesn't need to be updated
belongsTo: ['map'],
}, },
zoomControl: { zoomControl: {
type: Boolean, type: Boolean,
impacts: ['ui'], impacts: ['ui'],
belongsTo: ['map'],
nullable: true, nullable: true,
label: translate('Display the zoom control'), label: translate('Display the zoom control'),
default: true, default: true,
@ -488,6 +574,7 @@ export const SCHEMA = {
zoomTo: { zoomTo: {
type: Number, type: Number,
impacts: [], // not need to update the view impacts: [], // not need to update the view
belongsTo: ['map'],
placeholder: translate('Inherit'), placeholder: translate('Inherit'),
helpEntries: 'zoomTo', helpEntries: 'zoomTo',
label: translate('Default zoom level'), label: translate('Default zoom level'),