From c7906147d241d0bc4a4a1624a65ce30d83778a43 Mon Sep 17 00:00:00 2001 From: Tim Steiner <tsteiner2@unl.edu> Date: Tue, 1 Jun 2010 15:41:52 +0000 Subject: [PATCH] Merging changes from /branches/redesign up to r690. --- .../auth/controllers/IndexController.php | 12 +- application/modules/auth/models/UserModel.php | 35 ++++- .../controllers/PublicViewController.php | 4 +- .../modules/courses/models/CourseModel.php | 19 ++- .../scripts/queue-manager/request-table.phtml | 42 +++++ .../default/views/scripts/error/error.phtml | 6 +- .../default/views/scripts/layout.phtml | 2 +- .../modules/default/views/scripts/menu.phtml | 27 +++- .../requests/controllers/IndexController.php | 1 - .../controllers/QueueManagerController.php | 52 ++++++- .../models/ApprovalActionQueueModel.php | 105 +++++++++++-- .../models/ApprovalActionVoteModel.php | 143 ++++++++---------- .../requests/models/ApproverVoteModel.php | 23 ++- .../modules/requests/models/RequestModel.php | 9 +- .../approval-body-admin/edit-role.phtml | 4 +- .../views/scripts/queue-manager/view.phtml | 18 ++- .../ucc/controllers/ReportsController.php | 42 +---- .../courses/queue-manager/request-table.css | 4 + .../javascript/requests/queue-manager.js | 10 ++ document_root/schema/courses.xsd | 2 +- library/App/Controller/Action.php | 30 +--- 21 files changed, 397 insertions(+), 193 deletions(-) create mode 100644 application/modules/courses/views/scripts/queue-manager/request-table.phtml create mode 100644 document_root/css/courses/queue-manager/request-table.css create mode 100644 document_root/javascript/requests/queue-manager.js diff --git a/application/modules/auth/controllers/IndexController.php b/application/modules/auth/controllers/IndexController.php index d8624c79..331f4f11 100644 --- a/application/modules/auth/controllers/IndexController.php +++ b/application/modules/auth/controllers/IndexController.php @@ -45,14 +45,17 @@ class Auth_IndexController extends App_Controller_Action { public function logoutAction() { Zend_Auth::getInstance()->clearIdentity(); - $this->_getCasAdapter()->clearIdentity(); $this->_redirect($this->_getCasAdapter()->getLogoutUrl()); } public function validateAction() { - $auth = Unl_Auth::getInstance(); - $auth->pushAdapter($this->_getCasAdapter()); + $auth = Unl_Auth::getInstance(); + $casAdapter = $this->_getCasAdapter(); + if ($this->_getParam('logoutRequest')) { + $casAdapter->handleLogoutRequest($this->_getParam('logoutRequest')); + } + $auth->pushAdapter($casAdapter); try { $result = $auth->authenticate(); @@ -65,6 +68,9 @@ class Auth_IndexController extends App_Controller_Action { if (!$user) { $user = Auth_UserModel::fetchNewFromLdap($auth->getIdentity()); } + } else { + Zend_Auth::getInstance()->clearIdentity(); + setcookie('unl_sso', 'fake', time() - 60*60*24, '/', '.unl.edu'); } $session = new Zend_Session_Namespace(__CLASS__); diff --git a/application/modules/auth/models/UserModel.php b/application/modules/auth/models/UserModel.php index f6c6c0cb..d3a25e6b 100644 --- a/application/modules/auth/models/UserModel.php +++ b/application/modules/auth/models/UserModel.php @@ -96,7 +96,7 @@ class Auth_UserModel extends Unl_Model { { $username = Zend_Auth::getInstance()->getIdentity(); if (!$username) { - throw new Exception('You must be logged in to view this page.'); + self::authenticateUser(TRUE); } return self::findByUsername($username); @@ -405,6 +405,39 @@ class Auth_UserModel extends Unl_Model { $db->query($sql); } + /** + * If the user is not currently logged in, calling this will attempt to log them in + * and if $required is TRUE, additionally redirect them to the login page. + * @param bool $required + */ + static public function authenticateUser($required = FALSE) + { + $redirectUri = $_SERVER['REQUEST_URI']; + $baseUrl = Zend_Controller_Front::getInstance()->getBaseUrl(); + $redirectUri = substr($redirectUri, strlen($baseUrl)); + + $authSession = new Zend_Session_Namespace('Auth_IndexController'); + $authSession->referer = $redirectUri; + + + if ($_SERVER['HTTPS'] == 'on') { + $serviceUrl = 'https://'; + } else { + $serviceUrl = 'http://'; + } + $serviceUrl .= $_SERVER['SERVER_NAME'] . Zend_Controller_Front::getInstance()->getBaseUrl() . '/auth/index/validate'; + + $casAdapter = new Unl_Auth_Adapter_Cas($serviceUrl, 'https://login.unl.edu/cas'); + if (!$required) { + $casAdapter->setGateway(); + } + + if ($casAdapter->isTicketExpired() || !Zend_Auth::getInstance()->hasIdentity()) { + header('Location: ' . $casAdapter->getLoginUrl()); + exit; + } + } + public function __toString() { return $this->getFirstName() . ' ' . $this->getLastName(); diff --git a/application/modules/courses/controllers/PublicViewController.php b/application/modules/courses/controllers/PublicViewController.php index e874200f..3fe6773d 100644 --- a/application/modules/courses/controllers/PublicViewController.php +++ b/application/modules/courses/controllers/PublicViewController.php @@ -54,8 +54,8 @@ class Courses_PublicViewController extends App_Controller_Action { if ($crosslisting['courseLetter']) { $courseCodeNode->appendChild($dom->createElement('courseLetter', $crosslisting['courseLetter'])); } - if ($crosslisting['courseGroup']) { - $courseCodeNode->appendChild($dom->createElement('courseGroup', $crosslisting['courseGroup'])); + foreach ($crosslisting['courseGroups'] as $courseGroup) { + $courseCodeNode->appendChild($dom->createElement('courseGroup', $courseGroup)); } } } else { diff --git a/application/modules/courses/models/CourseModel.php b/application/modules/courses/models/CourseModel.php index f34d01ed..8411788d 100644 --- a/application/modules/courses/models/CourseModel.php +++ b/application/modules/courses/models/CourseModel.php @@ -152,7 +152,8 @@ class Courses_CourseModel extends Unl_Model $select = new Zend_Db_Select($db); $select->from(array('x' => 'creqCourseCrosslistings'), array('courseCrosslistingId', 'generation', 'type')); $select->join(array('c' => 'creqCourseCodes'), 'x.courseCode = c.courseCodeId'); - $select->joinLeft(array('u' => 'creqCourseGroups'), 'c.group = u.courseGroupId', array('courseGroup' => 'name')); + $select->joinLeft(array('g' => 'creqCourseCodeGroups'), 'c.courseCodeId = g.courseCode', array('courseCodeGroupId')); + $select->joinLeft(array('u' => 'creqCourseGroups'), 'g.group = u.courseGroupId', array('courseGroup' => 'name')); $select->join(array('s' => 'creqSubjects'), 'c.subject = s.name', array()); $select->join(array('d' => 'creqDepartments'), 's.department = d.departmentId', array('department' => 'name')); $select->join(array('cl' => 'creqColleges'), 'd.college = cl.collegeId', array('college' => 'name', 'collegeLong' => 'description')); @@ -162,6 +163,12 @@ class Courses_CourseModel extends Unl_Model foreach($records as $record) { $courseId = $record['generation']; $crosslistingId = $record['courseCrosslistingId']; + $groups = (array)$courses[$courseId]['crosslistings'][$crosslistingId]['courseGroups']; + if ($record['courseGroup']) { + $groups[$record['courseCodeGroupId']] = $record['courseGroup']; + } + $record['courseGroups'] = $groups; + unset($record['courseGroup']); $courses[$courseId]['crosslistings'][$crosslistingId] = $record; } @@ -1717,7 +1724,7 @@ class Courses_CourseModel extends Unl_Model if ($crosslisting['type'] != 'home listing') { continue; } - $homeNumber = str_pad($crosslisting['courseNumber'], 3, '0', STR_PAD_LEFT); + $homeNumber = $crosslisting['courseNumber']; } return $homeNumber; } @@ -1769,7 +1776,7 @@ class Courses_CourseModel extends Unl_Model continue; } $homeSubject = $crosslisting['subject']; - $courseNumbers[] = str_pad($crosslisting['courseNumber'], 3, '0', STR_PAD_LEFT) . $crosslisting['courseLetter']; + $courseNumbers[] = $crosslisting['courseNumber'] . $crosslisting['courseLetter']; } foreach ($this->_data['crosslistings'] as $crosslisting) { if ($this->_isEffectiveHomeCrosslisting($crosslisting)) { @@ -1778,7 +1785,7 @@ class Courses_CourseModel extends Unl_Model if ($crosslisting['subject'] != $homeSubject) { continue; } - $courseNumbers[] = str_pad($crosslisting['courseNumber'], 3, '0', STR_PAD_LEFT) . $crosslisting['courseLetter']; + $courseNumbers[] = $crosslisting['courseNumber'] . $crosslisting['courseLetter']; } sort($courseNumbers); @@ -1794,7 +1801,7 @@ class Courses_CourseModel extends Unl_Model continue; } $homeSubject = $crosslisting['subject']; - $courseNumbers[] = str_pad($crosslisting['courseNumber'], 3, '0', STR_PAD_LEFT) . $crosslisting['courseLetter']; + $courseNumbers[] = $crosslisting['courseNumber'] . $crosslisting['courseLetter']; } foreach ($this->_data['crosslistings'] as $crosslisting) { if ($this->_isEffectiveHomeCrosslisting($crosslisting)) { @@ -1803,7 +1810,7 @@ class Courses_CourseModel extends Unl_Model if ($crosslisting['subject'] != $homeSubject) { continue; } - $courseNumbers[] = str_pad($crosslisting['courseNumber'], 3, '0', STR_PAD_LEFT) . $crosslisting['courseLetter'] . 'x'; + $courseNumbers[] = $crosslisting['courseNumber'] . $crosslisting['courseLetter'] . 'x'; } sort($courseNumbers); diff --git a/application/modules/courses/views/scripts/queue-manager/request-table.phtml b/application/modules/courses/views/scripts/queue-manager/request-table.phtml new file mode 100644 index 00000000..3f987fa1 --- /dev/null +++ b/application/modules/courses/views/scripts/queue-manager/request-table.phtml @@ -0,0 +1,42 @@ +<?php + +$proposedCourses = Courses_CourseModel::findLatestOfRequest($this->requests); +$originalCourses = Courses_CourseModel::findParentOfRequest($this->requests); + +$requestCourses = array(); +foreach ($this->requests as $requset) { + $requestId = $requset->getId(); + if ($originalCourses[$requestId]) { + $course = $originalCourses[$requestId]; + } else { + $course = $proposedCourses[$requestId]; + } + $requestCourses[$requestId] = $course; +} + + + + + +$this->headLink()->appendStylesheet($this->baseUrl() . '/css/courses/queue-manager/request-table.css', 'all'); ?> +<table class="zentable primary" id="courseRequestTable"> + <tr> + <th>Course Code</th> + <?php foreach ($this->users as $user) { ?> + <th><?php echo $user->getFirstName() . ' ' . $user->getLastName(); ?></th> + <?php } ?> + </tr> + +<?php foreach ($this->requests as $request) { + $course = $requestCourses[$request->getId()]; + $userVotes = $this->requestUserVotes[$request->getId()]; ?> + <tr> + <td><?php echo $course->getCourseCode(); ?></td> + <?php foreach ($this->users as $user) { + $vote = $userVotes[$user->getId()]; ?> + <td><?php echo $vote; ?></td> + <?php } ?> + </tr> + +<?php } ?> +</table> \ No newline at end of file diff --git a/application/modules/default/views/scripts/error/error.phtml b/application/modules/default/views/scripts/error/error.phtml index 928c154a..76d75973 100644 --- a/application/modules/default/views/scripts/error/error.phtml +++ b/application/modules/default/views/scripts/error/error.phtml @@ -1,9 +1,9 @@ -<h1>Unfortunately an unexpected error has occured.</h1> +<h1>Unfortunately an unexpected error has occurred.</h1> <h2>Details have been mailed to the administrator for analysis.</h2> <p> The error message was: "<?php echo $this->exceptions[0]->getMessage(); ?>" </p> <p> - We appologize for the inconvience. + We apologize for the inconvenience. Please use the back button to return to your previous location -</p> \ No newline at end of file +</p> diff --git a/application/modules/default/views/scripts/layout.phtml b/application/modules/default/views/scripts/layout.phtml index 7df5e3b3..f7c51575 100644 --- a/application/modules/default/views/scripts/layout.phtml +++ b/application/modules/default/views/scripts/layout.phtml @@ -9,7 +9,7 @@ if ($_SERVER['HTTPS']) { $staticBaseUrl = 'http://'; } $staticBaseUrl .= $_SERVER['HTTP_HOST'] - . $baseUrl; + . $baseUrl . '/'; $this->headLink()->appendStylesheet($this->baseUrl() . '/css/index.css', 'all'); $this->headLink()->appendStylesheet($this->baseUrl() . '/css/print.css', 'print'); diff --git a/application/modules/default/views/scripts/menu.phtml b/application/modules/default/views/scripts/menu.phtml index 7b4c9ab8..d70f6844 100644 --- a/application/modules/default/views/scripts/menu.phtml +++ b/application/modules/default/views/scripts/menu.phtml @@ -1,5 +1,14 @@ +<?php +if (Zend_Auth::getInstance()->getIdentity()) { + $user = Auth_UserModel::findCurrentUser(); + $roles = Auth_GroupModel::findByUser($user); +} else { + $user = NULL; +} + +?> <ul> - <?php if (Zend_Auth::getInstance()->getIdentity()) { ?> + <?php if ($user) { ?> <li><a href="<?php echo $this->baseUrl(); ?>/requests">My Requests</a></li> <li><a href="<?php echo $this->baseUrl(); ?>/requests/new">New Request</a></li> <?php } ?> @@ -7,7 +16,21 @@ <li><a href="<?php echo $this->baseUrl(); ?>/courses/public-view/search">Curriculum Search</a></li> <li><a href="<?php echo $this->baseUrl(); ?>/ucc/reports/monthly">UCC Activity</a></li> - <?php if (Zend_Auth::getInstance()->getIdentity()) { ?> + <?php if ($user && in_array(1, $roles->getId())) { ?> + <li> + <a>Admin</a> + <ul> + <li><a href="<?php echo $this->baseUrl(); ?>/auth/user-admin">Users & Groups</a></li> + <li><a href="<?php echo $this->baseUrl(); ?>/requests/approval-body-admin">Approval Bodies</a></li> + <li><a href="<?php echo $this->baseUrl(); ?>/requests/approval-chain-manager">Approval Chains</a></li> + <li><a href="<?php echo $this->baseUrl(); ?>/requests/queue-manager">Queues</a></li> + <li><a href="<?php echo $this->baseUrl(); ?>/requests/withdrawn">Withdrawn Requests</a></li> + <li><a href="<?php echo $this->baseUrl(); ?>/requests/notification" dir="dir ">Notification List</a></li> + </ul> + </li> + <?php } ?> + + <?php if ($user) { ?> <li><a href="<?php echo $this->baseUrl(); ?>/auth/index/logout">Log Out</a></li> <?php } else { ?> <li><a href="<?php echo $this->baseUrl(); ?>/auth/index/login">Log In</a></li> diff --git a/application/modules/requests/controllers/IndexController.php b/application/modules/requests/controllers/IndexController.php index b67d5d06..5a37969e 100644 --- a/application/modules/requests/controllers/IndexController.php +++ b/application/modules/requests/controllers/IndexController.php @@ -16,7 +16,6 @@ class Requests_IndexController extends App_Controller_Action */ public function indexAction() { - $this->_authorize->requireLogin(); $in = $this->getRequest()->getParams(); $user = Auth_UserModel::findCurrentUser(); diff --git a/application/modules/requests/controllers/QueueManagerController.php b/application/modules/requests/controllers/QueueManagerController.php index b6312b63..bfa286e6 100644 --- a/application/modules/requests/controllers/QueueManagerController.php +++ b/application/modules/requests/controllers/QueueManagerController.php @@ -22,10 +22,58 @@ class Requests_QueueManagerController extends App_Controller_Action { $in = $this->_getAllParams(); $queue = Requests_ApprovalActionModel::find($in['id']); - $requests = Requests_RequestModel::findWithCurrentApprovalAction($queue); + $periodId = $in['period']; + if ($periodId > 0) { + $periods = $queue->getPeriods(); + $period = $periods[$periodId]; + $periodStart = $period['start']->addSecond(1); + $periodEnd = $period['end']; + $allRequests = Requests_ApprovalHistoryModel::findRequestsWithinTimeRangeAndApprovalAction( + $periodStart, $periodEnd, $queue + ); + } else { + $allRequests = Requests_RequestModel::findWithCurrentApprovalAction($queue); + $periodEnd = new Zend_Date(); + } + $moduleRequests = array(); + foreach ($allRequests as $request) { + $module = $request->getModule(); + if (!$moduleRequests[$module]) { + $moduleRequests[$module] = new Unl_Model_Collection('Requests_RequestModel'); + } + $moduleRequests[$module][$request->getId()] = $request; + } + + $periods = $queue->getPeriods(); + $periodArray = array(); + foreach ($periods as $periodId => $period) { + if ($period['end']) { + $periodArray[$periodId] = $period['end']->toString('YYYY-MM-dd'); + } else { + $periodArray[-1] = 'Current'; + } + } + + $requestVotes = Requests_ApproverVoteModel::findVotesForRequests($allRequests, $periodEnd, $queue); + + $requestUserVotes = array(); + $userIds = array(); + foreach ($requestVotes as $requestId => $votes) { + foreach ($votes as $voteId => $vote) { + $userIds[$vote->getUser()] = $vote->getUser(); + $requestUserVotes[$requestId][$vote->getUser()] = $vote->getVote(); + } + } + $users = Auth_UserModel::find($userIds); + $users->orderBy('getLastName'); + $this->view->queue = $queue; - $this->view->requests = $requests; + $this->view->currentPeriod = $in['period']; + $this->view->periods = $periodArray; + $this->view->moduleRequests = $moduleRequests; + $this->view->requestUserVotes = $requestUserVotes; + $this->view->users = $users; } public function editPostAction() diff --git a/application/modules/requests/models/ApprovalActionQueueModel.php b/application/modules/requests/models/ApprovalActionQueueModel.php index a9d5a30a..e66ad75c 100644 --- a/application/modules/requests/models/ApprovalActionQueueModel.php +++ b/application/modules/requests/models/ApprovalActionQueueModel.php @@ -9,6 +9,9 @@ class Requests_ApprovalActionQueueModel extends Requests_ApprovalActionModel $select = new Zend_Db_Select($db); $select->from(array('a' => 'creqApprovalActions')); $select->join(array('q' => 'creqApprovalActionsQueue'), 'a.approvalActionId = q.approvalActionId'); + $select->join(array('p' => 'creqApprovalActionsQueuePeriods'), + 'a.approvalActionId = p.approvalAction AND p.endTime IS NULL', + array('startTime', 'currentPeriod' => 'approvalActionsQueuePeriodId')); if (Unl_Util::isArray($id)) { $select->where('a.approvalActionId IN(?)', $id); } else { @@ -38,6 +41,25 @@ class Requests_ApprovalActionQueueModel extends Requests_ApprovalActionModel $date = $record['date']; $objects[$objectId]->_data['dates'][] = new Zend_Date($date); } + + + $select = new Zend_Db_Select($db); + $select->from(array('p' => 'creqApprovalActionsQueuePeriods')); + $select->order('startTime DESC'); + if (Unl_Util::isArray($id)) { + $select->where('p.approvalAction IN(?)', $id); + } else { + $select->where('p.approvalAction = ?', $id); + } + $records = $db->query($select)->fetchAll(); + + foreach ($records as $record) { + $objectId = $record['approvalAction']; + $periodId = $record['approvalActionsQueuePeriodId']; + $objects[$objectId]->_data['periods'][$periodId] = array('start' => new Zend_Date($record['startTime']), + 'end' => ($record['endTime'] ? new Zend_Date($record['endTime']) : NULL), + 'id' => $record['approvalActionsQueuePeriodId']); + } if (Unl_Util::isArray($objects)) { return $objects; @@ -154,7 +176,8 @@ class Requests_ApprovalActionQueueModel extends Requests_ApprovalActionModel static protected function _insert(Unl_Model_Collection $models) { $db = Zend_Registry::get('db'); - + + // Insert the queue row $sql = 'INSERT INTO creqApprovalActionsQueue (approvalActionId, canChangeVote) VALUES '; $sqlParts = array(); foreach ($models as $model) { @@ -163,6 +186,18 @@ class Requests_ApprovalActionQueueModel extends Requests_ApprovalActionModel } $sql .= implode(', ', $sqlParts); $db->query($sql); + + + + // Insert the initial queue period starting at the current time. + $sql = 'INSERT INTO creqApprovalActionsQueuePeriods (approvalAction, startTime) VALUES '; + $sqlParts = array(); + foreach ($models as $model) { + $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId']) + . $db->quoteInto('?)' , time()); + } + $sql .= implode(', ', $sqlParts); + $db->query($sql); } static protected function _insertDates(array $models) @@ -248,6 +283,38 @@ class Requests_ApprovalActionQueueModel extends Requests_ApprovalActionModel Requests_ApprovalChainModel::advance($requests); Requests_ApprovalChainModel::consider($requests); + + + $select = new Zend_Db_Select($db); + $select->from(array('q' => 'creqApprovalActionsQueueDates'), array('approvalAction')); + $select->where('q.date <= ?', time()); + + $queueIds = array(); + $records = $select->query()->fetchAll(); + if (count($records) == 0) { + return; + } + foreach ($records as $record) { + $queueIds[] = $record['approvalAction']; + } + + + $sql = 'UPDATE creqApprovalActionsQueuePeriods ' + . $db->quoteInto('SET endTime = ? ', time()) + . 'WHERE endTime IS NULL ' + . $db->quoteInto('AND approvalAction IN (?) ', $queueIds); + $db->query($sql); + + $sql = 'INSERT INTO creqApprovalActionsQueuePeriods (approvalAction, startTime) VALUES '; + $sqlParts = array(); + foreach ($queueIds as $queueId) { + $sqlParts[] = $db->quoteInto('(?, ', $queueId) + . $db->quoteInto('?)' , time()); + } + $sql .= implode(', ', $sqlParts); + $db->query($sql); + + $db->query($db->quoteInto('DELETE FROM creqApprovalActionsQueueDates WHERE date <= ?', time())); } @@ -259,21 +326,12 @@ class Requests_ApprovalActionQueueModel extends Requests_ApprovalActionModel public function userMadeDecisions($requests, $requestDecisions) { $user = Auth_UserModel::findCurrentUser(); - $votes = Requests_ApproverVoteModel::findUsersVotesForRequests($user, $requests, $this); - $requestHistories = Requests_ApprovalHistoryModel::findByRequest($requests); + $votes = Requests_ApproverVoteModel::findUsersVotesForRequests($user, $requests, $this->getCurrentPeriodId()); foreach ($requests as $request) { - $histories = $requestHistories[$request->getId()]; - $histories->orderBy('getUnixtime', SORT_DESC); - $lastEndTime = new Zend_Date(0); - foreach ($histories as $history) { - if ($history->getApprovalAction() == $this->getId()) { - $lastEndTime = $history->getTime(); - break; - } - } - if ($votes[$request->getId()] && $votes[$request->getId()]->getApprovalAction() == $this->getId()) { - $vote = $votes[$request->getId()]; - if (!$this->getCanChangeVote() && $lastEndTime->isEarlier($vote->getTime())) { + if ($votes[$request->getId()]) { + if ($this->getCanChangeVote()) { + $vote = $votes[$request->getId()]; + } else { continue; } } else { @@ -314,6 +372,11 @@ class Requests_ApprovalActionQueueModel extends Requests_ApprovalActionModel $this->_data['dates'] = $dates; } + public function getPeriods() + { + return $this->_data['periods']; + } + public function setExtendedData($data) { $this->_data['canChangeVote'] = $data['canChangeVote']; @@ -324,6 +387,8 @@ class Requests_ApprovalActionQueueModel extends Requests_ApprovalActionModel continue; } $date = new Zend_Date(); + $date->setDay(1); + $date->setYear($dateParts['year']); $date->setMonth($dateParts['month']); $date->setDay($dateParts['day']); @@ -336,5 +401,15 @@ class Requests_ApprovalActionQueueModel extends Requests_ApprovalActionModel $this->setDates($dates); } + + public function getCurrentPeriodStartTime() + { + return new Zend_Date($this->_data['startTime']); + } + + public function getCurrentPeriodId() + { + return $this->_data['currentPeriod']; + } } diff --git a/application/modules/requests/models/ApprovalActionVoteModel.php b/application/modules/requests/models/ApprovalActionVoteModel.php index 48194cff..134358c7 100644 --- a/application/modules/requests/models/ApprovalActionVoteModel.php +++ b/application/modules/requests/models/ApprovalActionVoteModel.php @@ -10,6 +10,9 @@ class Requests_ApprovalActionVoteModel extends Requests_ApprovalActionQueueModel $select->from(array('a' => 'creqApprovalActions')); $select->join(array('q' => 'creqApprovalActionsQueue'), 'a.approvalActionId = q.approvalActionId'); $select->join(array('v' => 'creqApprovalActionsVote'), 'a.approvalActionId = v.approvalActionId'); + $select->join(array('p' => 'creqApprovalActionsQueuePeriods'), + 'a.approvalActionId = p.approvalAction AND p.endTime IS NULL', + array('startTime', 'currentPeriod' => 'approvalActionsQueuePeriodId')); if (Unl_Util::isArray($id)) { $select->where('a.approvalActionId IN(?)', $id); } else { @@ -24,32 +27,39 @@ class Requests_ApprovalActionVoteModel extends Requests_ApprovalActionQueueModel $objectId = $object->getId(); $objects[$objectId] = $object; } + $select = new Zend_Db_Select($db); - $select->from(array('v' => 'creqApproverVotes')); + $select->from(array('d' => 'creqApprovalActionsQueueDates')); if (Unl_Util::isArray($id)) { - $select->where('v.approvalAction IN(?)', $id); + $select->where('d.approvalAction IN(?)', $id); } else { - $select->where('v.approvalAction = ?', $id); + $select->where('d.approvalAction = ?', $id); } - $records = $select->query()->fetchAll(); + $records = $db->query($select)->fetchAll(); + foreach ($records as $record) { - $objects[$record['approvalAction']]->_data['votes'][$record['request']][$record['approverVoteId']] = $record; + $objectId = $record['approvalAction']; + $date = $record['date']; + $objects[$objectId]->_data['dates'][] = new Zend_Date($date); } - + $select = new Zend_Db_Select($db); - $select->from(array('d' => 'creqApprovalActionsQueueDates')); + $select->from(array('p' => 'creqApprovalActionsQueuePeriods')); + $select->order('startTime DESC'); if (Unl_Util::isArray($id)) { - $select->where('d.approvalAction IN(?)', $id); + $select->where('p.approvalAction IN(?)', $id); } else { - $select->where('d.approvalAction = ?', $id); + $select->where('p.approvalAction = ?', $id); } $records = $db->query($select)->fetchAll(); foreach ($records as $record) { $objectId = $record['approvalAction']; - $date = $record['date']; - $objects[$objectId]->_data['dates'][] = new Zend_Date($date); + $periodId = $record['approvalActionsQueuePeriodId']; + $objects[$objectId]->_data['periods'][$periodId] = array('start' => new Zend_Date($record['startTime']), + 'end' => ($record['endTime'] ? new Zend_Date($record['endTime']) : NULL), + 'id' => $record['approvalActionsQueuePeriodId']); } if (Unl_Util::isArray($objects)) { @@ -174,73 +184,12 @@ class Requests_ApprovalActionVoteModel extends Requests_ApprovalActionQueueModel } public function finalize($requests) - { - $requestHistories = Requests_ApprovalHistoryModel::findByRequest($requests); - + { + $requestVotes = Requests_ApproverVoteModel::findVotesForRequests($requests, new Zend_Date(), $this); foreach ($requests as $request) { - - $votes = $this->_data['votes'][$request->getId()]; - if (!Unl_Util::isArray($votes) || count($votes) == 0) { - $request->setState(null); - continue; - } - - - $histories = $requestHistories[$request->getId()]; - $histories->orderBy('getUnixtime', SORT_DESC); - $lastEndTime = new Zend_Date(0); - foreach ($histories as $history) { - if ($history->getApprovalAction() == $this->getId()) { - $lastEndTime = $history->getTime(); - break; - } - } - $currentVotes = array(); - foreach ($votes as $vote) { - $voteTime = new Zend_Date($vote['time']); - if ($voteTime->isEarlier($lastEndTime)) { - continue; - } - $currentVotes[] = $vote; - } - $votes = $currentVotes; - - - $voteCount = count($votes); - if ($voteCount < $this->getQuorum()) { - $request->setState(null); - continue; - } - - - $voteTally = array(); - foreach ($votes as $vote) { - $voteTally[$vote['vote']]++; - } - if ($voteTally['Table'] >= $this->getVotesToTable()) { - $request->setState('Table'); - continue; - } - - // TODO: Handle Ties - $mostVotes = 0; - $winner = ''; - foreach ($voteTally as $name => $count) { - if ($count > $mostVotes) { - $winner = $name; - $mostVotes = $count; - } - } - - if ($this->_data['requiredVotes'] == 'plurality') { - $request->setState($winner); - } else if ($this->_data['requiredVotes'] == 'majority' && ($mostVotes / $voteCount) > 0.5) { - $request->setState($winner); - } else if ($this->_data['requiredVotes'] == 'unanimity' && ($mostVotes / $voteCount) == 1.0) { - $request->setState($winner); - } else { - $request->setState(null); - } + $votes = $requestVotes[$request->getId()]; + $result = $this->tallyVotes($votes); + $request->setState($result); } Requests_RequestModel::save($requests); @@ -260,4 +209,44 @@ class Requests_ApprovalActionVoteModel extends Requests_ApprovalActionQueueModel { return $this->_data['requiredVotes']; } + + public function tallyVotes($votes) + { + if (!Unl_Util::isArray($votes) || count($votes) == 0) { + return NULL; + } + + $voteCount = count($votes); + if ($voteCount < $this->getQuorum()) { + return NULL; + } + + $voteTally = array(); + foreach ($votes as $vote) { + $voteTally[$vote->getVote()]++; + } + if ($voteTally['Table'] >= $this->getVotesToTable()) { + return 'Table'; + } + + // TODO: Handle Ties + $mostVotes = 0; + $winner = ''; + foreach ($voteTally as $name => $count) { + if ($count > $mostVotes) { + $winner = $name; + $mostVotes = $count; + } + } + + if ($this->_data['requiredVotes'] == 'plurality') { + return $winner; + } else if ($this->_data['requiredVotes'] == 'majority' && ($mostVotes / $voteCount) > 0.5) { + return $winner; + } else if ($this->_data['requiredVotes'] == 'unanimity' && ($mostVotes / $voteCount) == 1.0) { + return $winner; + } else { + return NULL; + } + } } diff --git a/application/modules/requests/models/ApproverVoteModel.php b/application/modules/requests/models/ApproverVoteModel.php index c1918b0f..c230b9ba 100644 --- a/application/modules/requests/models/ApproverVoteModel.php +++ b/application/modules/requests/models/ApproverVoteModel.php @@ -38,7 +38,7 @@ class Requests_ApproverVoteModel extends Unl_Model } } - static public function findVotesForRequests($requests, $approvalAction = null) + static public function findVotesForRequests($requests, Zend_Date $timeInPeriod, Requests_ApprovalActionModel $approvalAction) { $db = Zend_Registry::get('db'); @@ -54,10 +54,13 @@ class Requests_ApproverVoteModel extends Unl_Model $select = new Zend_Db_Select($db); $select->from(array('a' => 'creqApproverVotes'), array('approverVoteId', 'request')); + $select->join(array('p' => 'creqApprovalActionsQueuePeriods'), + 'a.approvalAction = p.approvalAction AND p.startTime <= a.time AND (a.time <= p.endTime OR p.endTime IS NULL)', + array()); $select->where('a.request IN(?)', $requests->getId()); - if ($approvalAction instanceof Requests_ApprovalActionModel) { - $select->where('approvalAction = ?', $approvalAction->getId()); - } + $select->where('a.approvalAction = ?', $approvalAction->getId()); + $select->where('p.startTime < ?', $timeInPeriod->getTimestamp()); + $select->where('p.endTime >= ? OR p.endTime IS NULL', $timeInPeriod->getTimestamp()); $select->order('time'); $records = $db->query($select)->fetchAll(); @@ -79,7 +82,7 @@ class Requests_ApproverVoteModel extends Unl_Model return $requestVotes; } - static public function findUsersVotesForRequests(Auth_UserModel $user, $requests, $approvalAction = null) + static public function findUsersVotesForRequests(Auth_UserModel $user, $requests, $queuePeriodId = null) { $db = Zend_Registry::get('db'); @@ -94,10 +97,14 @@ class Requests_ApproverVoteModel extends Unl_Model $select->where('a.request = ?', $requests->getId()); } $select->where('user = ?', $user->getId()); - if ($approvalAction instanceof Requests_ApprovalActionModel) { - $select->where('approvalAction = ?', $approvalAction->getId()); - } $select->order('time'); + + if ($queuePeriodId) { + $select->join(array('p' => 'creqApprovalActionsQueuePeriods'), + 'a.approvalAction = p.approvalAction AND a.time >= p.startTime AND (a.time <= p.endTime OR p.endTime IS NULL)', + array()); + $select->where('p.approvalActionsQueuePeriodId = ?', $queuePeriodId); + } $records = $db->query($select)->fetchAll(); $requestVoteIds = array(); diff --git a/application/modules/requests/models/RequestModel.php b/application/modules/requests/models/RequestModel.php index ae78fe50..aa6109a2 100644 --- a/application/modules/requests/models/RequestModel.php +++ b/application/modules/requests/models/RequestModel.php @@ -724,8 +724,13 @@ class Requests_RequestModel extends Unl_Model } $sql = $db->quoteInto('DELETE FROM creqRequestFiles WHERE requestFileId IN (?)', $requestFileIds); $db->query($sql); - $sql = $db->quoteInto('DELETE FROM creqFiles WHERE fileId IN (?)', $fileIds); - $db->query($sql); + try { + $sql = $db->quoteInto('DELETE FROM creqFiles WHERE fileId IN (?)', $fileIds); + $db->query($sql); + } catch (Zend_Db_Statement_Exception $e) { + // If the file is used by multiple requsets, an integrity exception will be thrown. + // We should just ignore it since it turns out we didn't want to delete this file anyway. + } } static protected function _saveFileToDisk($data) diff --git a/application/modules/requests/views/scripts/approval-body-admin/edit-role.phtml b/application/modules/requests/views/scripts/approval-body-admin/edit-role.phtml index 723f7216..18a23e2d 100644 --- a/application/modules/requests/views/scripts/approval-body-admin/edit-role.phtml +++ b/application/modules/requests/views/scripts/approval-body-admin/edit-role.phtml @@ -28,7 +28,7 @@ </label> <label> - Description:<br /> + Notice:<br /> <?php echo $this->formTextarea('notice', $this->approvalRole->getNotice(), array('class' => 'mceEditor')); ?><br /> </label> @@ -41,4 +41,4 @@ ?> </form> - \ No newline at end of file + diff --git a/application/modules/requests/views/scripts/queue-manager/view.phtml b/application/modules/requests/views/scripts/queue-manager/view.phtml index aa45df69..2413d3ba 100644 --- a/application/modules/requests/views/scripts/queue-manager/view.phtml +++ b/application/modules/requests/views/scripts/queue-manager/view.phtml @@ -1,8 +1,16 @@ <?php $this->layout()->breadcrumbs = array('Queue Manager: ' . $this->queue->getName()); ?> +<?php $this->headScript()->appendFile($this->baseUrl() . '/javascript/requests/queue-manager.js'); ?> +<script type="text/javascript"> +queueManager.queueId = <?php echo $this->queue->getId(); ?> +</script> + +Select period that ended on <?php echo $this->formSelect('period', $this->currentPeriod, NULL, $this->periods); ?> <h3>Requests:</h3> -<ul> -<?php foreach ($this->requests as $request) { ?> - <li><a href="<?php echo $this->baseUrl(); ?>/requests/view/index/id/<?php echo $request->getId(); ?>"><?php echo $request->getId(); ?></a></li> -<?php } ?> -</ul> +<?php +foreach ($this->moduleRequests as $module => $requests) { + echo $this->partial('queue-manager/request-table.phtml', $module, array('requests' => $requests, + 'action' => $this->queue, + 'requestUserVotes' => $this->requestUserVotes, + 'users' => $this->users)); +} diff --git a/application/modules/ucc/controllers/ReportsController.php b/application/modules/ucc/controllers/ReportsController.php index 217e2e56..6f2f967b 100644 --- a/application/modules/ucc/controllers/ReportsController.php +++ b/application/modules/ucc/controllers/ReportsController.php @@ -110,7 +110,7 @@ class Ucc_ReportsController extends App_Controller_Action $currentCourses = Courses_CourseModel::findLatestOfRequest($requests); $originalCourses = Courses_CourseModel::findParentOfRequest($requests); - $requestVotes = Requests_ApproverVoteModel::findVotesForRequests($requests, $approvalAction); + $requestVotes = Requests_ApproverVoteModel::findVotesForRequests($requests, $startDate, $approvalAction); $data = new Unl_Model_Collection('Unl_Model_Array'); foreach ($requests as $request) { @@ -141,7 +141,7 @@ class Ucc_ReportsController extends App_Controller_Action $difference = $currentCourse->getDifferenceSummary($originalCourse, $request); if ($approvalAction instanceof Requests_ApprovalActionVoteModel) { - $voteResult = $this->_tallyVotes($votes, $startDate, $endDate, $approvalAction->getVotesToTable()); + $voteResult = $approvalAction->tallyVotes($votes); } $data[] = new Unl_Model_Array(array( @@ -154,7 +154,7 @@ class Ucc_ReportsController extends App_Controller_Action 'esAreas' => $originalCourse->getEssentialStudiesAreas(), 'crosslist' => $originalCourse->getCrosslistingsText(), 'course' => $originalCourse->getCourseId(), - 'voteResult' => $voteResult, + 'voteResult' => ($voteResult ? $voteResult : 'Resubmit'), 'type' => $request->getTypeDescription() )); } @@ -189,7 +189,7 @@ class Ucc_ReportsController extends App_Controller_Action $this->view->currentCourses = Courses_CourseModel::findLatestOfRequest($requests); $this->view->originalCourses = Courses_CourseModel::findParentOfRequest($requests); - $requestVotes = Requests_ApproverVoteModel::findVotesForRequests($requests, $approvalAction); + $requestVotes = Requests_ApproverVoteModel::findVotesForRequests($requests, $startDate, $approvalAction); $requestVoteTally = array(); $requestVoteResults = array(); foreach ($requestVotes as $requestId => $votes) { @@ -203,7 +203,7 @@ class Ucc_ReportsController extends App_Controller_Action $requestVoteTally[$requestId][$vote->getVote()]++; } - $requestVoteResults[$requestId] = $this->_tallyVotes($votes, $startDate, $endDate, $approvalAction->getVotesToTable()); + $requestVoteResults[$requestId] = $approvalAction->tallyVotes($votes); } $this->view->requestVoteTally = $requestVoteTally; $this->view->requestVoteResults = $requestVoteResults; @@ -215,7 +215,7 @@ class Ucc_ReportsController extends App_Controller_Action $approvalAction = Requests_ApprovalActionModel::find(313); $requests = Requests_ApprovalHistoryModel::findRequestsWithinTimeRangeAndApprovalAction($startDate, $endDate, $approvalAction); - $requestVotes = Requests_ApproverVoteModel::findVotesForRequests($requests, $approvalAction); + $requestVotes = Requests_ApproverVoteModel::findVotesForRequests($requests, $startDate, $approvalAction); $requestVoteTally = array(); $requestVoteResults = array(); foreach ($requestVotes as $requestId => $votes) { @@ -229,7 +229,7 @@ class Ucc_ReportsController extends App_Controller_Action $requestVoteTally[$requestId][$vote->getVote()]++; } - $requestVoteResults[$requestId] = $this->_tallyVotes($votes, $startDate, $endDate, $approvalAction->getVotesToTable()); + $requestVoteResults[$requestId] = $approvalAction->tallyVotes($votes); } $facilitatorApprovalActionId = 325; @@ -249,7 +249,7 @@ class Ucc_ReportsController extends App_Controller_Action if (in_array($aHistory->getDecision(), $this->_internalDecisions)) { continue; } - $requestVoteResults[$requestId] = $aHistory->getDecision(); + $requestVoteResults[$requestId] = $aHistory->getDecision() . ' (via Facilitator)'; } } @@ -270,30 +270,4 @@ class Ucc_ReportsController extends App_Controller_Action $this->render('monthly-extended'); } - protected function _tallyVotes($votes, $startDate, $endDate, $votesToTable) - { - $voteTally = array(); - $voteResult = ''; - $voteCount = 0; - foreach ($votes as $vote) { - if ($vote->getTime()->isLater($endDate)) { - continue; - } - if ($vote->getTime()->isEarlier($startDate)) { - continue; - } - $voteTally[$vote->getVote()]++; - $voteCount++; - if ($voteTally[$vote->getVote()] == max($voteTally)) { - $voteResult = $vote->getVote(); - } - } - - if ($voteCount < 7 || $voteTally['Table'] >= $votesToTable) { - $voteResult = 'Table'; - } - - return $voteResult; - } - } diff --git a/document_root/css/courses/queue-manager/request-table.css b/document_root/css/courses/queue-manager/request-table.css new file mode 100644 index 00000000..f892601b --- /dev/null +++ b/document_root/css/courses/queue-manager/request-table.css @@ -0,0 +1,4 @@ +@CHARSET "UTF-8"; + +#courseRequestTable {overflow: scroll;} +#courseRequestTable td {text-align: center; white-space:nowrap;} \ No newline at end of file diff --git a/document_root/javascript/requests/queue-manager.js b/document_root/javascript/requests/queue-manager.js new file mode 100644 index 00000000..cdd2fcc5 --- /dev/null +++ b/document_root/javascript/requests/queue-manager.js @@ -0,0 +1,10 @@ +var queueManager = {}; + +$().ready(function() { + $('#period').change(queueManager.handleChangePeriod); +}); + +queueManager.handleChangePeriod = function() +{ + document.location = baseUrl + '/requests/queue-manager/view/id/' + queueManager.queueId + '/period/' + this.value; +} diff --git a/document_root/schema/courses.xsd b/document_root/schema/courses.xsd index f11207cf..6ce09d81 100644 --- a/document_root/schema/courses.xsd +++ b/document_root/schema/courses.xsd @@ -110,7 +110,7 @@ <xs:element name="subject" type="xs:string" /> <xs:element name="courseNumber" type="xs:positiveInteger" /> <xs:element name="courseLetter" type="xs:string" minOccurs="0" /> - <xs:element name="courseGroup" type="xs:string" minOccurs="0" /> + <xs:element name="courseGroup" type="xs:string" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> <xs:attribute name="type" type="courseCodeType" /> </xs:complexType> diff --git a/library/App/Controller/Action.php b/library/App/Controller/Action.php index 19706f2c..492dd8d9 100644 --- a/library/App/Controller/Action.php +++ b/library/App/Controller/Action.php @@ -18,39 +18,13 @@ class App_Controller_Action extends Unl_Controller_Action protected function _transparentCasLogin() { - $session = new Zend_Session_Namespace(__CLASS__); - // The auth module is doing its thing (probably an active login or logout). Let it be. if (get_class($this) == 'Auth_IndexController') { return; } - // Only passively check for a login once per hour (per user) - if ($session->lastCasCheck > time() - 60*60) { - return; - } - - $session->lastCasCheck = time(); - - - // Do a passive authentication check - $redirectUri = $_SERVER['REQUEST_URI']; - $baseUrl = Zend_Controller_Front::getInstance()->getBaseUrl(); - $redirectUri = substr($redirectUri, strlen($baseUrl)); - - $authSession = new Zend_Session_Namespace('Auth_IndexController'); - $authSession->referer = $redirectUri; - - - if ($_SERVER['HTTPS'] == 'on') { - $serviceUrl = 'https://'; - } else { - $serviceUrl = 'http://'; + if (array_key_exists('unl_sso', $_COOKIE) || Zend_Auth::getInstance()->hasIdentity()) { + Auth_UserModel::authenticateUser(); } - $serviceUrl .= $_SERVER['SERVER_NAME'] . Zend_Controller_Front::getInstance()->getBaseUrl() . '/auth/index/validate'; - - $casAdapter = new Unl_Auth_Adapter_Cas($serviceUrl, 'https://login.unl.edu/cas', $this->_getParam('ticket')); - $casAdapter->setGateway(); - $this->_redirect($casAdapter->getLoginUrl()); } } -- GitLab