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

feat: Add optional restriction of script execution to certain object fields and values #2488

Merged
merged 12 commits into from
Jun 27, 2024
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,31 @@ You can specify scripts to execute Cloud Functions with the `scripts` option:
]
```

You can also specify custom fields with the `scrips` option:

```json
"apps": [
{
"scripts": [
{
"title": "Delete account",
"classes": [
{
"name": "_User",
"fields": [
{ "name": "createdAt", "validator": "value => value > new Date(\"2025\")" }
]
}
],
mtrezza marked this conversation as resolved.
Show resolved Hide resolved
"cloudCodeFunction": "deleteAccount"
}
]
}
]

```


Next, define the Cloud Function in Parse Server that will be called. The object that has been selected in the data browser will be made available as a request parameter:

```js
Expand Down
37 changes: 31 additions & 6 deletions src/components/BrowserCell/BrowserCell.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,23 +334,48 @@ export default class BrowserCell extends Component {
});
}

const { className, objectId } = this.props;
const validScripts = (this.props.scripts || []).filter(script =>
script.classes?.includes(this.props.className)
);
const { className, objectId, field, scripts = [], rowValue } = this.props;
let validator = null;
const validScripts = (scripts || []).filter(script => {
if (script.classes?.includes(className)) {
return true;
}
for (const script of script?.classes || []) {
if (script?.name !== className) {
continue;
}
const fields = script?.fields || [];
if (script?.fields.includes(field) || script?.fields.includes('*')) {
return true;
}
for (const currentField of fields) {
if (Object.prototype.toString.call(currentField) === '[object Object]') {
if (currentField.name === field) {
if (typeof currentField.validator === 'string') {
validator = eval(currentField.validator);
} else {
validator = currentField.validator;
}
return true;
}
}
}
}
});
if (validScripts.length) {
onEditSelectedRow &&
contextMenuOptions.push({
text: 'Scripts',
items: validScripts.map(script => {
return {
text: script.title,
disabled: validator?.(rowValue, field) === false,
callback: () => {
this.selectedScript = { ...script, className, objectId };
if (script.showConfirmationDialog) {
this.toggleConfirmationDialog();
} else {
this.executeSript(script);
this.executeScript(script);
}
},
};
Expand All @@ -361,7 +386,7 @@ export default class BrowserCell extends Component {
return contextMenuOptions;
}

async executeSript(script) {
async executeScript(script) {
try {
const object = Parse.Object.extend(this.props.className).createWithoutData(
this.props.objectId
Expand Down
2 changes: 2 additions & 0 deletions src/components/BrowserRow/BrowserRow.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default class BrowserRow extends Component {
order,
readOnlyFields,
row,
rowValue,
rowWidth,
selection,
selectRow,
Expand Down Expand Up @@ -114,6 +115,7 @@ export default class BrowserRow extends Component {
className={className}
field={name}
row={row}
rowValue={rowValue}
col={j}
type={type}
readonly={isUnique || readOnlyFields.indexOf(name) > -1}
Expand Down
4 changes: 4 additions & 0 deletions src/components/ContextMenu/ContextMenu.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,11 @@ const MenuSection = ({ level, items, path, setPath, hide }) => {
<li
key={`menu-section-${level}-${index}`}
className={styles.option}
style={item.disabled ? { opacity: 0.5, cursor: 'not-allowed' } : {}}
onClick={() => {
if (item.disabled === true) {
return;
}
item.callback && item.callback();
hide();
}}
Expand Down
2 changes: 2 additions & 0 deletions src/dashboard/Data/Browser/BrowserTable.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ export default class BrowserTable extends React.Component {
order={this.props.order}
readOnlyFields={READ_ONLY}
row={index}
rowValue={this.props.data[index]}
rowWidth={rowWidth}
selection={this.props.selection}
selectRow={this.props.selectRow}
Expand Down Expand Up @@ -300,6 +301,7 @@ export default class BrowserTable extends React.Component {
order={this.props.order}
readOnlyFields={READ_ONLY}
row={i}
rowValue={this.props.data[i]}
rowWidth={rowWidth}
selection={this.props.selection}
selectRow={this.props.selectRow}
Expand Down