diff --git a/CHANGELOG.md b/CHANGELOG.md index d04d4473f9b..03a998323c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -252,6 +252,7 @@ or not matching password confirmation. (PR #6615, #6705, #6611) #### DQT - Improve the visibility of some dropdown elements (PR #6602) +- ADD delete the saved query feature (PR #8078) ### Clean Up - New tool for detection of multiple first visits for a candidate (prevents a database diff --git a/modules/dqt/ajax/DeleteDoc.php b/modules/dqt/ajax/DeleteDoc.php new file mode 100644 index 00000000000..11eab76d142 --- /dev/null +++ b/modules/dqt/ajax/DeleteDoc.php @@ -0,0 +1,37 @@ + + * @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3 + * @link https://www.github.com/aces/Loris/ + */ +header("Content-Type: application/json"); +$config = \NDB_Config::singleton(); +$couchConfig = $config->getSetting('CouchDB'); +$cdb = \NDB_Factory::singleton()->couchDB( + $couchConfig['dbName'], + $couchConfig['hostname'], + intval($couchConfig['port']), + $couchConfig['admin'], + $couchConfig['adminpass'] +); +$is_author = false; +$docID = urlencode($_REQUEST['DocID']); +$user = User::singleton(); +$tmp_author = explode("_", $docID); +$doc_author = str_replace("global:", '', $tmp_author[0]); +if ($doc_author == $user->getUsername()) { + $is_author = true; +} + +if ($user->hasPermission('superuser') || $is_author) { + $results = $cdb->deleteDoc($docID); + print json_encode($results); +} else { + header("HTTP/1.1 403 Forbidden"); +} diff --git a/modules/dqt/ajax/saveQuery.php b/modules/dqt/ajax/saveQuery.php index a4a0bcbb3ff..2ad5b6066e3 100644 --- a/modules/dqt/ajax/saveQuery.php +++ b/modules/dqt/ajax/saveQuery.php @@ -69,7 +69,7 @@ ': ' . $_REQUEST['QueryName']; } -$fields = json_decode($_REQUEST['Fields']); +$fields = json_decode(strval($_REQUEST['Fields'])); $cond = $_REQUEST['Filters']; $baseDocument['Conditions'] = $cond; $baseDocument['Fields'] = $fields; diff --git a/modules/dqt/css/dataquery.css b/modules/dqt/css/dataquery.css index 5e0038bba04..3d187290d2b 100644 --- a/modules/dqt/css/dataquery.css +++ b/modules/dqt/css/dataquery.css @@ -556,7 +556,7 @@ tr.statsReport:nth-child(even) { } .tableFieldsCell { overflow-x: scroll; - max-width: 400px; + max-width: 280px; min-height: 100px; } .tableFiltersCell { diff --git a/modules/dqt/jsx/react.app.js b/modules/dqt/jsx/react.app.js index c209f7d4a90..6678aeb1f9d 100644 --- a/modules/dqt/jsx/react.app.js +++ b/modules/dqt/jsx/react.app.js @@ -40,6 +40,7 @@ class DataQueryApp extends Component { queryIDs: { user: [], shared: [], + author: [], }, savedQueries: {}, queriesLoaded: false, @@ -1325,6 +1326,7 @@ class DataQueryApp extends Component { { const [content, setContent] = useState(null); @@ -70,7 +71,39 @@ const ManageSavedQueryFilters = (props) => { const ManageSavedQueryRow = (props) => { const [fieldsVisible, setFields] = useState(null); const [filtersVisible, setFilters] = useState(null); - + /** + * @deleteclick + */ +function publicquerydelete() { + const id = props.Query['_id']; + swal.fire({ + title: 'Are you sure?', + text: 'You won\'t be able to revert this!', + type: 'warning', + showCancelButton: true, + confirmButtonColor: '#3085d6', + cancelButtonColor: '#d33', + confirmButtonText: 'Yes, delete it!', + }).then((result) => { + if (result.value) { + let deleteurl = loris.BaseURL + + '/AjaxHelper.php?Module=dqt&script=DeleteDoc.php&DocID=' + + encodeURIComponent(id); + fetch(deleteurl, { + cache: 'no-cache', + credentials: 'same-origin', + }).then((resp) => { + if (resp.status == 200) { + swal.fire('delete Successful!', '', 'success'); + } else { + swal.fire('delete Not Successful!', '', 'error'); + } + }).then(()=>{ + location.reload(); + }); + } + }); + }; useEffect(() => { let fields = []; let filters = []; @@ -157,7 +190,21 @@ const ManageSavedQueryRow = (props) => { setFilters(filters); setFields(fields); }, []); - + let docName = props.Query.Meta['name']; + let docAuthor = docName.substring(0, docName.lastIndexOf(':')); + let btn = ''; + if (props.author == docAuthor) { + btn = ( + + ); + } return ( @@ -175,6 +222,11 @@ const ManageSavedQueryRow = (props) => { {filtersVisible} + +
+ {btn} +
+ ); }; @@ -199,7 +251,6 @@ const SavedQueriesList = (props) => { props.queryDetails[queryName].Conditions ); }; - if (props.queriesLoaded === false) { return null; } @@ -222,6 +273,7 @@ const SavedQueriesList = (props) => { ); } @@ -247,6 +299,7 @@ const SavedQueriesList = (props) => { Query Name Fields Filters + Delete diff --git a/modules/dqt/jsx/react.tabs.js b/modules/dqt/jsx/react.tabs.js index 6c60fe07c5d..cb95e3f0268 100644 --- a/modules/dqt/jsx/react.tabs.js +++ b/modules/dqt/jsx/react.tabs.js @@ -11,6 +11,8 @@ import React, {Component, useState} from 'react'; import PropTypes from 'prop-types'; import StaticDataTable from '../../../jsx/StaticDataTable'; +import swal from 'sweetalert2'; + const {jStat} = require('jstat'); /** @@ -1116,6 +1118,39 @@ class ManageSavedQueryRow extends Component { super(props); this.state = {}; } + /** + * @deleteclick + */ + deleteclick() { + let id = this.props.Query['_id']; + swal.fire({ + title: 'Are you sure?', + text: 'You won\'t be able to revert this!', + type: 'warning', + showCancelButton: true, + confirmButtonColor: '#3085d6', + cancelButtonColor: '#d33', + confirmButtonText: 'Yes, delete it!', + }).then((result) => { + if (result.value) { + let deleteurl = loris.BaseURL + + '/AjaxHelper.php?Module=dqt&script=DeleteDoc.php&DocID=' + + encodeURIComponent(id); + fetch(deleteurl, { + cache: 'no-cache', + credentials: 'same-origin', + }).then((resp) => { + if (resp.status == 200) { + swal.fire('delete Successful!', '', 'success'); + } else { + swal.fire('delete Not Successful!', '', 'error'); + } + }).then(()=>{ + location.reload(); + }); + } + }); + } /** * Renders the React component. @@ -1224,6 +1259,17 @@ class ManageSavedQueryRow extends Component { {filters} + +
+ +
+ ); } @@ -1296,6 +1342,7 @@ let ManageSavedQueriesTabPane = (props) => { Query Name Fields Filters + Delete diff --git a/modules/dqt/php/dqt_setup.class.inc b/modules/dqt/php/dqt_setup.class.inc index 24ea6fe998e..88e3e2d55a1 100644 --- a/modules/dqt/php/dqt_setup.class.inc +++ b/modules/dqt/php/dqt_setup.class.inc @@ -164,12 +164,12 @@ class Dqt_Setup extends \NDB_Form implements RequestHandlerInterface return $row['id']; }; - $usersavedNames = array_map($IDMapCallback, $usersaved); - $globalsavedNames = array_map($IDMapCallback, $globalsaved); - + $usersavedNames = array_map($IDMapCallback, $usersaved); + $globalsavedNames = array_map($IDMapCallback, $globalsaved); $data['savedqueries'] = [ 'user' => $usersavedNames, 'shared' => $globalsavedNames, + 'author' => $user->getUsername(), ]; $data['visits'] = \Utility::getVisitList(); // Note: StringStream since BinaryStream isn't in 23.0-release. diff --git a/tools/dqt_delete_saved_query.php b/tools/dqt_delete_saved_query.php new file mode 100644 index 00000000000..95d27ae9c9c --- /dev/null +++ b/tools/dqt_delete_saved_query.php @@ -0,0 +1,43 @@ + + * @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3 + * @link https://www.github.com/aces/Loris/ + */ +require_once __DIR__ . '/../vendor/autoload.php'; +header("Content-Type: application/json"); +$config = \NDB_Config::singleton(); +$couchConfig = $config->getSetting('CouchDB'); +$cdb = \NDB_Factory::singleton()->couchDB( + $couchConfig['dbName'], + $couchConfig['hostname'], + intval($couchConfig['port']), + $couchConfig['admin'], + $couchConfig['adminpass'] +); +echo "Deleting a saved query in DQT.\n"; + + $user = readline("Please input the author of the saved query:"); + $name = readline("Please input the name of the saved query:"); + $global = readline("If the saved query is global then input 'y':"); +if ($global) { + $docID = urlencode("global:".$user."_".$name); +} else { + $docID = urlencode($user."_".$name); +} +$results = $cdb->deleteDoc( + $docID +); + + +if (json_encode($results) == "true") { + echo $name." has been deleted in DQT.\n"; +} else { + echo "There is no query named ".$name." in DQT.\n"; +};