From 50d668723f81c40765a6d41a249c98d53271094b Mon Sep 17 00:00:00 2001 From: Loris Admin Date: Thu, 23 Jul 2020 15:29:53 -0400 Subject: [PATCH] updated conflict resolver fix function --- .../.unresolved_filterabledatatable.js.swp | Bin 0 -> 16384 bytes .../jsx/fix_conflict_form.js | 98 +++++++++--------- .../jsx/unresolved_filterabledatatable.js | 16 +-- .../php/conflict_resolver.class.inc | 6 +- .../php/endpoints/resolved.class.inc | 10 +- .../php/endpoints/unresolved.class.inc | 27 ++--- .../php/models/resolveddto.class.inc | 30 +++--- .../conflict_resolver/php/module.class.inc | 64 ++++++------ .../resolvedprovisioner.class.inc | 2 +- .../unresolvedprovisioner.class.inc | 2 +- .../test/conflict_resolverTest.php | 4 +- webpack.config.js | 5 +- 12 files changed, 136 insertions(+), 128 deletions(-) create mode 100644 modules/conflict_resolver/jsx/.unresolved_filterabledatatable.js.swp diff --git a/modules/conflict_resolver/jsx/.unresolved_filterabledatatable.js.swp b/modules/conflict_resolver/jsx/.unresolved_filterabledatatable.js.swp new file mode 100644 index 0000000000000000000000000000000000000000..e559d35188903a6969f43c6ee574d6139b18999c GIT binary patch literal 16384 zcmeI2Ux*|}9mgv%YI4cNm?%cc!|zsbX3pK2+q;0eH?!ulm&GM_xyxtq`-HgnLqbGJ8Y(a7 zhcRa!eDzXq(~G=NEd+AZ)U}$vH(S0n^3v9LJZ|YCt$q>=BdJ<`5_hA}&#tCYCDBNx zt!=f_8pif(aJ3sonM50r47?2g@JDl7&DwVSPjHD3&mE(O z9=v=&VVCR_a0)mDoB~b(r+`zyDc}@v3j9ARkPYq>UqHw1w4J+QKkwM{`40R2J@)g< zd-Cm9_u&+93OEIv0!{&^fK$LJ;1qBQI0c*nP64OD|DXb1AjBi^>l|+Y;P?Oh{r@+3 z(SHS82Ty~G;9+nF_|yGD{1LnfUIRY@KLFncp98Dlac~AS!27^kM}_z;coX~@JO{3W z&wxendz?A=4tN3hU;{M3L*Os>qAqv^JP*DKJ`a3w3cMfO4gPsVh`)kAfSceK;OF3{ z;0E|2*aiW31{?*q?h)c;@GWp1Y=Cvp2JZ#8?iS*g;D_KP@D&h&P4HQ;0WN}%fFt1V z?-t@!a06_Br@#~7lVBM<4F2{m=mFjUx4`$nOW8N zxs%m$Geoi1=hUZ%Qe|Nh7deF=WsY?uONVlv%&C$knplUbEhPgsrIyJ4(F|jST74O3 zWy97TB_rwY<4{>;)}^(=T+!{f;nXNpVRnwyKD1L;iYl{C={(Z*{sXUWJ17^|SJuwX zwq%nJJscyBB#iN?6Sxp5cEtWoM67smuwUzW`k|Yji3Z3nXPh`F4%Sh)aJdLdllt~u z7^KNI!tT&sTr}lp9Vs#n?aOUPe8nE-+E;j+N1SP!(~H91$%qqSD#HYoQJ|{9($#Y(7j ze$cRMLaRle_QEWTx2T(>T50Nnjj$qnJ*}v*)~$M`=E+v}s4tabpI{}G zF*L4oHGIoEH?62+T9DZ~k6nGDJ6q=C=wRme>UEvmpw4o+LN{R0TzgFLpp+KSYB?07 zM{J33aiM*Oo7A@+4~N^+h4AQO+ka@n_@7)~|+GS=0ok4vbFWY}s}8IP0a! zm|{7mCwTPh+8fiu(p6T!l2MpyV#wpV&f2AiO~*OOfllW?a4<57>kXrn9iFaaL5FEH zPZJ*jg}YdYdodPNg-}_*DbKAiu1!rH(-{=T3^PYLANQ2JeCb>hIT)IHZJz_1@SUQMv)p-EKK;WDj!X7Crvp8z@& zyYQ5?I2W4ev#V=CXMz#tE%@Q%W1iAP6Rgr=P|GZZ_^Z$fX>8fEYsSO;4C!`5i?ZxlW5qF z%@Tk$ulzp6AO%Wz__RX_>|-|R@r4^X5f!c$>Ze|rZA}bFt0XZmRQ;fM>2-2 z+$?)ygX6J*mwJ7gcxmcgn{s=$8CoEnMoHHi>zVd*-}UpM(y@*3n=!*9R<*(X;Ze;n zNtE?T4Wu7-L!X<~J{5NGP>3aYYC5oBK5XR!3hIubLDNI+T&0`mlOXI~qfOcKMqx5c zxmUJzh-K@ri;Baa?*!WaXZT1ovipN1hTkyAGXfuZ@Y$6@uM&Hf&itmgMEnFgZP>Y> zOI4;Zj1~6JhQaw{7-zfJcvGViBl#`58aK_&Fb?!BX5V&-D!gKG*LIa>p~{(2I&PjJ zbZ)-dPwZ=h=`7!8U|Qdh5Zl86?oW7t8Yu0Ao*wDY&#*3=RFu?rQo39mLSHS;ptD;> zaJ+}$UZ-d!7oJ-PF$lQv?wRSN*Rxu))eU#9qCs=uot3GbF016n+{-3RwS5{dtC?pS z+kp8}W?qsW9ujF%xHz>1Q_es+eu()J-p~16p5OoRdativ;g8qBYv3o~MerPu;5;Dk z0q_904;%sa0Jif6+j5svz$xGqa0)mDoB~b(r+`zyDc}@v3OEJ+I||4h{U#pBt~ZRb z+rP`>_X6H4G5aOOc3@>Ia7$*ZdT#@}Rx8+m>6jh;>fT1a* { + this.setState({error: false}); + }, 3000); + } + if (this.state.success) { + setTimeout(() => { + this.setState({success: false}); + }, 3000); + } } /** @@ -41,22 +60,12 @@ class FixConflictForm extends Component { * beside the dropdown. On error, a red cross will be displayed as well as a * sweetalert (swal) with the error message. * - * @param {Event} e - The onChange event. + * @param {string} name + * @param {string} value */ - fix(e) { - const conflictid = e.target.name; - const correctanswer = e.target.value; - - const feedbackicon = e.target.parentElement.getElementsByTagName('span')[0]; + resolveConflict(name, value) { // Hide any previously displayed icon. - feedbackicon.style.display = 'none'; - - try { - // Remove the empty option from the options to prevent sending an empty value. - e.target.querySelector('option[name="0"]').remove(); - } catch (error) { - // TypeError when already removed. Do nothing. - } + this.setState({success: false, error: false, emptyOption: false}); fetch(loris.BaseURL.concat('/conflict_resolver/unresolved'), { method: 'POST', @@ -64,58 +73,49 @@ class FixConflictForm extends Component { headers: { 'Content-Type': 'application/json', }, - body: JSON.stringify({conflictid: conflictid, correctanswer: correctanswer}), + body: JSON.stringify({conflictid: name, correctanswer: value}), }) .then((resp) => { return resp.ok ? {} : resp.json(); }) .then((json) => { - if (json.error) { - throw json.error; - } - // Set feedback icon to green checkmark - setTimeout(() => { - feedbackicon.className = 'glyphicon glyphicon-ok-circle'; - feedbackicon.style.color = 'green'; - feedbackicon.style.display = 'inline'; - }, 200); + if (json.error) { + throw json.error; + } + this.setState({success: true}); }) .catch((error) => { swal('Error!', error, 'error'); - // Set feedback icon to red cross - setTimeout(() => { - feedbackicon.className = 'glyphicon glyphicon-remove-sign'; - feedbackicon.style.color = 'red'; - feedbackicon.style.display = 'inline'; - }, 200); + this.setState({error: true}); }); - } + } render() { - const options = [ - , - , - , - ]; + const {success, error, emptyOption} = this.state; + const iconStyle = { + opacity: success || error ? 1 : 0, + color: success ? 'green' : (error ? 'red' : 'white'), + transition: 'opacity 2s, color 2s', + }; + const iconClass = 'glyphicon glyphicon-' + (success ? 'ok' : 'remove') + + '-circle'; return ( -
- - - + + ); } } FixConflictForm.propTypes = { - conflictid: PropTypes.string.isRequired, - values: PropTypes.arrayOf(PropTypes.shape({ - name: PropTypes.string.isRequired, - value: PropTypes.string.isRequired, - })).isRequired, + conflictId: PropTypes.string.isRequired, + options: PropTypes.object.isRequired, }; export default FixConflictForm; diff --git a/modules/conflict_resolver/jsx/unresolved_filterabledatatable.js b/modules/conflict_resolver/jsx/unresolved_filterabledatatable.js index 9e58d56904c..86938687f99 100644 --- a/modules/conflict_resolver/jsx/unresolved_filterabledatatable.js +++ b/modules/conflict_resolver/jsx/unresolved_filterabledatatable.js @@ -34,12 +34,15 @@ class UnresolvedFilterableDataTable extends Component { formatColumn(column, cell, rowData, rowHeaders) { switch (column) { case 'Correct Answer': - const values = [ - {name: '1', value: rowData['Value 1']}, - {name: '2', value: rowData['Value 2']}, - ]; + const options = { + 1: rowData['Value 1'], + 2: rowData['Value 2'], + }; return ( - + ); } return ( @@ -52,7 +55,8 @@ class UnresolvedFilterableDataTable extends Component { * @return {object} */ fetchData() { - return fetch(loris.BaseURL.concat('/conflict_resolver/unresolved'), {credentials: 'same-origin'}) + const url = loris.BaseURL.concat('/conflict_resolver/unresolved'); + return fetch(url, {credentials: 'same-origin'}) .then((resp) => resp.json()) .then((json) => { if (json.error) { diff --git a/modules/conflict_resolver/php/conflict_resolver.class.inc b/modules/conflict_resolver/php/conflict_resolver.class.inc index 2e39cd038d5..b3583cdd77c 100644 --- a/modules/conflict_resolver/php/conflict_resolver.class.inc +++ b/modules/conflict_resolver/php/conflict_resolver.class.inc @@ -53,9 +53,9 @@ class Conflict_Resolver extends \NDB_Page $deps = parent::getJSDependencies(); return array_merge( $deps, - array( - $baseURL . '/conflict_resolver/js/conflict_resolver.js', - ) + [ + $baseURL . '/conflict_resolver/js/conflict_resolver.js', + ] ); } } diff --git a/modules/conflict_resolver/php/endpoints/resolved.class.inc b/modules/conflict_resolver/php/endpoints/resolved.class.inc index ecd11434709..769e6cb4d8c 100644 --- a/modules/conflict_resolver/php/endpoints/resolved.class.inc +++ b/modules/conflict_resolver/php/endpoints/resolved.class.inc @@ -85,12 +85,12 @@ class Resolved extends Endpoint implements ETagCalculator $visitlabels = array_values(\Utility::getVisitList()); $projects = array_values(\Utility::getProjectList()); - return array( + return [ 'site' => array_combine($sites, $sites), 'instrument' => \Utility::getAllInstruments(), 'visitLabel' => array_combine($visitlabels, $visitlabels), 'project' => array_combine($projects, $projects), - ); + ]; } /** @@ -133,7 +133,7 @@ class Resolved extends Endpoint implements ETagCalculator $provisioner = (new ResolvedProvisioner()) ->filter( new HasAnyPermissionOrUserSiteMatch( - array('access_all_profiles') + ['access_all_profiles'] ) ) ->filter(new UserProjectMatch()); @@ -143,10 +143,10 @@ class Resolved extends Endpoint implements ETagCalculator ->withDataFrom($provisioner) ->toArray($user); - $body = array( + $body = [ 'data' => $conflicts, 'fieldOptions' => $this->_getFieldOptions(), - ); + ]; $this->_cache = new \LORIS\Http\Response\JsonResponse($body); diff --git a/modules/conflict_resolver/php/endpoints/unresolved.class.inc b/modules/conflict_resolver/php/endpoints/unresolved.class.inc index 786d084aeb1..205b6b7f36e 100644 --- a/modules/conflict_resolver/php/endpoints/unresolved.class.inc +++ b/modules/conflict_resolver/php/endpoints/unresolved.class.inc @@ -77,10 +77,10 @@ class Unresolved extends Endpoint implements ETagCalculator */ protected function allowedMethods() : array { - return array( + return [ 'GET', 'POST', - ); + ]; } /** @@ -94,12 +94,12 @@ class Unresolved extends Endpoint implements ETagCalculator $visitlabels = array_values(\Utility::getVisitList()); $projects = array_values(\Utility::getProjectList()); - return array( + return [ 'site' => array_combine($sites, $sites), 'instrument' => \Utility::getAllInstruments(), 'visitLabel' => array_combine($visitlabels, $visitlabels), 'project' => array_combine($projects, $projects), - ); + ]; } /** @@ -145,7 +145,7 @@ class Unresolved extends Endpoint implements ETagCalculator $provisioner = (new UnresolvedProvisioner()) ->filter( new HasAnyPermissionOrUserSiteMatch( - array('access_all_profiles') + ['access_all_profiles'] ) ) ->filter(new UserProjectMatch()); @@ -155,10 +155,10 @@ class Unresolved extends Endpoint implements ETagCalculator ->withDataFrom($provisioner) ->toArray($user); - $body = array( + $body = [ 'data' => $conflicts, 'fieldOptions' => $this->_getFieldOptions(), - ); + ]; $this->_cache = new \LORIS\Http\Response\JsonResponse($body); @@ -219,10 +219,10 @@ class Unresolved extends Endpoint implements ETagCalculator WHERE ConflictID = :v_conflictid ', - array( + [ 'v_conflictid' => $conflictid, 'v_value' => $correctanswer, - ) + ] ); if (empty($conflict)) { @@ -239,8 +239,9 @@ class Unresolved extends Endpoint implements ETagCalculator false ); - $instrument->_saveValues(array($conflict['FieldName'] => $correctanswer)); + $instrument->_saveValues([$conflict['FieldName'] => $correctanswer]); + // TODO: UNCOMMENT THE FOLLOWING LINES BEFORE SUBMITTING PR. // Using an output buffer because the score function prints to STDOUT ob_start(); $instrument->score(); @@ -313,11 +314,11 @@ class Unresolved extends Endpoint implements ETagCalculator ); $success = $stmt->execute( - array( + [ 'v_username' => $user->getUsername(), 'v_newvalue' => $correctanswer, 'v_conflictid' => $conflictid, - ) + ] ); if (!$success) { @@ -325,7 +326,7 @@ class Unresolved extends Endpoint implements ETagCalculator } // Delete from conflicts_unresolved - $db->delete('conflicts_unresolved', array('ConflictID' => $conflictid)); + $db->delete('conflicts_unresolved', ['ConflictID' => $conflictid]); return new \LORIS\Http\Response(); } diff --git a/modules/conflict_resolver/php/models/resolveddto.class.inc b/modules/conflict_resolver/php/models/resolveddto.class.inc index 2b4284af021..29af31e4adf 100644 --- a/modules/conflict_resolver/php/models/resolveddto.class.inc +++ b/modules/conflict_resolver/php/models/resolveddto.class.inc @@ -36,21 +36,21 @@ class ResolvedDTO implements \LORIS\Data\DataInstance public function jsonSerialize(): array { return [ - 'ResolvedID' => $this->resolvedid, - 'Project' => $this->project, - 'Site' => $this->site, - 'CandID' => $this->candid, - 'PSCID' => $this->pscid, - 'Visit Label' => $this->visitlabel, - 'Instrument' => $this->instrument, - 'Question' => $this->question, - 'Value 1' => $this->value1, - 'Value 2' => $this->value2, - 'Correct Answer' => $this->correctanswer, - 'User 1' => $this->user1, - 'User 2' => $this->user2, - 'Resolver' => $this->resolver, - 'ResolutionTimestamp' => $this->resolutiontimestamp, + 'ResolvedID' => $this->resolvedid, + 'Project' => $this->project, + 'Site' => $this->site, + 'CandID' => $this->candid, + 'PSCID' => $this->pscid, + 'Visit Label' => $this->visitlabel, + 'Instrument' => $this->instrument, + 'Question' => $this->question, + 'Value 1' => $this->value1, + 'Value 2' => $this->value2, + 'Correct Answer' => $this->correctanswer, + 'User 1' => $this->user1, + 'User 2' => $this->user2, + 'Resolver' => $this->resolver, + 'ResolutionTimestamp' => $this->resolutiontimestamp, ]; } diff --git a/modules/conflict_resolver/php/module.class.inc b/modules/conflict_resolver/php/module.class.inc index 1357da51f4e..a4b6b0f2f41 100644 --- a/modules/conflict_resolver/php/module.class.inc +++ b/modules/conflict_resolver/php/module.class.inc @@ -131,18 +131,18 @@ class Module extends \Module 'conflict_resolver' ) ]; - case 'candidate': - $factory = \NDB_Factory::singleton(); - $baseURL = $factory->settings()->getBaseURL(); - $DB = $factory->database(); + case 'candidate': + $factory = \NDB_Factory::singleton(); + $baseURL = $factory->settings()->getBaseURL(); + $DB = $factory->database(); - $candidate = $options['candidate']; - if ($candidate === null) { - return []; - } + $candidate = $options['candidate']; + if ($candidate === null) { + return []; + } - $candID = $candidate->getCandID(); - $results = $DB->pselect( + $candID = $candidate->getCandID(); + $results = $DB->pselect( "SELECT f1.Test_name, s1.Visit_label, COUNT(*) as Conflicts FROM conflicts_unresolved cu LEFT JOIN flag f1 ON (f1.CommentID=cu.CommentId1) @@ -151,29 +151,29 @@ class Module extends \Module LEFT JOIN session s2 ON (f2.SessionID=s2.ID) WHERE (s1.CandID=:cand1 OR s2.CandID=:cand2) GROUP BY f1.Test_name, s1.Visit_label - ORDER BY s1.Visit_label, f1.Test_name", - ['cand1' => $candID, 'cand2' => $candID], - ); - // Do not show the conflicts card if there are no conflicts - if (empty($results)) { - return []; - } + ORDER BY s1.Visit_label, f1.Test_name", + ['cand1' => $candID, 'cand2' => $candID], + ); + // Do not show the conflicts card if there are no conflicts + if (empty($results)) { + return []; + } - $width = 1; - if (count($results) > 10) { - $width = 2; - } - return [ - new \LORIS\candidate_profile\CandidateWidget( - "Unresolved Conflicts", - $baseURL . "/conflict_resolver/js/CandidateConflictsWidget.js", - "lorisjs.conflict_resolver.CandidateConflictsWidget.default", - [ - 'Conflicts' => $results, - ], - $width, - 1, - ) + $width = 1; + if (count($results) > 10) { + $width = 2; + } + return [ + new \LORIS\candidate_profile\CandidateWidget( + "Unresolved Conflicts", + $baseURL . "/conflict_resolver/js/CandidateConflictsWidget.js", + "lorisjs.conflict_resolver.CandidateConflictsWidget.default", + [ + 'Conflicts' => $results, + ], + $width, + 1, + ) ]; } diff --git a/modules/conflict_resolver/php/provisioners/resolvedprovisioner.class.inc b/modules/conflict_resolver/php/provisioners/resolvedprovisioner.class.inc index 24a50a731e0..b0c5f41be2d 100644 --- a/modules/conflict_resolver/php/provisioners/resolvedprovisioner.class.inc +++ b/modules/conflict_resolver/php/provisioners/resolvedprovisioner.class.inc @@ -58,7 +58,7 @@ class ResolvedProvisioner extends \LORIS\Data\Provisioners\DBObjectProvisioner LEFT JOIN psc ON (session.CenterID = psc.CenterID) WHERE session.Active="Y" AND candidate.Active ="Y" ', - array(), + [], '\LORIS\conflict_resolver\Models\ResolvedDTO' ); } diff --git a/modules/conflict_resolver/php/provisioners/unresolvedprovisioner.class.inc b/modules/conflict_resolver/php/provisioners/unresolvedprovisioner.class.inc index 24adfaef385..2da636927e5 100644 --- a/modules/conflict_resolver/php/provisioners/unresolvedprovisioner.class.inc +++ b/modules/conflict_resolver/php/provisioners/unresolvedprovisioner.class.inc @@ -53,7 +53,7 @@ class UnresolvedProvisioner extends \LORIS\Data\Provisioners\DBObjectProvisioner LEFT JOIN psc ON (session.CenterID = psc.CenterID) WHERE session.Active="Y" AND candidate.Active ="Y" ', - array(), + [], '\LORIS\conflict_resolver\Models\UnresolvedDTO' ); } diff --git a/modules/conflict_resolver/test/conflict_resolverTest.php b/modules/conflict_resolver/test/conflict_resolverTest.php index 004918a43a9..51af08c835c 100644 --- a/modules/conflict_resolver/test/conflict_resolverTest.php +++ b/modules/conflict_resolver/test/conflict_resolverTest.php @@ -89,7 +89,7 @@ function tearDown() */ function testConflictResolverPermission() { - $this->setupPermissions(array("conflict_resolver")); + $this->setupPermissions(["conflict_resolver"]); $this->safeGet($this->url . "/conflict_resolver"); $this->webDriver->wait()->until( \WebDriverExpectedCondition::presenceOfElementLocated( @@ -106,7 +106,7 @@ function testConflictResolverPermission() */ function testConflictResolverWithoutPermission() { - $this->setupPermissions(array()); + $this->setupPermissions([]); $this->safeGet($this->url . "/conflict_resolver"); $bodyText = $this->webDriver->findElement( \WebDriverBy::id('lorisworkspace') diff --git a/webpack.config.js b/webpack.config.js index 3ccd8c309cd..0757af9150c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -190,7 +190,10 @@ const config = [ 'ConsentWidget', ]), lorisModule('configuration', ['SubprojectRelations']), - lorisModule('conflict_resolver', ['conflict_resolver']), + lorisModule('conflict_resolver', [ + 'conflict_resolver', + 'CandidateConflictsWidget', + ]), lorisModule('battery_manager', ['batteryManagerIndex']), lorisModule('bvl_feedback', ['react.behavioural_feedback_panel']), lorisModule('behavioural_qc', ['behavioural_qc_module']),