+<?php
+/**\r
+ * @file class_erErrorReportManager.inc -- management of multiple error reports\r
+ * @author Roland Hieber (roland.hieber@wilhelm-gym.net)\r
+ * @date 18.10.2007\r
+ * \r
+ * Copyright © 2007 Roland Hieber\r
+ * \r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * copy of this software and associated documentation files (the "Software"),\r
+ * to deal in the Software without restriction, including without limitation\r
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
+ * and/or sell copies of the Software, and to permit persons to whom the\r
+ * Software is furnished to do so, subject to the following conditions:\r
+ * \r
+ * The above copyright notice and this permission notice shall be included in\r
+ * all copies or substantial portions of the Software.\r
+ * \r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
+ * THE SOFTWARE.\r
+ */
+
+require_once("mod_error-reporter/class_erErrorReport.inc");
+require_once("mod_error-reporter/class_erConfig.inc");
+require_once("mod_error-reporter/functions.inc");
+require_once("db.inc");
+require_once("user.inc");
+
+db_query("SET DATESTYLE = ISO ");
+
+/**
+ * @page errorreportmanager_constants erErrorReportManager Constants
+ * @section errorreportmanager_sorting Sorting constants
+ * - @b ER_ERM_SORT_UID: Array is sorted by unique ID
+ * - @b ER_ERM_SORT_DATE: Array is sorted by the creation date
+ * - @b ER_ERM_SORT_OWNER: Array is sorted by owner of the error report
+ * - @b ER_ERM_SORT_MACHINE: Array is sorted by the machine to which the report refers
+ * - @b ER_ERM_SORT_TEXT: Array is sorted by text / notes
+ * - @b ER_ERM_SORT_COMMENT: Array is sorted by comment
+ * - @b ER_ERM_SORT_COMMENTOWNER: Array is sorted by the account name of the person who wrote the comment
+ * - @b ER_ERM_SORT_VISIBILITY: Array is sorted by hide status
+ * @section errorreportmanager_sorting_dir Sorting direction constants
+ * - @b ER_ERM_SORT_ASC: Array is sorted in ascending order
+ * - @b ER_ERM_SORT_DESC: Array is sorted in descending order
+ */
+define("ER_ERM_SORT_UID", 0); /*< sort by unique ID */
+define("ER_ERM_SORT_DATE", 1); /*< sort by date */
+define("ER_ERM_SORT_OWNER", 2); /*< sort by owner */
+define("ER_ERM_SORT_MACHINE", 3); /*< sort by machine to which the report refers */
+define("ER_ERM_SORT_TEXT", 4); /*< sort by text*/
+define("ER_ERM_SORT_COMMENT", 5); /*< sort by comment */
+define("ER_ERM_SORT_COMMENTOWNER", 6); /*< sort by account name of the person who wrote the comment */
+define("ER_ERM_SORT_VISIBILITY", 6); /*< sort by visibility */
+
+define("ER_ERM_SORT_ASC", 0); /*< sort ascending */
+define("ER_ERM_SORT_DESC", 1); /*< sort descending */
+
+/**
+ * Management of error reports
+ *
+ * This class allows a comprehensive management of error reports.
+ *
+ * @par Error reports management
+ * To add an error reports, simply create an instance of this class and call writeErrorReport()
+ * with a erErrorReport object as the only parameter. If the $nUid member of the erErrorReport
+ * object is <tt>null</tt>, writeErrorReport() will use the next ID which is not used in the
+ * table.
+ *
+ * @par
+ * An error report that has been written to the database can be changed using
+ * writeErrorReport(), setting the $nUid member of the erErrorReport parameter to the UID of the
+ * error report to be changed.
+ *
+ * @par
+ * To change the visibility of an error report to @e hidden, call setErrorReportDoneFlag() with
+ * the UID of the error report and set the second parameter to <tt>false</tt>.
+ *
+ * @par
+ * To delete an error report from the database, call deleteErrorReport() with the UID of the
+ * error report you want to delete.
+ *
+ * @par
+ * Error reports can be retrieved by their UID (getErrorReportByID()), by creation date
+ * (getErrorReportsByDate()), by owner (getErrorReportsByOwner()), by machine to which the
+ * report refers (getErrorReportsByMachine()) and by the person who wrote the comment
+ * (getErrorReportsByCommentOwner()). All error reports in the database can be retrieved using
+ * getErrorReports(). All of these functions return a object of type erErrorReport or an array
+ * of erErrorReport objects.
+ *
+ * @par Example
+ * The following example creates a new error report “This doesn’t work”, written by the user
+ * “testuser” on February 5, 2007, which refers to the machine “Client-26” and is not visible for
+ * non-admin users. Then it adds a nice comment, makes the error report visible and writes it to
+ * the database.
+ * @code
+ * <?php
+ * require_once("class_erErrorReportManager.inc");
+ * $obj = new erErrorReportManager;
+ * $em = new erErrorReport(strtotime("2007-02-05"), "testuser", "Client-26",
+ * "This doesn’t work", false);
+ * $em->setComment("We know that already", "admin");
+ *
+ * $nNewID = $obj->writeErrorReport($em); // $em->nUid is null, so writeErrorReport()
+ * // calculates the UID by itself
+ * ?>
+ * @endcode
+ */
+
+class erErrorReportManager {
+
+
+ /**
+ * (object of type erConfig) pointer to the configuration class
+ */
+ protected $objcfg;
+
+ /**
+ * Constructor
+ * @param $objcfg (object of type erConfig) Pointer to the configuration class for retrieving the
+ * configuration data
+ * @return erErrorReportManager
+ */
+ public function __construct(&$objcfg) {
+ $this->objcfg = &$objcfg;
+ }
+
+ //////////////////////////////////////////// QUERYING ///////////////////////////////////////////
+
+ /**
+ * @name Quering
+ * @{ */
+
+ /**
+ * Get all error reports in the database.
+ * If this function fails, it returns <tt>null</tt>. Call getLastError() to get more information.
+ * @param $arcSort (array of constants) Defines the sorting of the returned array.
+ * See the documentation of the $arcSort parameter of buildOrderByClause() for more information.
+ * @return array of objects of type erErrorReport
+ */
+ public function getErrorReports($arcSort = array(ER_ERM_SORT_UID => ER_ERM_SORT_ASC)) {
+ return $this->readFromSQL("", $arcSort);
+ }
+
+ /**
+ * Get an error report by its unique ID in database.
+ * If this function fails, it returns <tt>null</tt>.
+ * @param $nID (int) ID of the error report
+ * @return erErrorReport
+ */
+ public function getErrorReportByID($nID) {
+ $arReturn = $this->readFromSQL("er_uid = ".qdb(intval($nID)));
+ if(is_array($arReturn) and count($arReturn) > 0) {
+ return $arReturn[0]; // return as scalar
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get all error reports which have been created on the specified date.
+ * If this function fails, it returns <tt>null</tt>. Call getLastError() to get more information.
+ * @param $tsDate (timestamp) Date
+ * @param $arcSort (array of constants) Defines the sorting of the returned array.
+ * See the documentation of the $arcSort parameter of buildOrderByClause() for more information.
+ * @return array of objects of type erErrorReport
+ */
+ public function getErrorReportsByDate($tsDate, $arcSort = array(ER_ERM_SORT_UID => ER_ERM_SORT_ASC)) {
+ return $this->readFromSQL("er_date = ".qdb(date("Y\-m\-d", $tsDate)), $arcSort);
+ }
+
+ /**
+ * Get all error reports which have been created by the specified user.
+ * If this function fails, it returns <tt>null</tt>. Call getLastError() to get more information.
+ * @param $strAct (string) Account name
+ * @param $arcSort (array of constants) Defines the sorting of the returned array.
+ * See the documentation of the $arcSort parameter of buildOrderByClause() for more information.
+ * @return array of objects of type erErrorReport
+ */
+ public function getErrorReportsByOwner($strAct, $arcSort = array(ER_ERM_SORT_UID => ER_ERM_SORT_ASC)) {
+ return $this->readFromSQL("er_act = ".qdb($strAct), $arcSort);
+ }
+
+ /**
+ * Get all error reports which are related to a specified machine.
+ * If this function fails, it returns <tt>null</tt>. Call getLastError() to get more information.
+ * @param $strMachine (string) Machine name
+ * @param $arcSort (array of constants) Defines the sorting of the returned array.
+ * See the documentation of the $arcSort parameter of buildOrderByClause() for more information.
+ * @return array of objects of type erErrorReport
+ */
+ public function getErrorReportsByMachine($strMachine,
+ $arcSort = array(ER_ERM_SORT_UID => ER_ERM_SORT_ASC)) {
+ return $this->readFromSQL("er_machine = ".qdb($strMachine), $arcSort);
+ }
+
+ /**
+ * Get all error reports which have been commented by the specified user.
+ * If this function fails, it returns <tt>null</tt>. Call getLastError() to get more information.
+ * @param $strAct (string) Account name
+ * @param $arcSort (array of constants) Defines the sorting of the returned array.
+ * See the documentation of the $arcSort parameter of buildOrderByClause() for more information.
+ * @return array of objects of type erErrorReport
+ */
+ public function getErrorReportsByCommentOwner($strAct,
+ $arcSort = array(ER_ERM_SORT_UID => ER_ERM_SORT_ASC)) {
+ return $this->readFromSQL("er_commentact = ".qdb($strAct), $arcSort);
+ }
+
+ /*@}*/
+
+ /**
+ * Get datasets from the SQL tables.
+ * This function should not be called directly. Use the getBy* functions instead.
+ * If this function fails, it returns <tt>null</tt>. Call getLastError() to get more information.
+ * @internal
+ * @param $strWhere (string) Parameters for the SQL WHERE clause
+ * @param $arcSort (array of constants) Defines the sorting of the returned array.
+ * See the documentation of the $arcSort parameter of buildOrderByClause() for more information.
+ * @return array of objects of type erErrorReport
+ */
+ protected function readFromSQL($strWhere = "", $arcSort = array(ER_ERM_SORT_UID => ER_ERM_SORT_ASC)) {
+ $arReturn = array();
+
+ // only allow visible reports for non-admins, but all reports for admins and owners
+ if($this->objcfg->userIsAdmin()) {
+ $strWhereClause = (trim($strWhere) == "") ? "" : "WHERE $strWhere";
+ } else {
+ $strWhereClause = "WHERE ".((trim($strWhere) == "") ? "" : "$strWhere AND ").
+ sprintf("((er_act = '%s') or (er_hidden IS NULL OR NOT er_hidden))", $_SESSION["act"]);
+ }
+
+ $strSortClause = $this->buildOrderByClause($arcSort);
+
+ // fetch the error reports
+ $hQuery = db_query("SELECT * FROM mod_errorreporter $strWhereClause $strSortClause;");
+ if(!is_resource($hQuery)) {
+ setLastError(ER_ERROR_SQL);
+ return null;
+ }
+ while($arResult = pg_fetch_array($hQuery)) {
+ $er = new erErrorReport(strtotime($arResult["er_date"]), $arResult["er_act"],
+ $arResult["er_machine"], $arResult["er_text"], $arResult["er_hidden"] == "t");
+ $er->setUid($arResult["er_uid"]);
+ $er->setComment($arResult["er_comment"], $arResult["er_commentact"]);
+ $arReturn[] = $er;
+ }
+ return $arReturn;
+ }
+
+ /**
+ * Build a ORDER BY clause from an array.
+ * This helper function takes an array of sorting constants as input and returns an ORDER BY
+ * clause. The values in the clause are in the same order as the constants in the array.
+ * The function in the following example returns an ORDER BY clause where the datasets are first
+ * sorted ascending by visibility, then descending by the machine name to which they refer and
+ * finally ascending by their UID:
+ * @code
+ * $strOrder = buildOrderClause(array(
+ * ER_ERM_SORT_VISIBILITY => ER_ERM_SORT_ASC,
+ * ER_ERM_SORT_MACHINE => ER_ERM_SORT_DESC,
+ * ER_ERM_SORT_UID => ER_ERM_SORT_ASC));
+ * echo $strOrder;
+ * @endcode
+ * The output is: <tt>ORDER BY er_hidden ASC, er_machine DESC, er_uid ASC</tt>
+ * @internal
+ * @param $arcSort (array of constants) The array which declares the order of the SQL rows. Use
+ * @ref errorreportmanager_sorting as keys and @ref errorreportmanager_sorting_dir as values.
+ * @return string
+ */
+ protected function buildOrderByClause($arcSort) {
+ // build the sorting clause
+ $arstrSort = array();
+ foreach($arcSort as $cSort => $cDir) {
+ switch($cSort) {
+ case ER_ERM_SORT_UID:
+ $arstrSort[] = "er_uid ".($cDir == ER_ERM_SORT_DESC ? "DESC" : "ASC"); break;
+ case ER_ERM_SORT_DATE:
+ $arstrSort[] = "er_date ".($cDir == ER_ERM_SORT_DESC ? "DESC" : "ASC"); break;
+ case ER_ERM_SORT_OWNER:
+ $arstrSort[] = "er_act ".($cDir == ER_ERM_SORT_DESC ? "DESC" : "ASC"); break;
+ case ER_ERM_SORT_MACHINE:
+ $arstrSort[] = "er_machine ".($cDir == ER_ERM_SORT_DESC ? "DESC" : "ASC"); break;
+ case ER_ERM_SORT_TEXT:
+ $arstrSort[] = "er_text ".($cDir == ER_ERM_SORT_DESC ? "DESC" : "ASC"); break;
+ case ER_ERM_SORT_COMMENT:
+ $arstrSort[] = "er_comment ".($cDir == ER_ERM_SORT_DESC ? "DESC" : "ASC"); break;
+ case ER_ERM_SORT_COMMENTOWNER:
+ $arstrSort[] = "er_commentact ".($cDir == ER_ERM_SORT_DESC ? "DESC" : "ASC"); break;
+ case ER_ERM_SORT_VISIBILITY:
+ $arstrSort[] = "er_hidden ".($cDir == ER_ERM_SORT_DESC ? "DESC" : "ASC"); break;
+ }
+ }
+ return ("ORDER BY ".join(", ", $arstrSort));
+ }
+
+ //////////////////////////////////// ERROR MESSAGE MANAGEMENT ///////////////////////////////////
+
+ /**
+ * @name Error report management
+ * @{
+ */
+
+ /**
+ * Insert or update an error report in the database.
+ * When the $nUid member of the $erErrorReport object is <tt>null</tt>, a new unique ID is
+ * assigned and the error report is written to the database. Otherwise, the corresponding
+ * record in the table is updated.
+ * @param $er (erErrorReport)
+ * @return (int) The unique ID of the inserted or updated record.
+ * @throws Exception
+ */
+ public function writeErrorReport(erErrorReport $er) {
+ if(!$this->objcfg->userHasAccess() and (!$this->userIsOwner($er->nUid) or
+ ($er->getUid() == null and !($this->objcfg->userIsAdmin())))) {
+ throw new Exception(ER_ERROR_ACCESS_DENIED);
+ }
+
+ $strWhere = null;
+ $strLog = "";
+
+ // Update or insert?
+ $arPut = array();
+ if($er->getUid() == null) {
+ // er_uid is now serial
+ /*$hQuery = db_query("SELECT MAX(er_uid) AS id FROM mod_errorreporter;");
+ if(!is_resource($hQuery)) {
+ setLastError(ER_ERROR_SQL);
+ return -1;
+ }
+ $arResult = pg_fetch_array($hQuery);
+ $er->setUid(intval($arResult["id"]) + 1);*/
+ $strLog = sprintf("Fehlermeldung für Rechner „%s“ eingetragen.",
+ $er->getMachine());
+ } else {
+ $strWhere = "er_uid = ".qdb(intval($er->getUid()));
+ $oOldReport = $this->getErrorReportByID($er->getUid());
+ $strLog = sprintf("Fehlermeldung geändert, Rechner war „%s“, Text war „%s“. ".
+ "Neuer Rechner: „%s“, neuer Text: „%s“, Kommentar: %s",
+ $oOldReport->getMachine(), $oOldReport->getText(), $er->getMachine(),
+ $er->getText(), (strlen($er->getComment()) > 0) ? "„".$er->getComment()."“" : "(leer)");
+ }
+ $arPut["er_date"] = date("Y\-m\-d\ G\:i\:s", $er->getDate());
+ $arPut["er_act"] = $er->getOwner();
+ $arPut["er_machine"] = $er->getMachine();
+ $arPut["er_text"] = $er->getText();
+ $arPut["er_comment"] = $er->getComment();
+ $arPut["er_commentact"] = $er->getCommentOwner();
+ $arPut["er_hidden"] = $er->isHidden() ? "true" : "false";
+ db_store("mod_errorreporter", $arPut, $strWhere);
+
+ erInsertLog($strLog);
+
+ // send notification mail, but only if the message is new
+ if($this->objcfg->isMailNotify() and $er->getUid() == null) {
+ $strMailText = sprintf("<html><body>\nEin Benutzer hat eine Fehlermeldung mit dem ".
+ "Fehlermeldungs-Assistenten abgeschickt. Nachfolgend finden sich Angaben über den ".
+ "Fehler.\n<table>\n<tr><td>Fehler gemeldet von:</td><td>%s</td></tr>\n".
+ "<tr><td>Datum:</td><td>%s</td></tr>\n<tr><td>Betroffener Rechner:</td><td>%s</td></tr>\n".
+ "<tr><td colspan='2'>%s</td></tr>\n</table>\n<hr />\nDiese Mail wurde automatisch ".
+ "generiert.\n</body></html>", q(erGetRealUserName($er->getOwner())),
+ q(date("d\.m\.Y\ G\:i\:s", $er->getDate())), q($er->getMachine()), q($er->getText()));
+ $strMailSubject = sprintf("%s hat einen Fehler im System gemeldet",
+ q(erGetRealUserName($er->getOwner())));
+ $strMailHeader = sprintf("From: %s <%s>\nContent-Type: text/html; charset=utf-8",
+ q(erGetRealUserName($er->getOwner())), user_mail_addr($er->getOwner()));
+ mail($this->objcfg->getMailNotifyAddr(), $strMailSubject, $strMailText, $strMailHeader);
+ }
+
+ return $er->getUid();
+ }
+
+ /**
+ * Delete an error report from the database.
+ * @param $nErrorReportID (int) Unique ID of the error report to delete or -1 if an error
+ * occured. In this case, call getLastError() to get more information.
+ */
+ public function deleteErrorReport($nErrorReportID) {
+ if(!($this->objcfg->userIsAdmin() or $this->userIsOwner($nErrorReportID))) {
+ setLastError(ER_ERROR_ACCESS_DENIED);
+ return -1;
+ }
+
+ $oOldReport = $this->getErrorReportByID($nErrorReportID);
+ db_query(sprintf("DELETE FROM mod_errorreporter WHERE er_uid = '%d';", intval($nErrorReportID)));
+ erInsertLog(sprintf("Fehlermeldung gelöscht, Rechner war „%s“, Text war „%s“",
+ $oOldReport->getMachine(), $oOldReport->getText()));
+ }
+
+ /**
+ * Determine if the current user is the owner of a specified error report.
+ * If this function fails, call getLastError() to get more information.
+ * @param $nID (int) Unique ID of the error report
+ * @return bool
+ */
+ public function userIsOwner($nID) {
+ if(!$_SESSION["act"]) {
+ return false; // user is not logged in
+ } else {
+ $hQuery = db_query(sprintf("SELECT er_act FROM mod_errorreporter WHERE er_uid = %d;", intval($nID)));
+ if(!is_resource($hQuery)) {
+ setLastError(ER_ERROR_SQL);
+ return false;
+ }
+ $arResult = pg_fetch_array($hQuery);
+ return ($arResult["er_act"] == $_SESSION["act"]);
+ }
+ }
+}
+?>
\ No newline at end of file