diff --git a/ATL/CHANGEDB.php b/ATL/CHANGEDB.php index 243c190..59eee66 100644 --- a/ATL/CHANGEDB.php +++ b/ATL/CHANGEDB.php @@ -185,4 +185,9 @@ //v1.5.11 ++$count; $sql[$count][0] = '1.5.11'; -$sql[$count][1] = ''; \ No newline at end of file +$sql[$count][1] = ''; + +//v1.5.12 +++$count; +$sql[$count][0] = '1.5.12'; +$sql[$count][1] = ''; diff --git a/ATL/CHANGELOG.txt b/ATL/CHANGELOG.txt index 4db1c0c..86b8420 100644 --- a/ATL/CHANGELOG.txt +++ b/ATL/CHANGELOG.txt @@ -1,10 +1,13 @@ CHANGELOG ========= +v1.5.12 +------- +Enabled staff to view visualisation and data for unpublished ATLs + v1.5.11 ------- Refactoring null coalesce -======= v1.5.10 ------- Fixed visualization showing data that has not gone live diff --git a/ATL/atl_view.php b/ATL/atl_view.php index 721dee3..f8fccb3 100644 --- a/ATL/atl_view.php +++ b/ATL/atl_view.php @@ -85,6 +85,12 @@ echo __('The selected record does not exist, or you do not have access to it.'); echo ''; } else { + + $roleCategory = $session->get('gibbonRoleIDCurrentCategory'); + if ($roleCategory == 'Staff') { + echo Format::alert(__m('As a staff member, your view of this ATL diagram accounts for all current ATL records, including those before their complete date. Parents and students will only see the ATL diagram based on completed data.'), 'message'); + } + echo '
'; echo visualiseATL($container, $gibbonPersonID); @@ -105,9 +111,7 @@ } if ($result->rowCount() < 1) { - echo "
"; - echo __('Access denied.'); - echo '
'; + $page->addMessage(__('There are no records to display.')); } else { //Get child list $gibbonPersonID = null; @@ -127,9 +131,7 @@ } if (count($options) == 0) { - echo "
"; - echo __('Access denied.'); - echo '
'; + $page->addMessage(__('There are no records to display.')); } elseif (count($options) == 1) { $gibbonPersonID = key($options); } else { diff --git a/ATL/atl_write.php b/ATL/atl_write.php index 5a9f70d..54032e3 100644 --- a/ATL/atl_write.php +++ b/ATL/atl_write.php @@ -64,7 +64,7 @@ if ($gibbonCourseClassID == '') { try { $data = array('gibbonSchoolYearID' => $session->get('gibbonSchoolYearID'), 'gibbonPersonID' => $session->get('gibbonPersonID')); - $sql = 'SELECT gibbonCourse.nameShort AS course, gibbonCourseClass.nameShort AS class, gibbonCourseClass.gibbonCourseClassID FROM gibbonCourse, gibbonCourseClass, gibbonCourseClassPerson WHERE gibbonSchoolYearID=:gibbonSchoolYearID AND gibbonCourse.gibbonCourseID=gibbonCourseClass.gibbonCourseID AND gibbonCourseClass.gibbonCourseClassID=gibbonCourseClassPerson.gibbonCourseClassID AND gibbonCourseClassPerson.gibbonPersonID=:gibbonPersonID ORDER BY course, class'; + $sql = 'SELECT gibbonCourse.nameShort AS course, gibbonCourseClass.nameShort AS class, gibbonCourseClass.gibbonCourseClassID FROM gibbonCourse, gibbonCourseClass, gibbonCourseClassPerson WHERE gibbonSchoolYearID=:gibbonSchoolYearID AND gibbonCourse.gibbonCourseID=gibbonCourseClass.gibbonCourseID AND gibbonCourseClass.gibbonCourseClassID=gibbonCourseClassPerson.gibbonCourseClassID AND gibbonCourseClassPerson.gibbonPersonID=:gibbonPersonID AND gibbonCourseClassPerson.role NOT LIKE "%Left" ORDER BY course, class'; $result = $connection2->prepare($sql); $result->execute($data); } catch (PDOException $e) { diff --git a/ATL/atl_write_rubric.php b/ATL/atl_write_rubric.php index f96a8a0..f6eaeb1 100644 --- a/ATL/atl_write_rubric.php +++ b/ATL/atl_write_rubric.php @@ -121,7 +121,11 @@ echo "".Format::name('', $row4['preferredName'], $row4['surname'], 'Student', true).' - '.$row3['name'].''; echo ''; - $mark = isset($_GET['mark']) && $_GET['mark'] == 'FALSE' ? false : true; + $mark = $session->get('gibbonRoleIDCurrentCategory') == 'Staff'; + if (isset($_GET['mark']) && $_GET['mark'] == 'FALSE') { + $mark = false; + } + echo rubricView($guid, $connection2, $gibbonRubricID, $mark, $row4['gibbonPersonID'], 'atlColumn', 'atlColumnID', $atlColumnID, $contextDBTableGibbonRubricIDField, 'name', 'completeDate'); } } diff --git a/ATL/hook_studentProfile_atlView.php b/ATL/hook_studentProfile_atlView.php index 53f1896..56db83a 100644 --- a/ATL/hook_studentProfile_atlView.php +++ b/ATL/hook_studentProfile_atlView.php @@ -34,6 +34,11 @@ // Register scripts available to the core, but not included by default $page->scripts->add('chart'); + $roleCategory = $session->get('gibbonRoleIDCurrentCategory'); + if ($roleCategory == 'Staff') { + echo Format::alert(__m('As a staff member, your view of this ATL diagram accounts for all current ATL records, including those before their complete date. Parents and students will only see the ATL diagram based on completed data.'), 'message'); + } + echo visualiseATL($container, $gibbonPersonID); echo getATLRecord($guid, $connection2, $gibbonPersonID); diff --git a/ATL/manifest.php b/ATL/manifest.php index 043f608..1da467b 100644 --- a/ATL/manifest.php +++ b/ATL/manifest.php @@ -25,7 +25,7 @@ $entryURL = 'atl_write.php'; $type = 'Additional'; $category = 'Assess'; -$version = '1.5.11'; +$version = '1.5.12'; $author = 'Ross Parker'; $url = 'http://rossparker.org'; diff --git a/ATL/moduleFunctions.php b/ATL/moduleFunctions.php index d1efe9f..7708e1c 100644 --- a/ATL/moduleFunctions.php +++ b/ATL/moduleFunctions.php @@ -21,6 +21,7 @@ use Gibbon\Forms\Form; use Gibbon\Services\Format; use Gibbon\Forms\DatabaseFormFactory; +use Gibbon\Module\ATL\VisualiseATL; use Gibbon\Module\Rubrics\Visualise; use Gibbon\Domain\Rubrics\RubricGateway; use Gibbon\Module\ATL\Domain\ATLColumnGateway; @@ -29,6 +30,8 @@ function getATLRecord($guid, $connection2, $gibbonPersonID) { global $session, $container; + $roleCategory = $session->get('gibbonRoleIDCurrentCategory'); + require_once $session->get('absolutePath').'/modules/ATL/src/Domain/ATLColumnGateway.php'; $atlColumnGateway = $container->get(ATLColumnGateway::class); @@ -53,7 +56,8 @@ function getATLRecord($guid, $connection2, $gibbonPersonID) { $results = false; while ($rowYears = $resultYears->fetch()) { //Get and output ATLs - $entries = $atlColumnGateway->selectATLEntriesByStudent($rowYears['gibbonSchoolYearID'], $gibbonPersonID)->fetchAll(); + $entries = $atlColumnGateway->selectATLEntriesByStudent($rowYears['gibbonSchoolYearID'], $gibbonPersonID, $roleCategory)->fetchAll(); + $currentDate = date('Y-m-d'); if (!empty($entries)) { $results = true; @@ -80,15 +84,28 @@ function getATLRecord($guid, $connection2, $gibbonPersonID) { } ++$count; - $output .= ""; + if (!empty($rowATL['completeDate']) && $currentDate < $rowATL['completeDate']) { + $rowNum .= ' dull'; + if ($roleCategory != 'Staff') { + continue; + } + } + + $output .= ""; $output .= ''; $output .= "".$rowATL['course'].'
'.$rowATL['name'].'

