/**
  * Assigns the selected director to the submission.
  */
 function assignDirector($args, $request)
 {
     $this->validate($request);
     Locale::requireComponents(array(LOCALE_COMPONENT_PKP_MANAGER));
     // manager.people.noneEnrolled
     $schedConf =& $request->getSchedConf();
     $paperId = $request->getUserVar('paperId');
     $directorId = $request->getUserVar('directorId');
     $roleDao =& DAORegistry::getDAO('RoleDAO');
     $isDirector = $roleDao->userHasRole($schedConf->getConferenceId(), $schedConf->getId(), $directorId, ROLE_ID_DIRECTOR) || $roleDao->userHasRole($schedConf->getConferenceId(), 0, $directorId, ROLE_ID_DIRECTOR);
     $isTrackDirector = $roleDao->userHasRole($schedConf->getConferenceId(), $schedConf->getId(), $directorId, ROLE_ID_TRACK_DIRECTOR) || $roleDao->userHasRole($schedConf->getConferenceId(), 0, $directorId, ROLE_ID_TRACK_DIRECTOR);
     if (isset($directorId) && $directorId != null && ($isDirector || $isTrackDirector)) {
         // A valid track director has already been chosen;
         // either prompt with a modifiable email or, if this
         // has been done, send the email and store the director
         // selection.
         $this->setupTemplate($request, DIRECTOR_TRACK_SUBMISSIONS, $paperId, 'summary');
         // FIXME: Prompt for due date.
         if (DirectorAction::assignDirector($paperId, $directorId, $isDirector, $request->getUserVar('send'))) {
             $request->redirect(null, null, null, 'submission', $paperId);
         }
     } else {
         // Allow the user to choose a track director or director.
         $this->setupTemplate($request, DIRECTOR_TRACK_SUBMISSIONS, $paperId, 'summary');
         $searchType = null;
         $searchMatch = null;
         $search = $request->getUserVar('search');
         $searchInitial = $request->getUserVar('searchInitial');
         if (!empty($search)) {
             $searchType = $request->getUserVar('searchField');
             $searchMatch = $request->getUserVar('searchMatch');
         } elseif (!empty($searchInitial)) {
             $searchInitial = String::strtoupper($searchInitial);
             $searchType = USER_FIELD_INITIAL;
             $search = $searchInitial;
         }
         $forDirectors = isset($args[0]) && $args[0] === 'director';
         $rangeInfo =& Handler::getRangeInfo('directors', array($forDirectors, (string) $searchType, (string) $search, (string) $searchMatch));
         $directorSubmissionDao =& DAORegistry::getDAO('DirectorSubmissionDAO');
         if ($forDirectors) {
             $roleName = 'user.role.director';
             $rolePath = 'director';
             while (true) {
                 $directors =& $directorSubmissionDao->getUsersNotAssignedToPaper($schedConf->getId(), $paperId, RoleDAO::getRoleIdFromPath('director'), $searchType, $search, $searchMatch, $rangeInfo);
                 if ($directors->isInBounds()) {
                     break;
                 }
                 unset($rangeInfo);
                 $rangeInfo =& $directors->getLastPageRangeInfo();
                 unset($directors);
             }
         } else {
             $roleName = 'user.role.trackDirector';
             $rolePath = 'trackDirector';
             while (true) {
                 $directors =& $directorSubmissionDao->getUsersNotAssignedToPaper($schedConf->getId(), $paperId, RoleDAO::getRoleIdFromPath('trackDirector'), $searchType, $search, $searchMatch, $rangeInfo);
                 if ($directors->isInBounds()) {
                     break;
                 }
                 unset($rangeInfo);
                 $rangeInfo =& $directors->getLastPageRangeInfo();
                 unset($directors);
             }
         }
         $templateMgr =& TemplateManager::getManager();
         $templateMgr->assign_by_ref('directors', $directors);
         $templateMgr->assign('roleName', $roleName);
         $templateMgr->assign('rolePath', $rolePath);
         $templateMgr->assign('paperId', $paperId);
         $trackDao =& DAORegistry::getDAO('TrackDAO');
         $trackDirectorTracks =& $trackDao->getDirectorTracks($schedConf->getId());
         $editAssignmentDao =& DAORegistry::getDAO('EditAssignmentDAO');
         $directorStatistics = $editAssignmentDao->getDirectorStatistics($schedConf->getId());
         $templateMgr->assign_by_ref('directorTracks', $trackDirectorTracks);
         $templateMgr->assign('directorStatistics', $directorStatistics);
         $templateMgr->assign('searchField', $searchType);
         $templateMgr->assign('searchMatch', $searchMatch);
         $templateMgr->assign('search', $search);
         $templateMgr->assign('searchInitial', $request->getUserVar('searchInitial'));
         $templateMgr->assign('fieldOptions', array(USER_FIELD_FIRSTNAME => 'user.firstName', USER_FIELD_LASTNAME => 'user.lastName', USER_FIELD_USERNAME => 'user.username', USER_FIELD_EMAIL => 'user.email'));
         $templateMgr->assign('alphaList', explode(' ', Locale::translate('common.alphaList')));
         $templateMgr->assign('helpTopicId', 'editorial.directorsRole.summaryPage.submissionManagement');
         $templateMgr->display('director/selectTrackDirector.tpl');
     }
 }
 /**
  * Retrieve a list of all reviewers not assigned to the specified paper.
  * @param $schedConfId int
  * @param $paperId int
  * @return array matching Users
  */
 function &getReviewersNotAssignedToPaper($schedConfId, $paperId)
 {
     $users = array();
     $result =& $this->retrieve('SELECT u.* FROM users u NATURAL JOIN roles r LEFT JOIN review_assignments a ON (a.reviewer_id = u.user_id AND a.paper_id = ?) WHERE r.sched_conf_id = ? AND r.role_id = ? AND a.paper_id IS NULL ORDER BY last_name, first_name', array($paperId, $schedConfId, RoleDAO::getRoleIdFromPath('reviewer')));
     while (!$result->EOF) {
         $users[] =& $this->userDao->_returnUserFromRowWithData($result->GetRowAssoc(false));
         $result->moveNext();
     }
     $result->Close();
     unset($result);
     return $users;
 }
 function display(&$args)
 {
     $templateMgr =& TemplateManager::getManager();
     parent::display($args);
     $templateMgr->assign('roleOptions', array('' => 'manager.people.doNotEnroll', 'manager' => 'user.role.manager', 'director' => 'user.role.director', 'trackDirector' => 'user.role.trackDirector', 'reviewer' => 'user.role.reviewer', 'author' => 'user.role.author', 'reader' => 'user.role.reader'));
     $roleDao =& DAORegistry::getDAO('RoleDAO');
     $schedConf =& Request::getSchedConf();
     switch (array_shift($args)) {
         case 'confirm':
             $this->import('UserXMLParser');
             $templateMgr->assign('helpTopicId', 'conference.currentConference.importExport');
             $sendNotify = (bool) Request::getUserVar('sendNotify');
             $continueOnError = (bool) Request::getUserVar('continueOnError');
             import('file.FileManager');
             if (($userFile = FileManager::getUploadedFilePath('userFile')) !== false) {
                 // Import the uploaded file
                 $parser = new UserXMLParser($schedConf->getConferenceId(), $schedConf->getId());
                 $users =& $parser->parseData($userFile);
                 $i = 0;
                 $usersRoles = array();
                 foreach ($users as $user) {
                     $usersRoles[$i] = array();
                     foreach ($user->getRoles() as $role) {
                         array_push($usersRoles[$i], $role->getRoleName());
                     }
                     $i++;
                 }
                 $templateMgr->assign_by_ref('users', $users);
                 $templateMgr->assign_by_ref('usersRoles', $usersRoles);
                 $templateMgr->assign('sendNotify', $sendNotify);
                 $templateMgr->assign('continueOnError', $continueOnError);
                 $templateMgr->assign('errors', $parser->errors);
                 // Show confirmation form
                 $templateMgr->display($this->getTemplatePath() . 'importUsersConfirm.tpl');
             }
             break;
         case 'import':
             $this->import('UserXMLParser');
             $userKeys = Request::getUserVar('userKeys');
             if (!is_array($userKeys)) {
                 $userKeys = array();
             }
             $sendNotify = (bool) Request::getUserVar('sendNotify');
             $continueOnError = (bool) Request::getUserVar('continueOnError');
             $users = array();
             foreach ($userKeys as $i) {
                 $newUser = new ImportedUser();
                 $newUser->setFirstName(Request::getUserVar($i . '_firstName'));
                 $newUser->setMiddleName(Request::getUserVar($i . '_middleName'));
                 $newUser->setLastName(Request::getUserVar($i . '_lastName'));
                 $newUser->setUsername(Request::getUserVar($i . '_username'));
                 $newUser->setEmail(Request::getUserVar($i . '_email'));
                 $locales = array();
                 if (Request::getUserVar($i . '_locales') != null || is_array(Request::getUserVar($i . '_locales'))) {
                     foreach (Request::getUserVar($i . '_locales') as $locale) {
                         array_push($locales, $locale);
                     }
                 }
                 $newUser->setLocales($locales);
                 $newUser->setSignature(Request::getUserVar($i . '_signature'), null);
                 $newUser->setBiography(Request::getUserVar($i . '_biography'), null);
                 $newUser->setInterests(Request::getUserVar($i . '_interests'), null);
                 $newUser->setCountry(Request::getUserVar($i . '_country'));
                 $newUser->setMailingAddress(Request::getUserVar($i . '_mailingAddress'));
                 $newUser->setFax(Request::getUserVar($i . '_fax'));
                 $newUser->setPhone(Request::getUserVar($i . '_phone'));
                 $newUser->setUrl(Request::getUserVar($i . '_url'));
                 $newUser->setAffiliation(Request::getUserVar($i . '_affiliation'));
                 $newUser->setGender(Request::getUserVar($i . '_gender'));
                 $newUser->setInitials(Request::getUserVar($i . '_initials'));
                 $newUser->setSalutation(Request::getUserVar($i . '_salutation'));
                 $newUser->setPassword(Request::getUserVar($i . '_password'));
                 $newUser->setMustChangePassword(Request::getUserVar($i . '_mustChangePassword'));
                 $newUser->setUnencryptedPassword(Request::getUserVar($i . '_unencryptedPassword'));
                 $newUserRoles = Request::getUserVar($i . '_roles');
                 if (is_array($newUserRoles) && count($newUserRoles) > 0) {
                     foreach ($newUserRoles as $newUserRole) {
                         if ($newUserRole != '') {
                             $role = new Role();
                             $role->setRoleId(RoleDAO::getRoleIdFromPath($newUserRole));
                             $newUser->AddRole($role);
                         }
                     }
                 }
                 array_push($users, $newUser);
             }
             $parser = new UserXMLParser($schedConf->getConferenceId(), $schedConf->getId());
             $parser->setUsersToImport($users);
             if (!$parser->importUsers($sendNotify, $continueOnError)) {
                 // Failures occurred
                 $templateMgr->assign('isError', true);
                 $templateMgr->assign('errors', $parser->getErrors());
             }
             $templateMgr->assign('importedUsers', $parser->getImportedUsers());
             $templateMgr->display($this->getTemplatePath() . 'importUsersResults.tpl');
             break;
         case 'exportAll':
             $this->import('UserExportDom');
             $users =& $roleDao->getUsersBySchedConfId($schedConf->getId());
             $users =& $users->toArray();
             $doc =& UserExportDom::exportUsers($schedConf, $users);
             header("Content-Type: application/xml");
             header("Cache-Control: private");
             header("Content-Disposition: attachment; filename=\"users.xml\"");
             echo XMLCustomWriter::getXML($doc);
             break;
         case 'exportByRole':
             $this->import('UserExportDom');
             $users = array();
             $rolePaths = array();
             foreach (Request::getUserVar('roles') as $rolePath) {
                 $roleId = $roleDao->getRoleIdFromPath($rolePath);
                 $thisRoleUsers =& $roleDao->getUsersByRoleId($roleId, $schedConf->getId());
                 foreach ($thisRoleUsers->toArray() as $user) {
                     $users[$user->getId()] = $user;
                 }
                 $rolePaths[] = $rolePath;
             }
             $users = array_values($users);
             $doc =& UserExportDom::exportUsers($schedConf, $users, $rolePaths);
             header("Content-Type: application/xml");
             header("Cache-Control: private");
             header("Content-Disposition: attachment; filename=\"users.xml\"");
             echo XMLCustomWriter::getXML($doc);
             break;
         default:
             $this->setBreadcrumbs();
             $templateMgr->display($this->getTemplatePath() . 'index.tpl');
     }
 }
