From 5a81bbee2c8d0473bebaba3efd46487bd8f45e15 Mon Sep 17 00:00:00 2001 From: Nino Crljenec Date: Tue, 31 Mar 2020 13:36:02 +0200 Subject: [PATCH 01/90] Test ACL with parse user login --- package-lock.json | 152 ++++++++++++++++++ .../BrowserMenu/BrowserMenu.react.js | 9 +- src/components/BrowserMenu/BrowserMenu.scss | 28 +++- src/components/BrowserMenu/MenuItem.react.js | 5 +- src/dashboard/Data/Browser/Browser.react.js | 34 +++- .../Data/Browser/BrowserToolbar.react.js | 21 ++- .../Data/Browser/LoginDialog.react.js | 76 +++++++++ 7 files changed, 315 insertions(+), 10 deletions(-) create mode 100644 src/dashboard/Data/Browser/LoginDialog.react.js diff --git a/package-lock.json b/package-lock.json index 918d92b659..cd6447a40e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3690,6 +3690,17 @@ "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", "dev": true }, + "bcrypt": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-3.0.7.tgz", + "integrity": "sha512-K5UglF9VQvBMHl/1elNyyFvAfOY9Bj+rpKrCSR9sFwcW8FywAYJSRwTURNej5TaAK2TEJkcJ6r6lh1YPmspx5Q==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.14.0", + "node-pre-gyp": "0.13.0" + } + }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -5265,6 +5276,13 @@ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", "dev": true }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "dev": true, + "optional": true + }, "detect-newline": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", @@ -7777,6 +7795,16 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, "immutable": { "version": "4.0.0-rc.9", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0-rc.9.tgz", @@ -9893,6 +9921,43 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "optional": true + } + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.9.0" + } + }, "mississippi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", @@ -10237,6 +10302,64 @@ } } }, + "node-pre-gyp": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz", + "integrity": "sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ==", + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "optional": true + } + } + }, "node-releases": { "version": "1.1.73", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", @@ -10377,6 +10500,35 @@ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" }, + "npm-bundled": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "dev": true, + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", diff --git a/src/components/BrowserMenu/BrowserMenu.react.js b/src/components/BrowserMenu/BrowserMenu.react.js index 516baff850..c3d2a9802a 100644 --- a/src/components/BrowserMenu/BrowserMenu.react.js +++ b/src/components/BrowserMenu/BrowserMenu.react.js @@ -28,10 +28,14 @@ export default class BrowserMenu extends React.Component { let menu = null; if (this.state.open) { let position = Position.inDocument(this.node); + let titleStyle = [styles.title]; + if (this.props.active) { + titleStyle.push(styles.active); + } menu = ( this.setState({ open: false })}>
-
this.setState({ open: false })}> +
this.setState({ open: false })}> {this.props.title}
@@ -48,6 +52,9 @@ export default class BrowserMenu extends React.Component { ); } const classes = [styles.entry]; + if (this.props.active) { + classes.push(styles.active); + } if (this.props.disabled) { classes.push(styles.disabled); } diff --git a/src/components/BrowserMenu/BrowserMenu.scss b/src/components/BrowserMenu/BrowserMenu.scss index 189d8f1efa..b938f3579e 100644 --- a/src/components/BrowserMenu/BrowserMenu.scss +++ b/src/components/BrowserMenu/BrowserMenu.scss @@ -12,8 +12,8 @@ } .entry { - height: 22px; - padding: 8px 8px 0 8px; + height: 30px; + padding: 8px; svg { fill: #66637A; @@ -33,6 +33,15 @@ fill: #66637A; } } + + &.active { + background: $blue; + border-radius: 5px; + + svg { + fill: white; + } + } } .title { @@ -43,21 +52,28 @@ svg { fill: white; } + + &.active { + background: $blue; + border-radius: 5px; + } } .entry, .title { @include NotoSansFont; + position: relative; + bottom: -4px; font-size: 14px; color: #ffffff; cursor: pointer; svg { - vertical-align: middle; + vertical-align: top; margin-right: 4px; } span { - vertical-align: middle; + vertical-align: top; height: 14px; line-height: 14px; } @@ -92,6 +108,10 @@ background: none; } } + + &.active { + background: $blue; + } } .separator { diff --git a/src/components/BrowserMenu/MenuItem.react.js b/src/components/BrowserMenu/MenuItem.react.js index b0fb1fbd2b..35d3673106 100644 --- a/src/components/BrowserMenu/MenuItem.react.js +++ b/src/components/BrowserMenu/MenuItem.react.js @@ -8,11 +8,14 @@ import React from 'react'; import styles from 'components/BrowserMenu/BrowserMenu.scss'; -let MenuItem = ({ text, disabled, onClick }) => { +let MenuItem = ({ text, disabled, active, onClick }) => { let classes = [styles.item]; if (disabled) { classes.push(styles.disabled); } + if (active) { + classes.push(styles.active); + } return
{text}
; }; diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js index 71b9d26981..341316e7d1 100644 --- a/src/dashboard/Data/Browser/Browser.react.js +++ b/src/dashboard/Data/Browser/Browser.react.js @@ -81,7 +81,9 @@ class Browser extends DashboardView { uniqueField: null, keepAddingCols: false, markRequiredField: false, - requiredColumnFields: [] + requiredColumnFields: [], + + useMasterKey: true, }; this.prefetchData = this.prefetchData.bind(this); @@ -94,6 +96,9 @@ class Browser extends DashboardView { this.showDeleteRows = this.showDeleteRows.bind(this); this.showDropClass = this.showDropClass.bind(this); this.showExport = this.showExport.bind(this); + this.login = this.login.bind(this); + this.logout = this.logout.bind(this); + this.toggleMasterKeyUsage = this.toggleMasterKeyUsage.bind(this); this.showAttachRowsDialog = this.showAttachRowsDialog.bind(this); this.cancelAttachRows = this.cancelAttachRows.bind(this); this.confirmAttachRows = this.confirmAttachRows.bind(this); @@ -246,6 +251,24 @@ class Browser extends DashboardView { this.setState({ showExportDialog: true }); } + async login(username, password) { + if (!!Parse.User.current()) { + Parse.User.logOut(); + } + const currentUser = await Parse.User.logIn(username, password); + this.setState({ currentUser: currentUser, useMasterKey: false }, () => this.refresh()); + } + + async logout() { + await Parse.User.logOut(); + this.setState({ currentUser: null, useMasterKey: true }, () => this.refresh()); + } + + toggleMasterKeyUsage() { + const { useMasterKey } = this.state; + this.setState({ useMasterKey: !useMasterKey }, () => this.refresh()); + } + createClass(className) { this.props.schema.dispatch(ActionTypes.CREATE_CLASS, { className }).then(() => { this.state.counts[className] = 0; @@ -497,6 +520,7 @@ class Browser extends DashboardView { } async fetchParseData(source, filters) { + const { useMasterKey } = this.state; const query = queryFromFilters(source, filters); const sortDir = this.state.ordering[0] === '-' ? '-' : '+'; const field = this.state.ordering.substr(sortDir === '-' ? 1 : 0) @@ -518,7 +542,7 @@ class Browser extends DashboardView { query.limit(MAX_ROWS_FETCHED); this.excludeFields(query, source); - let promise = query.find({ useMasterKey: true }); + let promise = query.find({ useMasterKey: useMasterKey }); let isUnique = false; let uniqueField = null; filters.forEach(async (filter) => { @@ -1200,7 +1224,11 @@ class Browser extends DashboardView { onEditPermissions={this.onDialogToggle} onSaveNewRow={this.saveNewRow} onAbortAddRow={this.abortAddRow} - + currentUser={this.state.currentUser} + useMasterKey={this.state.useMasterKey} + login={this.login} + logout={this.logout} + toggleMasterKeyUsage={this.toggleMasterKeyUsage} markRequiredField={this.state.markRequiredField} requiredColumnFields={this.state.requiredColumnFields} columns={columns} diff --git a/src/dashboard/Data/Browser/BrowserToolbar.react.js b/src/dashboard/Data/Browser/BrowserToolbar.react.js index 017ac7573b..07664ce422 100644 --- a/src/dashboard/Data/Browser/BrowserToolbar.react.js +++ b/src/dashboard/Data/Browser/BrowserToolbar.react.js @@ -15,8 +15,9 @@ import Separator from 'components/BrowserMenu/Separator.react'; import styles from 'dashboard/Data/Browser/Browser.scss'; import Toolbar from 'components/Toolbar/Toolbar.react'; import SecurityDialog from 'dashboard/Data/Browser/SecurityDialog.react'; -import ColumnsConfiguration from 'components/ColumnsConfiguration/ColumnsConfiguration.react' +import ColumnsConfiguration from 'components/ColumnsConfiguration/ColumnsConfiguration.react'; import SecureFieldsDialog from 'dashboard/Data/Browser/SecureFieldsDialog.react'; +import LoginDialog from 'dashboard/Data/Browser/LoginDialog.react'; let BrowserToolbar = ({ className, @@ -57,6 +58,12 @@ let BrowserToolbar = ({ enableColumnManipulation, enableClassManipulation, + + currentUser, + useMasterKey, + login, + logout, + toggleMasterKeyUsage, }) => { let selectionLength = Object.keys(selection).length; let details = []; @@ -177,9 +184,11 @@ let BrowserToolbar = ({ let clpDialogRef = useRef(null); let protectedDialogRef = useRef(null); + let loginDialogRef = useRef(null); const showCLP = ()=> clpDialogRef.current.handleOpen(); const showProtected = () => protectedDialogRef.current.handleOpen(); + const showLogin = () => loginDialogRef.current.handleOpen(); return ( + {enableSecurityDialog ? ( + + + {currentUser ? :
+ } + onCancel={this.handleClose} + onConfirm={this.login} + confirmText="Login" + cancelText="Cancel" + > + this.setState({username: e.nativeEvent.target.value})} />} + /> + this.setState({password: e.nativeEvent.target.value})} type="password" />} + /> + + ) + ); + } +} + +LoginDialog.contextTypes = { + currentApp: PropTypes.instanceOf(ParseApp) +}; From ac4f5ab2d51a79873685852c6731ade46cc5a551 Mon Sep 17 00:00:00 2001 From: Nino Crljenec Date: Fri, 3 Apr 2020 19:32:35 +0200 Subject: [PATCH 02/90] Login dialog upgrades; Expand / Collapse TextArea fields on EditRowDialog; Fix for live reload data on EditRowDialog when data is updated on server --- src/components/BrowserMenu/BrowserMenu.scss | 14 +++++ src/components/BrowserMenu/MenuItem.react.js | 5 +- src/dashboard/Data/Browser/Browser.react.js | 9 ++- .../Data/Browser/BrowserToolbar.react.js | 5 +- .../Data/Browser/LoginDialog.react.js | 60 +++++++++++++++---- 5 files changed, 76 insertions(+), 17 deletions(-) diff --git a/src/components/BrowserMenu/BrowserMenu.scss b/src/components/BrowserMenu/BrowserMenu.scss index b938f3579e..81ff4f7aa3 100644 --- a/src/components/BrowserMenu/BrowserMenu.scss +++ b/src/components/BrowserMenu/BrowserMenu.scss @@ -111,6 +111,20 @@ &.active { background: $blue; + + &:hover { + background: white; + color: $blue; + } + } + + &.greenActive { + background: $green; + + &:hover { + background: white; + color: $blue; + } } } diff --git a/src/components/BrowserMenu/MenuItem.react.js b/src/components/BrowserMenu/MenuItem.react.js index 35d3673106..27b1df6f9f 100644 --- a/src/components/BrowserMenu/MenuItem.react.js +++ b/src/components/BrowserMenu/MenuItem.react.js @@ -8,7 +8,7 @@ import React from 'react'; import styles from 'components/BrowserMenu/BrowserMenu.scss'; -let MenuItem = ({ text, disabled, active, onClick }) => { +let MenuItem = ({ text, disabled, active, greenActive, onClick }) => { let classes = [styles.item]; if (disabled) { classes.push(styles.disabled); @@ -16,6 +16,9 @@ let MenuItem = ({ text, disabled, active, onClick }) => { if (active) { classes.push(styles.active); } + if (greenActive) { + classes.push(styles.greenActive); + } return
{text}
; }; diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js index 341316e7d1..49d59059f2 100644 --- a/src/dashboard/Data/Browser/Browser.react.js +++ b/src/dashboard/Data/Browser/Browser.react.js @@ -84,6 +84,7 @@ class Browser extends DashboardView { requiredColumnFields: [], useMasterKey: true, + currentUser: Parse.User.current() }; this.prefetchData = this.prefetchData.bind(this); @@ -255,8 +256,12 @@ class Browser extends DashboardView { if (!!Parse.User.current()) { Parse.User.logOut(); } - const currentUser = await Parse.User.logIn(username, password); - this.setState({ currentUser: currentUser, useMasterKey: false }, () => this.refresh()); + try { + const currentUser = await Parse.User.logIn(username, password); + this.setState({ currentUser: currentUser, useMasterKey: false }, () => this.refresh()); + } catch (error) { + throw error; + } } async logout() { diff --git a/src/dashboard/Data/Browser/BrowserToolbar.react.js b/src/dashboard/Data/Browser/BrowserToolbar.react.js index 07664ce422..c7fe18fed9 100644 --- a/src/dashboard/Data/Browser/BrowserToolbar.react.js +++ b/src/dashboard/Data/Browser/BrowserToolbar.react.js @@ -270,8 +270,9 @@ let BrowserToolbar = ({ - - {currentUser ? :
@@ -59,12 +78,29 @@ export default class LoginDialog extends React.Component { > this.setState({username: e.nativeEvent.target.value})} />} + input={ + + this.setState({ username: e.nativeEvent.target.value }) + } + onKeyDown={this.handleKeyDown} + autoFocus + /> + } /> this.setState({password: e.nativeEvent.target.value})} type="password" />} + input={ + + this.setState({ password: e.nativeEvent.target.value }) + } + type="password" + onKeyDown={this.handleKeyDown} + /> + } /> + ) ); From e694aa782e31ab60ac3aa9196d5180127a8c56c0 Mon Sep 17 00:00:00 2001 From: Nino Crljenec Date: Sat, 11 Apr 2020 11:20:59 +0200 Subject: [PATCH 03/90] fix: eslint fixes --- src/dashboard/Data/Browser/Browser.react.js | 11 ++++------ .../Data/Browser/BrowserToolbar.react.js | 2 +- .../Data/Browser/LoginDialog.react.js | 22 +++++++++---------- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js index 49d59059f2..6d179ba9be 100644 --- a/src/dashboard/Data/Browser/Browser.react.js +++ b/src/dashboard/Data/Browser/Browser.react.js @@ -253,15 +253,12 @@ class Browser extends DashboardView { } async login(username, password) { - if (!!Parse.User.current()) { + if (Parse.User.current()) { Parse.User.logOut(); } - try { - const currentUser = await Parse.User.logIn(username, password); - this.setState({ currentUser: currentUser, useMasterKey: false }, () => this.refresh()); - } catch (error) { - throw error; - } + + const currentUser = await Parse.User.logIn(username, password); + this.setState({ currentUser: currentUser, useMasterKey: false }, () => this.refresh()); } async logout() { diff --git a/src/dashboard/Data/Browser/BrowserToolbar.react.js b/src/dashboard/Data/Browser/BrowserToolbar.react.js index c7fe18fed9..2624d5fd82 100644 --- a/src/dashboard/Data/Browser/BrowserToolbar.react.js +++ b/src/dashboard/Data/Browser/BrowserToolbar.react.js @@ -272,7 +272,7 @@ let BrowserToolbar = ({ {currentUser ? Browsing with Master Key : Browse with Master Key} onClick={toggleMasterKeyUsage} active={!!currentUser} greenActive={useMasterKey} /> :