'; $output .= ""; + if ($rowATL['completeDate'] != '') { - $output .= 'Marked on '.Format::date($rowATL['completeDate']).'
'; + $output .= 'Marked on '.Format::date($rowATL['completeDate']); } else { - $output .= 'Unmarked
'; + $output .= 'Unmarked'; } + + if (!empty($rowATL['completeDate']) && $currentDate < $rowATL['completeDate']) { + $output .= Format::tag(__m('Unpublished'), 'text-xxs bg-gray-400 ml-2'); + } + $output .= '

'; $output .= ''; if ($rowATL['gibbonRubricID'] == '') { @@ -151,6 +168,8 @@ function visualiseATL($container, $gibbonPersonID) { $session = $container->get(Session::class); $pdo = $container->get(Connection::class); + $roleCategory = $session->get('gibbonRoleIDCurrentCategory'); + require_once $session->get('absolutePath').'/modules/ATL/src/Domain/ATLColumnGateway.php'; // Display the visualization of all ATLs @@ -162,7 +181,7 @@ function visualiseATL($container, $gibbonPersonID) { $contextDBTableDateField = 'completeDate'; $rubricGateway = $container->get(RubricGateway::class); - $studentRubricInfo = $container->get(ATLColumnGateway::class)->getATLRubricByStudent($session->get('gibbonSchoolYearID'), $gibbonPersonID); + $studentRubricInfo = $container->get(ATLColumnGateway::class)->getATLRubricByStudent($session->get('gibbonSchoolYearID'), $gibbonPersonID, $roleCategory); $gibbonRubricID = $studentRubricInfo['gibbonRubricID'] ?? ''; $rubric = $rubricGateway->getByID($gibbonRubricID); @@ -195,8 +214,14 @@ function visualiseATL($container, $gibbonPersonID) { WHERE contextDBTable='$contextDBTable' AND gibbonRubricEntry.gibbonPersonID=:gibbonPersonID AND gibbonSchoolYearID=:gibbonSchoolYearID - AND NOT $contextDBTableDateField IS NULL - ORDER BY $contextDBTableDateField DESC"; + AND NOT $contextDBTableDateField IS NULL "; + + if ($roleCategory != 'Staff') { + $sqlContext .= " AND CURRENT_DATE >= $contextDBTable.$contextDBTableDateField "; + } + + $sqlContext .= " ORDER BY $contextDBTableDateField DESC"; + $resultContext = $pdo->select($sqlContext, $dataContext); if ($resultContext->rowCount() > 0) { @@ -219,7 +244,14 @@ function visualiseATL($container, $gibbonPersonID) { if (!empty($contexts) && !empty($columns) && !empty($rows) && !empty($cells)) { require_once $session->get('absolutePath').'/modules/Rubrics/src/Visualise.php'; - $visualise = new Visualise($session->get('absoluteURL'), $container->get('page'), $gibbonPersonID.'All', $columns, $rows, $cells, $contexts); + require_once $session->get('absolutePath').'/modules/ATL/src/VisualiseATL.php'; + + if (intval($gibbonRubricID) >= 318) { + $visualise = new VisualiseATL($session->get('absoluteURL'), $container->get('page'), $gibbonPersonID.'All', $columns, $rows, $cells, $contexts); + } else { + $visualise = new Visualise($session->get('absoluteURL'), $container->get('page'), $gibbonPersonID.'All', $columns, $rows, $cells, $contexts); + } + return $visualise->renderVisualise(); } diff --git a/ATL/src/Domain/ATLColumnGateway.php b/ATL/src/Domain/ATLColumnGateway.php index 3ff4db5..8b11b80 100644 --- a/ATL/src/Domain/ATLColumnGateway.php +++ b/ATL/src/Domain/ATLColumnGateway.php @@ -19,15 +19,15 @@ class ATLColumnGateway extends QueryableGateway private static $primaryKey = 'atlColumnID'; private static $searchableColumns = ['atlColumnID', 'issueName', 'description']; - public function getATLRubricByStudent($gibbonSchoolYearID, $gibbonPersonID) + public function getATLRubricByStudent($gibbonSchoolYearID, $gibbonPersonID, $roleCategory = 'Other') { - $data = array('gibbonSchoolYearID' => $gibbonSchoolYearID, 'gibbonPersonID' => $gibbonPersonID, 'today' => date('Y-m-d')); + $data = array('gibbonSchoolYearID' => $gibbonSchoolYearID, 'gibbonPersonID' => $gibbonPersonID); $sql = "SELECT gibbonPerson.gibbonPersonID, surname, preferredName, gibbonCourseClass.gibbonCourseClassID, - gibbonRubricID + atlColumn.gibbonRubricID FROM gibbonPerson JOIN gibbonStudentEnrolment ON (gibbonPerson.gibbonPersonID=gibbonStudentEnrolment.gibbonPersonID) JOIN gibbonFormGroup ON (gibbonStudentEnrolment.gibbonFormGroupID=gibbonFormGroup.gibbonFormGroupID) @@ -35,22 +35,30 @@ public function getATLRubricByStudent($gibbonSchoolYearID, $gibbonPersonID) JOIN gibbonCourseClass ON (gibbonCourseClassPerson.gibbonCourseClassID=gibbonCourseClass.gibbonCourseClassID) JOIN gibbonCourse ON (gibbonCourse.gibbonCourseID=gibbonCourseClass.gibbonCourseID AND gibbonCourse.gibbonSchoolYearID=gibbonStudentEnrolment.gibbonSchoolYearID) JOIN atlColumn ON (atlColumn.gibbonCourseClassID=gibbonCourseClass.gibbonCourseClassID) + JOIN gibbonRubric ON (gibbonRubric.gibbonRubricID=atlColumn.gibbonRubricID) WHERE status='Full' AND gibbonStudentEnrolment.gibbonSchoolYearID=:gibbonSchoolYearID - AND gibbonPerson.gibbonPersonID=:gibbonPersonID - AND atlColumn.completeDate<=:today + AND gibbonPerson.gibbonPersonID=:gibbonPersonID + AND gibbonRubric.active='Y'"; + + if ($roleCategory != 'Staff') { + $data['today'] = date('Y-m-d'); + $sql .= " AND atlColumn.completeDate<=:today "; + } + + $sql .= " AND gibbonCourseClassPerson.role='Student' AND gibbonCourseClass.reportable='Y' AND gibbonCourseClassPerson.reportable='Y' - ORDER BY surname, preferredName + ORDER BY atlColumn.completeDate DESC LIMIT 0, 1"; return $this->db()->selectOne($sql, $data); } - public function selectATLEntriesByStudent($gibbonSchoolYearID, $gibbonPersonID) + public function selectATLEntriesByStudent($gibbonSchoolYearID, $gibbonPersonID, $roleCategory = 'Other') { - $data = ['gibbonPersonID' => $gibbonPersonID, 'gibbonSchoolYearID' => $gibbonSchoolYearID, 'today' => date('Y-m-d')]; + $data = ['gibbonPersonID' => $gibbonPersonID, 'gibbonSchoolYearID' => $gibbonSchoolYearID]; $sql = "SELECT DISTINCT atlColumn.*, atlEntry.*, @@ -64,9 +72,14 @@ public function selectATLEntriesByStudent($gibbonSchoolYearID, $gibbonPersonID) JOIN gibbonPerson ON (atlEntry.gibbonPersonIDStudent=gibbonPerson.gibbonPersonID) WHERE gibbonCourseClassPerson.gibbonPersonID=:gibbonPersonID AND atlEntry.gibbonPersonIDStudent=:gibbonPersonID - AND gibbonSchoolYearID=:gibbonSchoolYearID - AND atlColumn.completeDate<=:today - AND gibbonCourseClassPerson.role='Student' + AND gibbonSchoolYearID=:gibbonSchoolYearID "; + + if ($roleCategory != 'Staff') { + $data['today'] = date('Y-m-d'); + $sql .= " AND atlColumn.completeDate<=:today "; + } + + $sql .= " AND gibbonCourseClassPerson.role='Student' AND gibbonCourseClass.reportable='Y' AND gibbonCourseClassPerson.reportable='Y' ORDER BY atlColumn.completeDate DESC, gibbonCourse.nameShort, gibbonCourseClass.nameShort"; diff --git a/ATL/src/VisualiseATL.php b/ATL/src/VisualiseATL.php new file mode 100644 index 0000000..833d4ba --- /dev/null +++ b/ATL/src/VisualiseATL.php @@ -0,0 +1,178 @@ +. + */ + +namespace Gibbon\Module\ATL; + +use Gibbon\Http\Url; +use Gibbon\UI\Chart\Chart; +use Gibbon\Module\Rubrics\Visualise; + +/** + * Attendance display & edit class + * + * @version v26 + * @since v18 + */ +class VisualiseATL extends Visualise +{ + + /** + * renderVisualise + * + * @version v26 + * @since v18 + * @param $legend should the legend be included? + * @param $image should the chart be saved as an image + * @param $path if image is saved, where should it be saved (defaults to standard upload location) + * @param $id optionally outputs the image path to the value of the given id + * @return void + */ + public function renderVisualise($legend = true, $image = false, $path = '', $id = '') + { + //Filter out columns to ignore from visualisation + $this->columns = array_filter($this->columns, function ($item) { + return (isset($item['visualise']) && $item['visualise'] == 'Y'); + }); + + + if (!empty($this->columns) && !empty($this->cells)) { + //Cycle through rows to calculate means + $means = array() ; + foreach ($this->rows as $row) { + $means[$row['gibbonRubricRowID']]['title'] = $row['title']; + $means[$row['gibbonRubricRowID']]['cumulative'] = 0; + $means[$row['gibbonRubricRowID']]['denonimator'] = 0; + + //Cycle through cells, and grab those for this row + $cellCount = 1 ; + + foreach ($this->cells[$row['gibbonRubricRowID']] as $cell) { + $visualise = false ; + foreach ($this->columns as $column) { + if ($column['gibbonRubricColumnID'] == $cell['gibbonRubricColumnID']) { + $visualise = true ; + } + } + + if ($visualise) { + foreach ($this->contexts as $entry) { + if ($entry['gibbonRubricCellID'] == $cell['gibbonRubricCellID']) { + $means[$row['gibbonRubricRowID']]['cumulative'] += $cellCount; + $means[$row['gibbonRubricRowID']]['denonimator']++; + } + } + $cellCount++; + } + } + } + + $columnCount = count($this->columns); + + $data = array_map(function ($mean) use ($columnCount) { + return !empty($mean['denonimator']) + ? round((($mean['cumulative']/$mean['denonimator'])/$columnCount), 2) + : 0; + }, $means); + + $this->page->scripts->add('chart'); + + $chart = Chart::create('visualisation'.$this->gibbonPersonID, 'polarArea') + ->setLegend(['display' => $legend, 'position' => 'right']) + ->setLabels(array_column($means, 'title')) + ->setColorOpacity(0.6) + ->onTooltip('function(tooltipItem) { + return tooltipItem.label; + }'); + + $options = [ + 'responsive' => 'true', + 'maintainAspectRatio' => 'true', + 'aspectRatio' => 2, + 'height' => '38vw', + + 'scales' => [ + 'r' => [ + + + 'min' => 0.0, + 'max' => 1.0, + + 'ticks' => [ + // 'display' => false, + 'z' => 1, + 'showLabelBackdrop' => false, + 'stepSize' => 0.142857143, + 'callback' => $chart->addFunction('function(tickValue, index, ticks) {'. + ($image ? '' : ' + var tick = Number(tickValue).toFixed(1); + + if (tick == 0.6) return "Apprentice"; + if (tick == 0.9) return "Wayfinder"; + if (tick == 1.0) return "Master"; + + return "";'). + '}'), + 'color' => '#777777', + 'font' => [ + 'size' => '14', + ], + ], + 'grid' => [ + 'display' => $image ? false : true, + ], + ], + ] + ]; + if ($image) { + $ajaxUrl = $this->absoluteURL . '/modules/Rubrics/rubrics_visualise_saveAjax.php'; + $options['animation'] = [ + 'duration' => 0, + 'onComplete' => $chart->addFunction('function(e) { + var img = visualisation'.$this->gibbonPersonID.'.toDataURL("image/png"); + $.ajax({ + url: ' . json_encode($ajaxUrl) . ', + type: "POST", + data: { + img: img, + gibbonPersonID: '.json_encode($this->gibbonPersonID).', + path: '.json_encode($path).' + }, + dataType: "html", + success: function (data) { + '.( $id ? '$("#'.$id.'").val(data);' : '' ).' + } + }); + this.options.animation.onComplete = null; + }'), + ]; + } + $chart->setOptions($options); + + // Handle custom colours only if there is one unique colour per row + $rowColours = array_unique(array_column($this->rows, 'backgroundColor')); + if (count($rowColours) == count($this->rows)) { + $chart->setColors($rowColours); + } + + $chart->addDataset('rubric')->setData($data); + + return $chart->render(); + } + } +} diff --git a/ATL/version.php b/ATL/version.php index 48e8eb1..4fae002 100644 --- a/ATL/version.php +++ b/ATL/version.php @@ -20,5 +20,5 @@ /** * Sets version information. */ -$moduleVersion = '1.5.11'; +$moduleVersion = '1.5.12'; $coreVersion = '23.0.00';