Beispiel #4
0
 /**
  * Assigns the selected editor to the submission.
  */
 function assignEditor($args, $request)
 {
     $this->validate();
     AppLocale::requireComponents(LOCALE_COMPONENT_PKP_MANAGER);
     // manager.people.noneEnrolled
     $journal =& $request->getJournal();
     $articleId = $request->getUserVar('articleId');
     $editorId = $request->getUserVar('editorId');
     $roleDao =& DAORegistry::getDAO('RoleDAO');
     $isSectionEditor = $roleDao->userHasRole($journal->getId(), $editorId, ROLE_ID_SECTION_EDITOR);
     $isEditor = $roleDao->userHasRole($journal->getId(), $editorId, ROLE_ID_EDITOR);
     if (isset($editorId) && $editorId != null && ($isEditor || $isSectionEditor)) {
         // A valid section editor has already been chosen;
         // either prompt with a modifiable email or, if this
         // has been done, send the email and store the editor
         // selection.
         $this->setupTemplate(EDITOR_SECTION_SUBMISSIONS, $articleId, 'summary');
         // FIXME: Prompt for due date.
         if (EditorAction::assignEditor($articleId, $editorId, $isEditor, $request->getUserVar('send'), $request)) {
             Request::redirect(null, null, 'submission', $articleId);
         }
     } else {
         // Allow the user to choose a section editor or editor.
         $this->setupTemplate(EDITOR_SECTION_SUBMISSIONS, $articleId, 'summary');
         $searchType = null;
         $searchMatch = null;
         $search = $request->getUserVar('search');
         $searchInitial = $request->getUserVar('searchInitial');
         if (!empty($search)) {
             $searchType = $request->getUserVar('searchField');
             $searchMatch = $request->getUserVar('searchMatch');
         } elseif (!empty($searchInitial)) {
             $searchInitial = String::strtoupper($searchInitial);
             $searchType = USER_FIELD_INITIAL;
             $search = $searchInitial;
         }
         $rangeInfo =& $this->getRangeInfo('editors');
         $editorSubmissionDao =& DAORegistry::getDAO('EditorSubmissionDAO');
         if (isset($args[0]) && $args[0] === 'editor') {
             $roleName = 'user.role.editor';
             $rolePath = 'editor';
             $editors =& $editorSubmissionDao->getUsersNotAssignedToArticle($journal->getId(), $articleId, RoleDAO::getRoleIdFromPath('editor'), $searchType, $search, $searchMatch, $rangeInfo);
         } else {
             $roleName = 'user.role.sectionEditor';
             $rolePath = 'sectionEditor';
             $editors =& $editorSubmissionDao->getUsersNotAssignedToArticle($journal->getId(), $articleId, RoleDAO::getRoleIdFromPath('sectionEditor'), $searchType, $search, $searchMatch, $rangeInfo);
         }
         $templateMgr =& TemplateManager::getManager();
         $templateMgr->assign_by_ref('editors', $editors);
         $templateMgr->assign('roleName', $roleName);
         $templateMgr->assign('rolePath', $rolePath);
         $templateMgr->assign('articleId', $articleId);
         $sectionDao =& DAORegistry::getDAO('SectionDAO');
         $sectionEditorSections =& $sectionDao->getEditorSections($journal->getId());
         $editAssignmentDao =& DAORegistry::getDAO('EditAssignmentDAO');
         $editorStatistics = $editAssignmentDao->getEditorStatistics($journal->getId());
         $templateMgr->assign_by_ref('editorSections', $sectionEditorSections);
         $templateMgr->assign('editorStatistics', $editorStatistics);
         $templateMgr->assign('searchField', $searchType);
         $templateMgr->assign('searchMatch', $searchMatch);
         $templateMgr->assign('search', $search);
         $templateMgr->assign('searchInitial', Request::getUserVar('searchInitial'));
         $templateMgr->assign('fieldOptions', array(USER_FIELD_FIRSTNAME => 'user.firstName', USER_FIELD_LASTNAME => 'user.lastName', USER_FIELD_USERNAME => 'user.username', USER_FIELD_EMAIL => 'user.email'));
         $templateMgr->assign('alphaList', explode(' ', __('common.alphaList')));
         $templateMgr->assign('helpTopicId', 'editorial.editorsRole.submissionSummary.submissionManagement');
         $templateMgr->display('editor/selectSectionEditor.tpl');
     }
 }
    /**
     * Retrieve a list of all copyeditors not assigned to the specified article.
     * @param $journalId int
     * @param $articleId int
     * @return array matching Users
     */
    function &getCopyeditorsNotAssignedToArticle($journalId, $articleId, $searchType = null, $search = null, $searchMatch = null)
    {
        $users = array();
        $paramArray = array('interests', $articleId, ASSOC_TYPE_ARTICLE, 'SIGNOFF_COPYEDITING_INITIAL', $journalId, RoleDAO::getRoleIdFromPath('copyeditor'));
        $searchSql = '';
        $searchTypeMap = array(USER_FIELD_FIRSTNAME => 'u.first_name', USER_FIELD_LASTNAME => 'u.last_name', USER_FIELD_USERNAME => 'u.username', USER_FIELD_EMAIL => 'u.email', USER_FIELD_INTERESTS => 's.setting_value');
        if (isset($search) && isset($searchTypeMap[$searchType])) {
            $fieldName = $searchTypeMap[$searchType];
            switch ($searchMatch) {
                case 'is':
                    $searchSql = "AND LOWER({$fieldName}) = LOWER(?)";
                    $paramArray[] = $search;
                    break;
                case 'contains':
                    $searchSql = "AND LOWER({$fieldName}) LIKE LOWER(?)";
                    $paramArray[] = '%' . $search . '%';
                    break;
                case 'startsWith':
                    $searchSql = "AND LOWER({$fieldName}) LIKE LOWER(?)";
                    $paramArray[] = $search . '%';
                    break;
            }
        } elseif (isset($search)) {
            switch ($searchType) {
                case USER_FIELD_USERID:
                    $searchSql = 'AND user_id=?';
                    $paramArray[] = $search;
                    break;
                case USER_FIELD_INITIAL:
                    $searchSql = 'AND (LOWER(last_name) LIKE LOWER(?) OR LOWER(username) LIKE LOWER(?))';
                    $paramArray[] = $search . '%';
                    $paramArray[] = $search . '%';
                    break;
            }
        }
        $result =& $this->retrieve('SELECT	u.*
			FROM	users u
				LEFT JOIN user_settings s ON (u.user_id = s.user_id AND s.setting_name = ?)
				LEFT JOIN roles r ON (r.user_id = u.user_id)
				LEFT JOIN signoffs sci ON (sci.user_id = u.user_id AND sci.assoc_id = ? AND sci.assoc_type = ? AND sci.symbolic = ?)
			WHERE	r.journal_id = ? AND
				r.role_id = ? AND
				sci.assoc_id IS NULL
				' . $searchSql . '
			ORDER BY last_name, first_name', $paramArray);
        while (!$result->EOF) {
            $users[] =& $this->userDao->_returnUserFromRowWithData($result->GetRowAssoc(false));
            $result->moveNext();
        }
        $result->Close();
        unset($result);
        return $users;
    }
    /**
     * Retrieve a list of all copyeditors not assigned to the specified article.
     * @param $journalId int
     * @param $articleId int
     * @return array matching Users
     */
    function &getCopyeditorsNotAssignedToArticle($journalId, $articleId, $searchType = null, $search = null, $searchMatch = null)
    {
        $users = array();
        $paramArray = array('interests', $articleId, $journalId, RoleDAO::getRoleIdFromPath('copyeditor'));
        $searchSql = '';
        if (isset($search)) {
            switch ($searchType) {
                case USER_FIELD_USERID:
                    $searchSql = 'AND user_id=?';
                    $paramArray[] = $search;
                    break;
                case USER_FIELD_FIRSTNAME:
                    $searchSql = 'AND LOWER(first_name) ' . ($searchMatch == 'is' ? '=' : 'LIKE') . ' LOWER(?)';
                    $paramArray[] = $searchMatch == 'is' ? $search : '%' . $search . '%';
                    break;
                case USER_FIELD_LASTNAME:
                    $searchSql = 'AND LOWER(last_name) ' . ($searchMatch == 'is' ? '=' : 'LIKE') . ' LOWER(?)';
                    $paramArray[] = $searchMatch == 'is' ? $search : '%' . $search . '%';
                    break;
                case USER_FIELD_USERNAME:
                    $searchSql = 'AND LOWER(username) ' . ($searchMatch == 'is' ? '=' : 'LIKE') . ' LOWER(?)';
                    $paramArray[] = $searchMatch == 'is' ? $search : '%' . $search . '%';
                    break;
                case USER_FIELD_EMAIL:
                    $searchSql = 'AND LOWER(email) ' . ($searchMatch == 'is' ? '=' : 'LIKE') . ' LOWER(?)';
                    $paramArray[] = $searchMatch == 'is' ? $search : '%' . $search . '%';
                    break;
                case USER_FIELD_INTERESTS:
                    $searchSql = 'AND LOWER(setting_value) ' . ($searchMatch == 'is' ? '=' : 'LIKE') . ' LOWER(?)';
                    $paramArray[] = $searchMatch == 'is' ? $search : '%' . $search . '%';
                    break;
                case USER_FIELD_INITIAL:
                    $searchSql = 'AND (LOWER(last_name) LIKE LOWER(?) OR LOWER(username) LIKE LOWER(?))';
                    $paramArray[] = $search . '%';
                    $paramArray[] = $search . '%';
                    break;
            }
        }
        $result =& $this->retrieve('SELECT	u.*
			FROM	users u
				LEFT JOIN user_settings s ON (u.user_id = s.user_id AND s.setting_name = ?)
				LEFT JOIN roles r ON (r.user_id = u.user_id)
				LEFT JOIN copyed_assignments a ON (a.copyeditor_id = u.user_id AND a.article_id = ?)
			WHERE	r.journal_id = ? AND
				r.role_id = ? AND
				a.article_id IS NULL
				' . $searchSql . '
			ORDER BY last_name, first_name', $paramArray);
        while (!$result->EOF) {
            $users[] =& $this->userDao->_returnUserFromRowWithData($result->GetRowAssoc(false));
            $result->moveNext();
        }
        $result->Close();
        unset($result);
        return $users;
    }
    /**
     * Retrieve a list of all reviewers along with information about their current status with respect to an article's current decision.
     * @param $journalId int
     * @param $decisionId int
     * @param $extReviewer bool indicate if the kind of reviewers
     * @param $searchType int USER_FIELD_...
     * @param $search string
     * @param $searchMatch string "is" or "contains" or "startsWith"
     * @param $rangeInfo RangeInfo optional
     * @return DAOResultFactory containing matching Users
     * Last Modified: EL on Febraury 16th 2013
     * Separation of External Reviewers
     */
    function &getReviewersForArticle($journalId, $decisionId, $sectionId, $extReviewer = false, $searchType = null, $search = null, $searchMatch = null, $rangeInfo = null, $sortBy = 'reviewerName', $sortDirection = SORT_DIRECTION_ASC)
    {
        $paramArray = array($decisionId, ASSOC_TYPE_USER, 'interest', $journalId, RoleDAO::getRoleIdFromPath('reviewer'));
        if ($extReviewer == true) {
            $searchSql = ' AND er.section_id = 0 ';
        } else {
            $searchSql = ' AND er.section_id = ? ';
            $paramArray[] = $sectionId;
        }
        $searchTypeMap = array(USER_FIELD_FIRSTNAME => 'u.first_name', USER_FIELD_LASTNAME => 'u.last_name', USER_FIELD_USERNAME => 'u.username', USER_FIELD_EMAIL => 'u.email', USER_FIELD_INTERESTS => 'cves.setting_value');
        if (isset($search) && isset($searchTypeMap[$searchType])) {
            $fieldName = $searchTypeMap[$searchType];
            switch ($searchMatch) {
                case 'is':
                    $searchSql .= "AND LOWER({$fieldName}) = LOWER(?)";
                    $paramArray[] = $search;
                    break;
                case 'contains':
                    $searchSql .= "AND LOWER({$fieldName}) LIKE LOWER(?)";
                    $paramArray[] = '%' . $search . '%';
                    break;
                case 'startsWith':
                    $searchSql .= "AND LOWER({$fieldName}) LIKE LOWER(?)";
                    $paramArray[] = $search . '%';
                    break;
            }
        } elseif (isset($search)) {
            switch ($searchType) {
                case USER_FIELD_USERID:
                    $searchSql .= ' AND user_id=?';
                    $paramArray[] = $search;
                    break;
                case USER_FIELD_INITIAL:
                    $searchSql .= ' AND (LOWER(last_name) LIKE LOWER(?) OR LOWER(username) LIKE LOWER(?))';
                    $paramArray[] = $search . '%';
                    $paramArray[] = $search . '%';
                    break;
            }
        }
        $result =& $this->retrieveRange('SELECT DISTINCT
				u.user_id,
				u.last_name,
				ar.review_id,
				AVG(ra.quality) AS average_quality,
				COUNT(ac.review_id) AS completed,
				COUNT(ai.review_id) AS incomplete,
				MAX(ac.date_notified) AS latest,
				AVG(ac.date_completed-ac.date_notified) AS average
			FROM	users u
			  LEFT JOIN review_assignments ra ON (ra.reviewer_id = u.user_id)
				LEFT JOIN review_assignments ac ON (ac.reviewer_id = u.user_id AND ac.date_completed IS NOT NULL)
				LEFT JOIN review_assignments ai ON (ai.reviewer_id = u.user_id AND ai.date_completed IS NULL)
				LEFT JOIN review_assignments ar ON (ar.reviewer_id = u.user_id AND ar.cancelled = 0 AND ar.decision_id = ?)
				LEFT JOIN roles r ON (r.user_id = u.user_id)
				LEFT JOIN section_decisions sd ON (ra.decision_id = sd.section_decision_id)
				LEFT JOIN controlled_vocabs cv ON (cv.assoc_type = ? AND cv.assoc_id = u.user_id AND cv.symbolic = ?)
				LEFT JOIN controlled_vocab_entries cve ON (cve.controlled_vocab_id = cv.controlled_vocab_id)
				LEFT JOIN controlled_vocab_entry_settings cves ON (cves.controlled_vocab_entry_id = cve.controlled_vocab_entry_id)
				LEFT JOIN erc_reviewers er ON (er.user_id = u.user_id)
			WHERE u.user_id = r.user_id AND
				r.journal_id = ? AND
				r.role_id = ? ' . $searchSql . ' GROUP BY u.user_id, u.last_name, ar.review_id' . ($sortBy ? ' ORDER BY ' . $this->getSortMapping($sortBy) . ' ' . $this->getDirectionMapping($sortDirection) : ''), $paramArray, $rangeInfo);
        $returner = new DAOResultFactory($result, $this, '_returnReviewerUserFromRow');
        return $returner;
    }
    /**
     * Retrieve a list of all reviewers not assigned to the specified article.
     * @param $journalId int
     * @param $articleId int
     * @return array matching Users
     */
    function &getReviewersNotAssignedToArticle($journalId, $articleId)
    {
        $users = array();
        $result =& $this->retrieve('SELECT	u.*
			FROM	users u
				LEFT JOIN roles r ON (r.user_id = u.user_id)
				LEFT JOIN review_assignments a ON (a.reviewer_id = u.user_id AND a.article_id = ?)
			WHERE	r.journal_id = ? AND
				r.role_id = ? AND
				a.article_id IS NULL
			ORDER BY last_name, first_name', array($articleId, $journalId, RoleDAO::getRoleIdFromPath('reviewer')));
        while (!$result->EOF) {
            $users[] =& $this->userDao->_returnUserFromRowWithData($result->GetRowAssoc(false));
            $result->moveNext();
        }
        $result->Close();
        unset($result);
        return $users;
    }