diff --git a/alpine/.gitignore b/.gitignore similarity index 87% rename from alpine/.gitignore rename to .gitignore index 77d7892..994c871 100644 --- a/alpine/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +cache/ db/ etc/ files/ diff --git a/alpine/README.md b/README.md similarity index 84% rename from alpine/README.md rename to README.md index 1d1c23f..4d31b10 100644 --- a/alpine/README.md +++ b/README.md @@ -1,6 +1,7 @@ Ajouter un fichier mysql_settings.ini qui contient ``` +MARIADB_AUTO_UPGRADE=1 MYSQL_DATABASE= MYSQL_USER= MYSQL_PASSWORD='' diff --git a/alpine/docker-compose.yml b/alpine/docker-compose.yml deleted file mode 100644 index 239be86..0000000 --- a/alpine/docker-compose.yml +++ /dev/null @@ -1,29 +0,0 @@ -version: '3.5' -services: - web: - container_name: glpi-web - build: web-builder - restart: always - volumes: - - ./etc/:/etc/glpi/ - - ./files/:/var/lib/glpi/ - - ./log/:/var/log/glpi/ - env_file: - - ./mysql_settings.ini - environment: - - PHP_MEMORY_LIMIT=256M - - PHP_UPLOAD_MAX_FILESIZE=10M - - PHP_POST_MAX_SIZE=20M - - PHP_DATE_TIMEZONE=Europe/Paris - depends_on: - - db - - db: - image: mariadb - container_name: glpi-db - command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci - restart: always - env_file: - - ./mysql_settings.ini - volumes: - - ./db/:/var/lib/mysql/ diff --git a/alpine/web-builder/Dockerfile b/alpine/web-builder/Dockerfile deleted file mode 100644 index fa9dc9f..0000000 --- a/alpine/web-builder/Dockerfile +++ /dev/null @@ -1,83 +0,0 @@ -FROM alpine -MAINTAINER Benoit LORAND - -WORKDIR /root -ENV GLPI_CONFIG_DIR=/etc/glpi -ENV GLPI_VAR_DIR=/var/lib/glpi -ENV GLPI_LOG_DIR=/var/log/glpi -ENV GLPI_VERSION=9.5.5 -ENV FUSIONINVENTORY_VERSION=9.5+3.0 -ENV FIELDS_VERSION=1.12.4 -ENV DATAINJECTION_VERSION=2.9.0 - -RUN \ -apk add --no-cache \ - runit \ - php7-apache2 \ - php7 \ - mariadb-client \ - php7-pecl-apcu \ - php7-mysqli \ - php7-gd \ - php7-intl \ - php7-ldap \ - php7-xmlrpc \ - php7-xml \ - php7-exif \ - php7-zip \ - php7-bz2 \ - php7-opcache \ - php7-pear \ - php7-curl \ - php7-dom \ - php7-pdo \ - php7-json \ - php7-session \ - php7-ctype \ - php7-fileinfo \ - php7-mbstring \ - php7-simplexml \ - php7-iconv \ - php7-sodium \ - php7-imap \ - php7-pdo \ - php7-pdo_mysql \ - php7-pspell \ - php7-phar \ - patch - -COPY CAS-1.3.8.tgz /root/ -RUN pear install /root/CAS-1.3.8.tgz && \ -pear install Archive_Tar -COPY httpd.conf /etc/apache2 -COPY service/ /etc/service/ -COPY glpi_init.sh /root/glpi_init.sh -COPY glpi.cron /var/spool/cron/crontabs/apache -COPY initrc /etc/ -COPY glpi_ticket.class.php.patch /root/glpi_ticket.class.php.patch -ADD https://github.com/glpi-project/glpi/releases/download/${GLPI_VERSION}/glpi-${GLPI_VERSION}.tgz /root/glpi-${GLPI_VERSION}.tgz -ADD https://github.com/fusioninventory/fusioninventory-for-glpi/releases/download/glpi${FUSIONINVENTORY_VERSION}/fusioninventory-${FUSIONINVENTORY_VERSION}.tar.bz2 /root/fusioninventory-${FUSIONINVENTORY_VERSION}.tar.bz2 -ADD https://github.com/pluginsGLPI/fields/releases/download/${FIELDS_VERSION}/glpi-fields-${FIELDS_VERSION}.tar.bz2 /root/glpi-fields-${FIELDS_VERSION}.tar.bz2 -ADD https://github.com/pluginsGLPI/datainjection/releases/download/${DATAINJECTION_VERSION}/glpi-datainjection-${DATAINJECTION_VERSION}.tar.bz2 /root/glpi-datainjection-${DATAINJECTION_VERSION}.tar.bz2 - -RUN \ -mkdir -p /root/glpi_template/etc /root/glpi_template/files && \ -tar x -f /root/glpi-${GLPI_VERSION}.tgz && \ -cp -r /root/glpi/config/. /root/glpi_template/etc/. && \ -cp -r /root/glpi/files/. /root/glpi_template/files/. && \ -rm -r /root/glpi/config /root/glpi/files && \ -mv /root/glpi /var/www/glpi && \ -cd /var/www/glpi && \ -patch -Np0 -i /root/glpi_ticket.class.php.patch && \ -cd /var/www/glpi/plugins && \ -tar x -f /root/fusioninventory-${FUSIONINVENTORY_VERSION}.tar.bz2 && \ -cd /var/www/glpi/marketplace && \ -tar x -f /root/glpi-fields-${FIELDS_VERSION}.tar.bz2 && \ -tar x -f /root/glpi-datainjection-${DATAINJECTION_VERSION}.tar.bz2 && \ -chmod a+x /root/glpi_init.sh /etc/initrc && \ -chmod 600 /etc/crontabs/apache && \ -rm -f /var/www/html/* /root/CAS-1.3.8.tgz /root/glpi-${GLPI_VERSION}.tgz /root/fusioninventory-${FUSIONINVENTORY_VERSION}.tar.bz2 /root/glpi-fields-${FIELDS_VERSION}.tar.bz2 /root/glpi-datainjection-${DATAINJECTION_VERSION}.tar.bz2 && \ -rm -f /root/glpi_ticket.class.php.patch && \ -rm -rf /tmp/* /var/tmp/* - -ENTRYPOINT ["/etc/initrc"] diff --git a/alpine/web-builder/glpi.cron b/alpine/web-builder/glpi.cron deleted file mode 100644 index c92ce0d..0000000 --- a/alpine/web-builder/glpi.cron +++ /dev/null @@ -1,6 +0,0 @@ -GLPI_CONFIG_DIR=/etc/glpi -GLPI_VAR_DIR=/var/lib/glpi -GLPI_LOG_DIR=/var/log/glpi - -*/1 * * * * /usr/bin/php7 /var/www/glpi/front/cron.php -0 * * * * cd /var/www/glpi && php bin/console glpi:ldap:synchronize_users -n diff --git a/alpine/web-builder/glpi_ticket.class.php.patch b/alpine/web-builder/glpi_ticket.class.php.patch deleted file mode 100644 index 632af8c..0000000 --- a/alpine/web-builder/glpi_ticket.class.php.patch +++ /dev/null @@ -1,19 +0,0 @@ ---- inc/ticket.class.php.old 2020-07-16 14:26:59.000000000 +0200 -+++ inc/ticket.class.php 2020-09-11 18:09:43.200657894 +0200 -@@ -3806,7 +3806,7 @@ - } - } - -- if (empty($delegating) -+/** if (empty($delegating) - && NotificationTargetTicket::isAuthorMailingActivatedForHelpdesk()) { - echo ""; - echo "".__('Inform me about the actions taken').""; -@@ -3821,6 +3821,7 @@ - - echo ""; - } -+*/ - if (($_SESSION["glpiactiveprofile"]["helpdesk_hardware"] != 0) - && (count($_SESSION["glpiactiveprofile"]["helpdesk_item_type"]))) { - if (!$tt->isHiddenField('items_id')) { diff --git a/alpine/web-builder/initrc b/alpine/web-builder/initrc deleted file mode 100644 index 2908475..0000000 --- a/alpine/web-builder/initrc +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -set -e - -rm -r /run/* -mkdir -p /run/apache2 -exec /sbin/runsvdir -P /etc/service diff --git a/alpine/web-builder/service/30-apache2/run b/alpine/web-builder/service/30-apache2/run deleted file mode 100644 index 1a1a0bb..0000000 --- a/alpine/web-builder/service/30-apache2/run +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -. /etc/service/template - -msglog green "Starting Apache..." -exec /usr/sbin/httpd -D FOREGROUND diff --git a/alpine/web-builder/service/90-glpi_init/run b/alpine/web-builder/service/90-glpi_init/run deleted file mode 100644 index 767ea4b..0000000 --- a/alpine/web-builder/service/90-glpi_init/run +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -. /etc/service/template - -msglog green "Starting glpi_init.sh..." -/root/glpi_init.sh -sleep infinity diff --git a/alpine/web-builder/ticket.class.php b/alpine/web-builder/ticket.class.php deleted file mode 100644 index 279aeb1..0000000 --- a/alpine/web-builder/ticket.class.php +++ /dev/null @@ -1,7331 +0,0 @@ -. - * --------------------------------------------------------------------- - */ - -use Glpi\Event; - -if (!defined('GLPI_ROOT')) { - die("Sorry. You can't access this file directly"); -} - -/** - * Ticket Class -**/ -class Ticket extends CommonITILObject { - - // From CommonDBTM - public $dohistory = true; - static protected $forward_entity_to = ['TicketValidation', 'TicketCost']; - - // From CommonITIL - public $userlinkclass = 'Ticket_User'; - public $grouplinkclass = 'Group_Ticket'; - public $supplierlinkclass = 'Supplier_Ticket'; - - static $rightname = 'ticket'; - - protected $userentity_oncreate = true; - - const MATRIX_FIELD = 'priority_matrix'; - const URGENCY_MASK_FIELD = 'urgency_mask'; - const IMPACT_MASK_FIELD = 'impact_mask'; - const STATUS_MATRIX_FIELD = 'ticket_status'; - - // HELPDESK LINK HARDWARE DEFINITION : CHECKSUM SYSTEM : BOTH=1*2^0+1*2^1=3 - const HELPDESK_MY_HARDWARE = 0; - const HELPDESK_ALL_HARDWARE = 1; - - // Specific ones - /// Hardware datas used by getFromDBwithData - public $hardwaredatas = []; - /// Is a hardware found in getHardwareData / getFromDBwithData : hardware link to the job - public $computerfound = 0; - - // Request type - const INCIDENT_TYPE = 1; - // Demand type - const DEMAND_TYPE = 2; - - const READMY = 1; - const READALL = 1024; - const READGROUP = 2048; - const READASSIGN = 4096; - const ASSIGN = 8192; - const STEAL = 16384; - const OWN = 32768; - const CHANGEPRIORITY = 65536; - const SURVEY = 131072; - - - function getForbiddenStandardMassiveAction() { - - $forbidden = parent::getForbiddenStandardMassiveAction(); - - if (!Session::haveRightsOr(self::$rightname, [DELETE, PURGE])) { - $forbidden[] = 'delete'; - $forbidden[] = 'purge'; - $forbidden[] = 'restore'; - } - - return $forbidden; - } - - - /** - * Name of the type - * - * @param $nb : number of item in the type (default 0) - **/ - static function getTypeName($nb = 0) { - return _n('Ticket', 'Tickets', $nb); - } - - - /** - * @see CommonGLPI::getMenuShorcut() - * - * @since 0.85 - **/ - static function getMenuShorcut() { - return 't'; - } - - - /** - * @see CommonGLPI::getAdditionalMenuContent() - * - * @since 0.85 - **/ - static function getAdditionalMenuContent() { - - if (static::canCreate()) { - $menu = [ - 'create_ticket' => [ - 'title' => __('Create ticket'), - 'page' => static::getFormURL(false), - 'icon' => 'fas fa-plus', - ], - ]; - return $menu; - } else { - return self::getAdditionalMenuOptions(); - } - } - - - /** - * @see CommonGLPI::getAdditionalMenuLinks() - * - * @since 0.85 - **/ - static function getAdditionalMenuLinks() { - global $CFG_GLPI; - - $links = parent::getAdditionalMenuLinks(); - if (Session::haveRightsOr('ticketvalidation', TicketValidation::getValidateRights())) { - $opt = []; - $opt['reset'] = 'reset'; - $opt['criteria'][0]['field'] = 55; // validation status - $opt['criteria'][0]['searchtype'] = 'equals'; - $opt['criteria'][0]['value'] = CommonITILValidation::WAITING; - $opt['criteria'][0]['link'] = 'AND'; - - $opt['criteria'][1]['field'] = 59; // validation aprobator - $opt['criteria'][1]['searchtype'] = 'equals'; - $opt['criteria'][1]['value'] = Session::getLoginUserID(); - $opt['criteria'][1]['link'] = 'AND'; - - $opt['criteria'][2]['field'] = 52; // global validation status - $opt['criteria'][2]['searchtype'] = 'equals'; - $opt['criteria'][2]['value'] = CommonITILValidation::WAITING; - $opt['criteria'][2]['link'] = 'AND'; - - $opt['criteria'][3]['field'] = 12; // ticket status - $opt['criteria'][3]['searchtype'] = 'equals'; - $opt['criteria'][3]['value'] = Ticket::CLOSED; - $opt['criteria'][3]['link'] = 'AND NOT'; - - $opt['criteria'][4]['field'] = 12; // ticket status - $opt['criteria'][4]['searchtype'] = 'equals'; - $opt['criteria'][4]['value'] = Ticket::SOLVED; - $opt['criteria'][4]['link'] = 'AND NOT'; - - $pic_validate = "\""."; - - $links[$pic_validate] = Ticket::getSearchURL(false) . '?'.Toolbox::append_params($opt, '&'); - } - - return $links; - } - - - function canAssign() { - if (isset($this->fields['is_deleted']) && ($this->fields['is_deleted'] == 1) - || isset($this->fields['status']) && in_array($this->fields['status'], $this->getClosedStatusArray()) - ) { - return false; - } - return Session::haveRight(static::$rightname, self::ASSIGN); - } - - - function canAssignToMe() { - - if (isset($this->fields['is_deleted']) && $this->fields['is_deleted'] == 1 - || isset($this->fields['status']) && in_array($this->fields['status'], $this->getClosedStatusArray()) - ) { - return false; - } - return (Session::haveRight(self::$rightname, self::STEAL) - || (Session::haveRight(self::$rightname, self::OWN) - && ($this->countUsers(CommonITILActor::ASSIGN) == 0))); - } - - - static function canUpdate() { - - // To allow update of urgency and category for post-only - if (Session::getCurrentInterface() == "helpdesk") { - return Session::haveRight(self::$rightname, CREATE); - } - - return Session::haveRightsOr(self::$rightname, - [UPDATE, - self::ASSIGN, - self::STEAL, - self::OWN, - self::CHANGEPRIORITY]); - } - - - static function canView() { - return (Session::haveRightsOr(self::$rightname, - [self::READALL, self::READMY, UPDATE, self::READASSIGN, - self::READGROUP, self::OWN]) - || Session::haveRightsOr('ticketvalidation', TicketValidation::getValidateRights())); - } - - - /** - * Is the current user have right to show the current ticket ? - * - * @return boolean - **/ - function canViewItem() { - - if (!Session::haveAccessToEntity($this->getEntityID())) { - return false; - } - return (Session::haveRight(self::$rightname, self::READALL) - || (Session::haveRight(self::$rightname, self::READMY) - && (($this->fields["users_id_recipient"] === Session::getLoginUserID()) - || $this->isUser(CommonITILActor::REQUESTER, Session::getLoginUserID()) - || $this->isUser(CommonITILActor::OBSERVER, Session::getLoginUserID()))) - || (Session::haveRight(self::$rightname, self::READGROUP) - && isset($_SESSION["glpigroups"]) - && ($this->haveAGroup(CommonITILActor::REQUESTER, $_SESSION["glpigroups"]) - || $this->haveAGroup(CommonITILActor::OBSERVER, $_SESSION["glpigroups"]))) - || (Session::haveRight(self::$rightname, self::READASSIGN) - && ($this->isUser(CommonITILActor::ASSIGN, Session::getLoginUserID()) - || (isset($_SESSION["glpigroups"]) - && $this->haveAGroup(CommonITILActor::ASSIGN, $_SESSION["glpigroups"])) - || (Session::haveRight(self::$rightname, self::ASSIGN) - && ($this->fields["status"] == self::INCOMING)))) - || (Session::haveRightsOr('ticketvalidation', TicketValidation::getValidateRights()) - && TicketValidation::canValidate($this->fields["id"]))); - } - - - /** - * Is the current user have right to approve solution of the current ticket ? - * - * @return boolean - **/ - function canApprove() { - - return ((($this->fields["users_id_recipient"] === Session::getLoginUserID()) - && Session::haveRight('ticket', Ticket::SURVEY)) - || $this->isUser(CommonITILActor::REQUESTER, Session::getLoginUserID()) - || (isset($_SESSION["glpigroups"]) - && $this->haveAGroup(CommonITILActor::REQUESTER, $_SESSION["glpigroups"]))); - } - - - /** - * @see CommonDBTM::canMassiveAction() - **/ - function canMassiveAction($action, $field, $value) { - - switch ($action) { - case 'update' : - switch ($field) { - case 'status' : - if (!self::isAllowedStatus($this->fields['status'], $value)) { - return false; - } - break; - } - break; - } - return true; - } - - /** - * Check if current user can take into account the ticket. - * - * @return boolean - */ - public function canTakeIntoAccount() { - - // Can take into account if user is assigned user - if ($this->isUser(CommonITILActor::ASSIGN, Session::getLoginUserID()) - || (isset($_SESSION["glpigroups"]) - && $this->haveAGroup(CommonITILActor::ASSIGN, $_SESSION['glpigroups']))) { - return true; - } - - // Cannot take into account if user is a requester (and not assigned) - if ($this->isUser(CommonITILActor::REQUESTER, Session::getLoginUserID()) - || (isset($_SESSION["glpigroups"]) - && $this->haveAGroup(CommonITILActor::REQUESTER, $_SESSION['glpigroups']))) { - return false; - } - - $canAddTask = Session::haveRight("task", CommonITILTask::ADDALLITEM); - $canAddFollowup = Session::haveRightsOr( - 'followup', - [ - ITILFollowup::ADDALLTICKET, - ITILFollowup::ADDMYTICKET, - ITILFollowup::ADDGROUPTICKET, - ] - ); - - // Can take into account if user has rights to add tasks or followups, - // assuming that users that does not have those rights cannot treat the ticket. - return $canAddTask || $canAddFollowup; - } - - /** - * Check if ticket has already been taken into account. - * - * @return boolean - */ - public function isAlreadyTakenIntoAccount() { - - return array_key_exists('takeintoaccount_delay_stat', $this->fields) - && $this->fields['takeintoaccount_delay_stat'] != 0; - } - - /** - * Get Datas to be added for SLA add - * - * @param $slas_id SLA id - * @param $entities_id entity ID of the ticket - * @param $date begin date of the ticket - * @param $type type of SLA - * - * @since 9.1 (before getDatasToAddSla without type parameter) - * - * @return array of datas to add in ticket - **/ - function getDatasToAddSLA($slas_id, $entities_id, $date, $type) { - - list($dateField, $slaField) = SLA::getFieldNames($type); - - $calendars_id = Entity::getUsedConfig('calendars_id', $entities_id); - $data = []; - - $sla = new SLA(); - if ($sla->getFromDB($slas_id)) { - $sla->setTicketCalendar($calendars_id); - if ($sla->fields['type'] == SLM::TTR) { - $data["slalevels_id_ttr"] = SlaLevel::getFirstSlaLevel($slas_id); - } - // Compute time_to_resolve - $data[$dateField] = $sla->computeDate($date); - $data['sla_waiting_duration'] = 0; - - } else { - $data["slalevels_id_ttr"] = 0; - $data[$slaField] = 0; - $data['sla_waiting_duration'] = 0; - } - return $data; - - } - - /** - * Get Datas to be added for OLA add - * - * @param $olas_id OLA id - * @param $entities_id entity ID of the ticket - * @param $date begin date of the ticket - * @param $type type of OLA - * - * @since 9.2 (before getDatasToAddOla without type parameter) - * - * @return array of datas to add in ticket - **/ - function getDatasToAddOLA($olas_id, $entities_id, $date, $type) { - - list($dateField, $olaField) = OLA::getFieldNames($type); - - $calendars_id = Entity::getUsedConfig('calendars_id', $entities_id); - $data = []; - - $ola = new OLA(); - if ($ola->getFromDB($olas_id)) { - $ola->setTicketCalendar($calendars_id); - if ($ola->fields['type'] == SLM::TTR) { - $data["olalevels_id_ttr"] = OlaLevel::getFirstOlaLevel($olas_id); - $data['ola_ttr_begin_date'] = $date; - } - // Compute time_to_resolve - $data[$dateField] = $ola->computeDate($date); - $data['ola_waiting_duration'] = 0; - - } else { - $data["olalevels_id_ttr"] = 0; - $data[$olaField] = 0; - $data['ola_waiting_duration'] = 0; - } - return $data; - - } - - - /** - * Delete Level Agreement for the ticket - * - * @since 9.2 - * - * @param string $laType (SLA | OLA) - * @param integer $id the sla/ola id - * @param integer $subtype (SLM::TTR | SLM::TTO) - * @param bool $delete_date (default false) - * - * @return bool - **/ - function deleteLevelAgreement($laType, $la_id, $subtype, $delete_date = false) { - switch ($laType) { - case "SLA": - $prefix = "sla"; - $prefix_ticket = ""; - $level_ticket = new SlaLevel_Ticket(); - break; - case "OLA": - $prefix = "ola"; - $prefix_ticket = "internal_"; - $level_ticket = new OlaLevel_Ticket(); - break; - } - - $input = []; - switch ($subtype) { - case SLM::TTR : - $input[$prefix.'s_id_ttr'] = 0; - if ($delete_date) { - $input[$prefix_ticket.'time_to_resolve'] = ''; - } - break; - - case SLM::TTO : - $input[$prefix.'s_id_tto'] = 0; - if ($delete_date) { - $input[$prefix_ticket.'time_to_own'] = ''; - } - break; - } - - $input[$prefix.'_waiting_duration'] = 0; - $input['id'] = $la_id; - $level_ticket->deleteForTicket($la_id, $subtype); - - return $this->update($input); - } - - - /** - * Is the current user have right to create the current ticket ? - * - * @return boolean - **/ - function canCreateItem() { - - if (!Session::haveAccessToEntity($this->getEntityID())) { - return false; - } - return self::canCreate(); - } - - - /** - * Is the current user have right to update the current ticket ? - * - * @return boolean - **/ - function canUpdateItem() { - if (!$this->checkEntity()) { - return false; - } - - // for all, if no modification in ticket return true - if ($can_requester = $this->canRequesterUpdateItem()) { - return true; - } - - // for self-service only, if modification in ticket, we can't update the ticket - if (Session::getCurrentInterface() == "helpdesk" - && !$can_requester) { - return false; - } - - // if we don't have global UPDATE right, maybe we can own the current ticket - if (!Session::haveRight(self::$rightname, UPDATE) - && !$this->ownItem()) { - //we always return false, as ownItem() = true is managed by below self::canUpdate - return false; - } - - return self::canupdate(); - } - - - /** - * Is the current user is a requester of the current ticket and have the right to update it ? - * - * @return boolean - */ - function canRequesterUpdateItem() { - return ($this->isUser(CommonITILActor::REQUESTER, Session::getLoginUserID()) - || $this->fields["users_id_recipient"] === Session::getLoginUserID()) - && $this->fields['status'] != self::SOLVED - && $this->fields['status'] != self::CLOSED - && $this->numberOfFollowups() == 0 - && $this->numberOfTasks() == 0; - } - - /** - * Is the current user have OWN right and is the assigned to the ticket - * - * @return boolean - */ - function ownItem() { - return Session::haveRight(self::$rightname, self::OWN) - && $this->isUser(CommonITILActor::ASSIGN, Session::getLoginUserID()); - } - - - /** - * @since 0.85 - **/ - static function canDelete() { - - // to allow delete for self-service only if no action on the ticket - if (Session::getCurrentInterface() == "helpdesk") { - return Session::haveRight(self::$rightname, CREATE); - } - return Session::haveRight(self::$rightname, DELETE); - } - - /** - * is the current user could reopen the current ticket - * @since 9.2 - * @return boolean - */ - function canReopen() { - return Session::haveRight('followup', CREATE) - && in_array($this->fields["status"], $this->getClosedStatusArray()) - && ($this->isAllowedStatus($this->fields['status'], self::INCOMING) - || $this->isAllowedStatus($this->fields['status'], self::ASSIGNED)); - } - - - /** - * Is the current user have right to delete the current ticket ? - * - * @return boolean - **/ - function canDeleteItem() { - - if (!Session::haveAccessToEntity($this->getEntityID())) { - return false; - } - - // user can delete his ticket if no action on it - if (Session::getCurrentInterface() == "helpdesk" - && (!($this->isUser(CommonITILActor::REQUESTER, Session::getLoginUserID()) - || $this->fields["users_id_recipient"] === Session::getLoginUserID()) - || $this->numberOfFollowups() > 0 - || $this->numberOfTasks() > 0 - || $this->fields["date"] != $this->fields["date_mod"])) { - return false; - } - - return static::canDelete(); - } - - /** - * @see CommonITILObject::getDefaultActor() - **/ - function getDefaultActor($type) { - - if ($type == CommonITILActor::ASSIGN) { - if (Session::haveRight(self::$rightname, self::OWN) - && $_SESSION['glpiset_default_tech']) { - return Session::getLoginUserID(); - } - } - if ($type == CommonITILActor::REQUESTER) { - if (Session::haveRight(self::$rightname, CREATE) - && $_SESSION['glpiset_default_requester']) { - return Session::getLoginUserID(); - } - } - return 0; - } - - - /** - * @see CommonITILObject::getDefaultActorRightSearch() - **/ - function getDefaultActorRightSearch($type) { - - $right = "all"; - if ($type == CommonITILActor::ASSIGN) { - $right = "own_ticket"; - if (!Session::haveRight(self::$rightname, self::ASSIGN)) { - $right = 'id'; - } - } - return $right; - } - - - function pre_deleteItem() { - global $CFG_GLPI; - - if (!isset($this->input['_disablenotif']) && $CFG_GLPI['use_notifications']) { - NotificationEvent::raiseEvent('delete', $this); - } - return true; - } - - - function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { - - if (static::canView()) { - $nb = 0; - $title = self::getTypeName(Session::getPluralNumber()); - if ($_SESSION['glpishow_count_on_tabs']) { - switch ($item->getType()) { - case 'User' : - $nb = countElementsInTable( - ['glpi_tickets', 'glpi_tickets_users'], [ - 'glpi_tickets_users.tickets_id' => new \QueryExpression(DB::quoteName('glpi_tickets.id')), - 'glpi_tickets_users.users_id' => $item->getID(), - 'glpi_tickets_users.type' => CommonITILActor::REQUESTER - ] + getEntitiesRestrictCriteria(self::getTable()) - ); - $title = __('Created tickets'); - break; - - case 'Supplier' : - $nb = countElementsInTable( - ['glpi_tickets', 'glpi_suppliers_tickets'], [ - 'glpi_suppliers_tickets.tickets_id' => new \QueryExpression(DB::quoteName('glpi_tickets.id')), - 'glpi_suppliers_tickets.suppliers_id' => $item->getID() - ] + getEntitiesRestrictCriteria(self::getTable()) - ); - break; - - case 'SLA' : - $nb = countElementsInTable( - 'glpi_tickets', [ - 'OR' => [ - 'slas_id_tto' => $item->getID(), - 'slas_id_ttr' => $item->getID() - ] - ] - ); - break; - case 'OLA' : - $nb = countElementsInTable( - 'glpi_tickets', [ - 'OR' => [ - 'olas_id_tto' => $item->getID(), - 'olas_id_ttr' => $item->getID() - ] - ] - ); - break; - - case 'Group' : - $nb = countElementsInTable( - ['glpi_tickets', 'glpi_groups_tickets'], [ - 'glpi_groups_tickets.tickets_id' => new \QueryExpression(DB::quoteName('glpi_tickets.id')), - 'glpi_groups_tickets.groups_id' => $item->getID(), - 'glpi_groups_tickets.type' => CommonITILActor::REQUESTER - ] + getEntitiesRestrictCriteria(self::getTable()) - ); - $title = __('Created tickets'); - break; - - default : - // Direct one - $nb = countElementsInTable( - 'glpi_items_tickets', - [ - 'INNER JOIN' => [ - 'glpi_tickets' => [ - 'FKEY' => [ - 'glpi_items_tickets' => 'tickets_id', - 'glpi_tickets' => 'id' - ] - ] - ], - 'WHERE' => [ - 'itemtype' => $item->getType(), - 'items_id' => $item->getID(), - 'is_deleted' => 0 - ] - ] - ); - - // Linked items - $linkeditems = $item->getLinkedItems(); - - if (count($linkeditems)) { - foreach ($linkeditems as $type => $tab) { - foreach ($tab as $ID) { - $nb += countElementsInTable( - 'glpi_items_tickets', - [ - 'INNER JOIN' => [ - 'glpi_tickets' => [ - 'FKEY' => [ - 'glpi_items_tickets' => 'tickets_id', - 'glpi_tickets' => 'id' - ] - ] - ], - 'WHERE' => [ - 'itemtype' => $type, - 'items_id' => $ID, - 'is_deleted' => 0 - ] - ] - ); - } - } - } - break; - } - - } // glpishow_count_on_tabs - // Not for Ticket class - if ($item->getType() != __CLASS__) { - return self::createTabEntry($title, $nb); - } - } // self::READALL right check - - // Not check self::READALL for Ticket itself - switch ($item->getType()) { - case __CLASS__ : - $ong = []; - - $timeline = $item->getTimelineItems(); - $nb_elements = count($timeline); - $ong[1] = __("Processing ticket")." $nb_elements"; - - // enquete si statut clos - $satisfaction = new TicketSatisfaction(); - if ($satisfaction->getFromDB($item->getID()) - && $item->fields['status'] == self::CLOSED) { - $ong[3] = __('Satisfaction'); - } - if ($item->canView()) { - $ong[4] = __('Statistics'); - } - return $ong; - - // default : - // return _n('Ticket','Tickets', Session::getPluralNumber()); - } - - return ''; - } - - - static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) { - - switch ($item->getType()) { - case __CLASS__ : - switch ($tabnum) { - - case 1 : - echo "
"; - $rand = mt_rand(); - $item->showTimelineForm($rand); - $item->showTimeline($rand); - echo "
"; - break; - - case 3 : - $satisfaction = new TicketSatisfaction(); - if (($item->fields['status'] == self::CLOSED) - && $satisfaction->getFromDB($_GET["id"])) { - - $duration = Entity::getUsedConfig('inquest_duration', $item->fields['entities_id']); - $date2 = strtotime($satisfaction->fields['date_begin']); - if (($duration == 0) - || (strtotime("now") - $date2) <= $duration*DAY_TIMESTAMP) { - $satisfaction->showForm($item); - } else { - echo "

".__('Satisfaction survey expired')."

"; - } - - } else { - echo "

".__('No generated survey')."

"; - } - break; - - case 4 : - $item->showStats(); - break; - } - break; - - case 'Group' : - case 'SLA' : - case 'OLA' : - default : - self::showListForItem($item, $withtemplate); - } - return true; - } - - - function defineTabs($options = []) { - $ong = []; - - $this->defineDefaultObjectTabs($ong, $options); - $this->addStandardTab('TicketValidation', $ong, $options); - $this->addStandardTab('KnowbaseItem_Item', $ong, $options); - $this->addStandardTab('Item_Ticket', $ong, $options); - - if ($this->hasImpactTab()) { - $this->addStandardTab('Impact', $ong, $options); - } - - $this->addStandardTab('TicketCost', $ong, $options); - $this->addStandardTab('Itil_Project', $ong, $options); - $this->addStandardTab('ProjectTask_Ticket', $ong, $options); - $this->addStandardTab('Problem_Ticket', $ong, $options); - $this->addStandardTab('Change_Ticket', $ong, $options); - - $entity = $this->getEntityID(); - if (!(Entity::getUsedConfig('anonymize_support_agents', $entity) - && Session::getCurrentInterface() == 'helpdesk') - ) { - $this->addStandardTab('Log', $ong, $options); - } - - return $ong; - } - - - /** - * Retrieve data of the hardware linked to the ticket if exists - * - * @return void - **/ - function getAdditionalDatas() { - - $this->hardwaredatas = []; - - if (!empty($this->fields["id"])) { - $item_ticket = new Item_Ticket(); - $data = $item_ticket->find(['tickets_id' => $this->fields["id"]]); - - foreach ($data as $val) { - if (!empty($val["itemtype"]) && ($item = getItemForItemtype($val["itemtype"]))) { - if ($item->getFromDB($val["items_id"])) { - $this->hardwaredatas[] = $item; - } - } - } - } - - } - - - function cleanDBonPurge() { - - // OlaLevel_Ticket does not extends CommonDBConnexity - $olaLevel_ticket = new OlaLevel_Ticket(); - $olaLevel_ticket->deleteForTicket($this->fields['id'], SLM::TTO); - $olaLevel_ticket->deleteForTicket($this->fields['id'], SLM::TTR); - - // SlaLevel_Ticket does not extends CommonDBConnexity - $slaLevel_ticket = new SlaLevel_Ticket(); - $slaLevel_ticket->deleteForTicket($this->fields['id'], SLM::TTO); - $slaLevel_ticket->deleteForTicket($this->fields['id'], SLM::TTR); - - // TicketSatisfaction does not extends CommonDBConnexity - $tf = new TicketSatisfaction(); - $tf->deleteByCriteria(['tickets_id' => $this->fields['id']]); - - // CommonITILTask does not extends CommonDBConnexity - $tt = new TicketTask(); - $tt->deleteByCriteria(['tickets_id' => $this->fields['id']]); - - $this->deleteChildrenAndRelationsFromDb( - [ - Change_Ticket::class, - Item_Ticket::class, - Problem_Ticket::class, - ProjectTask_Ticket::class, - TicketCost::class, - Ticket_Ticket::class, - TicketValidation::class, - ] - ); - - parent::cleanDBonPurge(); - - } - - - function prepareInputForUpdate($input) { - global $DB; - - // Get ticket : need for comparison - $this->getFromDB($input['id']); - - // Clean new lines before passing to rules - if (isset($input["content"])) { - $input["content"] = preg_replace('/\\\\r\\\\n/', "\n", $input['content']); - $input["content"] = preg_replace('/\\\\n/', "\n", $input['content']); - } - - // automatic recalculate if user changes urgence or technician change impact - $canpriority = Session::haveRight(self::$rightname, self::CHANGEPRIORITY); - if ((isset($input['urgency']) && $input['urgency'] != $this->fields['urgency']) - || (isset($input['impact']) && $input['impact'] != $this->fields['impact']) - && ($canpriority && !isset($input['priority']) || !$canpriority) - ) { - if (!isset($input['urgency'])) { - $input['urgency'] = $this->fields['urgency']; - } - if (!isset($input['impact'])) { - $input['impact'] = $this->fields['impact']; - } - $input['priority'] = self::computePriority($input['urgency'], $input['impact']); - } - - // Security checks - if (!Session::isCron() - && !Session::haveRight(self::$rightname, self::ASSIGN)) { - if (isset($input["_itil_assign"]) - && isset($input['_itil_assign']['_type']) - && ($input['_itil_assign']['_type'] == 'user')) { - - // must own_ticket to grab a non assign ticket - if ($this->countUsers(CommonITILActor::ASSIGN) == 0) { - if ((!Session::haveRightsOr(self::$rightname, [self::STEAL, self::OWN])) - || !isset($input["_itil_assign"]['users_id']) - || ($input["_itil_assign"]['users_id'] != Session::getLoginUserID())) { - unset($input["_itil_assign"]); - } - - } else { - // Can not steal or can steal and not assign to me - if (!Session::haveRight(self::$rightname, self::STEAL) - || !isset($input["_itil_assign"]['users_id']) - || ($input["_itil_assign"]['users_id'] != Session::getLoginUserID())) { - unset($input["_itil_assign"]); - } - } - } - - // No supplier assign - if (isset($input["_itil_assign"]) - && isset($input['_itil_assign']['_type']) - && ($input['_itil_assign']['_type'] == 'supplier')) { - unset($input["_itil_assign"]); - } - - // No group - if (isset($input["_itil_assign"]) - && isset($input['_itil_assign']['_type']) - && ($input['_itil_assign']['_type'] == 'group')) { - unset($input["_itil_assign"]); - } - } - - //must be handled here for tickets. @see CommonITILObject::prepareInputForUpdate() - $input = $this->handleTemplateFields($input); - if ($input === false) { - return false; - } - - if (isset($input['entities_id'])) { - $entid = $input['entities_id']; - } else { - $entid = $this->fields['entities_id']; - } - - // Process Business Rules - $this->fillInputForBusinessRules($input); - - // Add actors on standard input - $rules = new RuleTicketCollection($entid); - $rule = $rules->getRuleClass(); - $changes = []; - $post_added = []; - $tocleanafterrules = []; - $usertypes = [ - CommonITILActor::ASSIGN => 'assign', - CommonITILActor::REQUESTER => 'requester', - CommonITILActor::OBSERVER => 'observer' - ]; - foreach ($usertypes as $k => $t) { - //handle new input - if (isset($input['_itil_'.$t]) && isset($input['_itil_'.$t]['_type'])) { - $field = $input['_itil_'.$t]['_type'].'s_id'; - if (isset($input['_itil_'.$t][$field]) - && !isset($input[$field.'_'.$t])) { - $input['_'.$field.'_'.$t][] = $input['_itil_'.$t][$field]; - $tocleanafterrules['_'.$field.'_'.$t][] = $input['_itil_'.$t][$field]; - } - } - - //handle existing actors: load all existing actors from ticket - //to make sure business rules will receive all informations, and not just - //what have been entered in the html form. - // - //ref also this actor into $post_added to avoid the filling of $changes - //and triggering businness rules when not needed - $users = $this->getUsers($k); - if (count($users)) { - $field = 'users_id'; - foreach ($users as $user) { - if (!isset($input['_'.$field.'_'.$t]) || !in_array($user[$field], $input['_'.$field.'_'.$t])) { - if (!isset($input['_'.$field.'_'.$t])) { - $post_added['_'.$field.'_'.$t] = '_'.$field.'_'.$t; - } - $input['_'.$field.'_'.$t][] = $user[$field]; - $tocleanafterrules['_'.$field.'_'.$t][] = $user[$field]; - } - } - } - - $groups = $this->getGroups($k); - if (count($groups)) { - $field = 'groups_id'; - foreach ($groups as $group) { - if (!isset($input['_'.$field.'_'.$t]) || !in_array($group[$field], $input['_'.$field.'_'.$t])) { - if (!isset($input['_'.$field.'_'.$t])) { - $post_added['_'.$field.'_'.$t] = '_'.$field.'_'.$t; - } - $input['_'.$field.'_'.$t][] = $group[$field]; - $tocleanafterrules['_'.$field.'_'.$t][] = $group[$field]; - } - } - } - - $suppliers = $this->getSuppliers($k); - if (count($suppliers)) { - $field = 'suppliers_id'; - foreach ($suppliers as $supplier) { - if (!isset($input['_'.$field.'_'.$t]) || !in_array($supplier[$field], $input['_'.$field.'_'.$t])) { - if (!isset($input['_'.$field.'_'.$t])) { - $post_added['_'.$field.'_'.$t] = '_'.$field.'_'.$t; - } - $input['_'.$field.'_'.$t][] = $supplier[$field]; - $tocleanafterrules['_'.$field.'_'.$t][] = $supplier[$field]; - } - } - } - } - - foreach ($rule->getCriterias() as $key => $val) { - if (array_key_exists($key, $input) - && !array_key_exists($key, $post_added)) { - if (!isset($this->fields[$key]) - || ($DB->escape($this->fields[$key]) != $input[$key])) { - $changes[] = $key; - } - } - } - - // Business Rules do not override manual SLA and OLA - $manual_slas_id = []; - $manual_olas_id = []; - foreach ([SLM::TTR, SLM::TTO] as $slmType) { - list($dateField, $slaField) = SLA::getFieldNames($slmType); - if (isset($input[$slaField]) && ($input[$slaField] > 0)) { - $manual_slas_id[$slmType] = $input[$slaField]; - } - - list($dateField, $olaField) = OLA::getFieldNames($slmType); - if (isset($input[$olaField]) && ($input[$olaField] > 0)) { - $manual_olas_id[$slmType] = $input[$olaField]; - } - } - - // Only process rules on changes - if (count($changes)) { - if (in_array('_users_id_requester', $changes)) { - // If _users_id_requester changed : set users_locations - $user = new User(); - if (isset($input["_itil_requester"]["users_id"]) - && $user->getFromDB($input["_itil_requester"]["users_id"])) { - $input['users_locations'] = $user->fields['locations_id']; - $changes[] = 'users_locations'; - } - // If _users_id_requester changed : add _groups_id_of_requester to changes - $changes[] = '_groups_id_of_requester'; - } - - $input = $rules->processAllRules($input, - $input, - ['recursive' => true, - 'entities_id' => $entid], - ['condition' => RuleTicket::ONUPDATE, - 'only_criteria' => $changes]); - $input = Toolbox::stripslashes_deep($input); - } - - // Clean actors fields added for rules - foreach ($tocleanafterrules as $key => $val) { - if ($input[$key] == $val) { - unset($input[$key]); - } - } - - // Manage fields from auto update or rules : map rule actions to standard additional ones - $usertypes = ['assign', 'requester', 'observer']; - $actortypes = ['user','group','supplier']; - foreach ($usertypes as $t) { - foreach ($actortypes as $a) { - if (isset($input['_'.$a.'s_id_'.$t])) { - switch ($a) { - case 'user' : - $additionalfield = '_additional_'.$t.'s'; - $input[$additionalfield][] = ['users_id' => $input['_'.$a.'s_id_'.$t]]; - break; - - default : - $additionalfield = '_additional_'.$a.'s_'.$t.'s'; - $input[$additionalfield][] = $input['_'.$a.'s_id_'.$t]; - break; - } - } - } - } - - if (isset($input['_link'])) { - $ticket_ticket = new Ticket_Ticket(); - if (!empty($input['_link']['tickets_id_2'])) { - if ($ticket_ticket->can(-1, CREATE, $input['_link'])) { - if ($ticket_ticket->add($input['_link'])) { - $input['_forcenotif'] = true; - } - } else { - Session::addMessageAfterRedirect(__('Unknown ticket'), false, ERROR); - } - } - } - - // SLA / OLA affect by rules : reset time_to_resolve / internal_time_to_resolve - // Manual SLA / OLA defined : reset time_to_resolve / internal_time_to_resolve - // No manual SLA / OLA and due date defined : reset auto SLA / OLA - foreach ([SLM::TTR, SLM::TTO] as $slmType) { - $this->slaAffect($slmType, $input, $manual_slas_id); - $this->olaAffect($slmType, $input, $manual_olas_id); - } - - if (isset($input['content'])) { - if (isset($input['_filename']) || isset($input['_content'])) { - $input['_disablenotif'] = true; - } else { - $input['_donotadddocs'] = true; - } - } - - $input = parent::prepareInputForUpdate($input); - return $input; - } - - - /** - * SLA affect by rules : reset time_to_resolve and time_to_own - * Manual SLA defined : reset time_to_resolve and time_to_own - * No manual SLA and due date defined : reset auto SLA - * - * @since 9.1 - * - * @param $type - * @param $input - * @param $manual_slas_id - */ - function slaAffect($type, &$input, $manual_slas_id) { - - list($dateField, $slaField) = SLA::getFieldNames($type); - - // Restore slas - if (isset($manual_slas_id[$type]) - && !isset($input['_'.$slaField])) { - $input[$slaField] = $manual_slas_id[$type]; - } - - // Ticket update - if (isset($this->fields['id']) && $this->fields['id'] > 0) { - if (!isset($manual_slas_id[$type]) - && isset($input[$slaField]) && ($input[$slaField] > 0) - && ($input[$slaField] != $this->fields[$slaField])) { - - if (isset($input[$dateField])) { - // Unset due date - unset($input[$dateField]); - } - } - - if (isset($input[$slaField]) && ($input[$slaField] > 0) - && ($input[$slaField] != $this->fields[$slaField])) { - - $date = $this->fields['date']; - /// Use updated date if also done - if (isset($input["date"])) { - $date = $input["date"]; - } - // Get datas to initialize SLA and set it - $sla_data = $this->getDatasToAddSLA($input[$slaField], $this->fields['entities_id'], - $date, $type); - if (count($sla_data)) { - foreach ($sla_data as $key => $val) { - $input[$key] = $val; - } - } - } - } else { // Ticket add - if (!isset($manual_slas_id[$type]) - && isset($input[$dateField]) && ($input[$dateField] != 'NULL')) { - // Valid due date - if ($input[$dateField] >= $input['date']) { - if (isset($input[$slaField])) { - unset($input[$slaField]); - } - } else { - // Unset due date - unset($input[$dateField]); - } - } - - if (isset($input[$slaField]) && ($input[$slaField] > 0)) { - // Get datas to initialize SLA and set it - $sla_data = $this->getDatasToAddSLA($input[$slaField], $input['entities_id'], - $input['date'], $type); - if (count($sla_data)) { - foreach ($sla_data as $key => $val) { - $input[$key] = $val; - } - } - } - } - } - - /** - * OLA affect by rules : reset internal_time_to_resolve and internal_time_to_own - * Manual OLA defined : reset internal_time_to_resolve and internal_time_to_own - * No manual OLA and due date defined : reset auto OLA - * - * @since 9.1 - * - * @param $type - * @param $input - * @param $manual_olas_id - */ - function olaAffect($type, &$input, $manual_olas_id) { - - list($dateField, $olaField) = OLA::getFieldNames($type); - - // Restore olas - if (isset($manual_olas_id[$type]) - && !isset($input['_'.$olaField])) { - $input[$olaField] = $manual_olas_id[$type]; - } - - // Ticket update - if (isset($this->fields['id']) && $this->fields['id'] > 0) { - if (!isset($manual_olas_id[$type]) - && isset($input[$olaField]) && ($input[$olaField] > 0) - && ($input[$olaField] != $this->fields[$olaField])) { - - if (isset($input[$dateField])) { - // Unset due date - unset($input[$dateField]); - } - } - - if (isset($input[$olaField]) && ($input[$olaField] > 0) - && ($input[$olaField] != $this->fields[$olaField] - || isset($input['_'.$olaField]))) { - - $date = date('Y-m-d H:i:s'); - - // Get datas to initialize OLA and set it - $ola_data = $this->getDatasToAddOLA($input[$olaField], $this->fields['entities_id'], - $date, $type); - if (count($ola_data)) { - foreach ($ola_data as $key => $val) { - $input[$key] = $val; - } - } - } - } else { // Ticket add - if (!isset($manual_olas_id[$type]) - && isset($input[$dateField]) && ($input[$dateField] != 'NULL')) { - // Valid due date - if ($input[$dateField] >= $input['date']) { - if (isset($input[$olaField])) { - unset($input[$olaField]); - } - } else { - // Unset due date - unset($input[$dateField]); - } - } - - if (isset($input[$olaField]) && ($input[$olaField] > 0)) { - // Get datas to initialize OLA and set it - $ola_data = $this->getDatasToAddOLA($input[$olaField], $input['entities_id'], - $input['date'], $type); - if (count($ola_data)) { - foreach ($ola_data as $key => $val) { - $input[$key] = $val; - } - } - } - } - } - - - /** - * Manage SLA level escalation - * - * @since 9.1 - * - * @param $slas_id - **/ - function manageSlaLevel($slas_id) { - - $calendars_id = Entity::getUsedConfig('calendars_id', $this->fields['entities_id']); - // Add first level in working table - $slalevels_id = SlaLevel::getFirstSlaLevel($slas_id); - - $sla = new SLA(); - if ($sla->getFromDB($slas_id)) { - $sla->setTicketCalendar($calendars_id); - $sla->addLevelToDo($this, $slalevels_id); - } - SlaLevel_Ticket::replayForTicket($this->getID(), $sla->getField('type')); - } - - /** - * Manage OLA level escalation - * - * @since 9.1 - * - * @param $slas_id - **/ - function manageOlaLevel($slas_id) { - - $calendars_id = Entity::getUsedConfig('calendars_id', $this->fields['entities_id']); - // Add first level in working table - $olalevels_id = OlaLevel::getFirstOlaLevel($slas_id); - - $ola = new OLA(); - if ($ola->getFromDB($slas_id)) { - $ola->setTicketCalendar($calendars_id); - $ola->addLevelToDo($this, $olalevels_id); - } - OlaLevel_Ticket::replayForTicket($this->getID(), $ola->getField('type')); - } - - - function pre_updateInDB() { - - if (!$this->isTakeIntoAccountComputationBlocked($this->input) - && !$this->isAlreadyTakenIntoAccount() - && $this->canTakeIntoAccount() - && !$this->isNew() - ) { - $this->updates[] = "takeintoaccount_delay_stat"; - $this->fields['takeintoaccount_delay_stat'] = $this->computeTakeIntoAccountDelayStat(); - } - - parent::pre_updateInDB(); - - } - - - /** - * Compute take into account stat of the current ticket - **/ - function computeTakeIntoAccountDelayStat() { - - if (isset($this->fields['id']) - && !empty($this->fields['date'])) { - $calendars_id = $this->getCalendar(); - $calendar = new Calendar(); - - // Using calendar - if (($calendars_id > 0) && $calendar->getFromDB($calendars_id)) { - return max(1, $calendar->getActiveTimeBetween($this->fields['date'], - $_SESSION["glpi_currenttime"])); - } - // Not calendar defined - return max(1, strtotime($_SESSION["glpi_currenttime"])-strtotime($this->fields['date'])); - } - return 0; - } - - - function post_updateItem($history = 1) { - global $CFG_GLPI; - - parent::post_updateItem($history); - - //Action for send_validation rule : do validation before clean - $this->manageValidationAdd($this->input); - - // Put same status on duplicated tickets when solving or closing (autoclose on solve) - if (isset($this->input['status']) - && in_array('status', $this->updates) - && (in_array($this->input['status'], $this->getSolvedStatusArray()) - || in_array($this->input['status'], $this->getClosedStatusArray()))) { - Ticket_Ticket::manageLinkedTicketsOnSolved($this->getID()); - } - - $donotif = count($this->updates); - - if (isset($this->input['_forcenotif'])) { - $donotif = true; - } - - // Manage SLA / OLA Level : add actions - foreach ([SLM::TTR, SLM::TTO] as $slmType) { - list($dateField, $slaField) = SLA::getFieldNames($slmType); - if (in_array($slaField, $this->updates) - && ($this->fields[$slaField] > 0)) { - $this->manageSlaLevel($this->fields[$slaField]); - } - - list($dateField, $olaField) = OLA::getFieldNames($slmType); - if (in_array($olaField, $this->updates) - && ($this->fields[$olaField] > 0)) { - $this->manageOlaLevel($this->fields[$olaField]); - } - } - - if (count($this->updates)) { - // Update Ticket Tco - if (in_array("actiontime", $this->updates) - || in_array("cost_time", $this->updates) - || in_array("cost_fixed", $this->updates) - || in_array("cost_material", $this->updates)) { - - if (!empty($this->input["items_id"])) { - foreach ($this->input["items_id"] as $itemtype => $items) { - foreach ($items as $items_id) { - if ($itemtype && ($item = getItemForItemtype($itemtype))) { - if ($item->getFromDB($items_id)) { - $newinput = []; - $newinput['id'] = $items_id; - $newinput['ticket_tco'] = self::computeTco($item); - $item->update($newinput); - } - } - } - } - } - } - - $donotif = true; - } - - if (isset($this->input['_disablenotif'])) { - $donotif = false; - } - - if ($donotif && $CFG_GLPI["use_notifications"]) { - $mailtype = "update"; - - if (isset($this->input["status"]) - && $this->input["status"] - && in_array("status", $this->updates) - && in_array($this->input["status"], $this->getSolvedStatusArray())) { - - $mailtype = "solved"; - } - - if (isset($this->input["status"]) - && $this->input["status"] - && in_array("status", $this->updates) - && in_array($this->input["status"], $this->getClosedStatusArray())) { - - $mailtype = "closed"; - } - // to know if a solution is approved or not - if ((isset($this->input['solvedate']) && ($this->input['solvedate'] == 'NULL') - && isset($this->oldvalues['solvedate']) && $this->oldvalues['solvedate']) - && (isset($this->input['status']) - && ($this->input['status'] != $this->oldvalues['status']) - && ($this->oldvalues['status'] == self::SOLVED))) { - - $mailtype = "rejectsolution"; - } - - // Read again ticket to be sure that all data are up to date - $this->getFromDB($this->fields['id']); - NotificationEvent::raiseEvent($mailtype, $this); - } - - // inquest created immediatly if delay = O - $inquest = new TicketSatisfaction(); - $rate = Entity::getUsedConfig('inquest_config', $this->fields['entities_id'], - 'inquest_rate'); - $delay = Entity::getUsedConfig('inquest_config', $this->fields['entities_id'], - 'inquest_delay'); - $type = Entity::getUsedConfig('inquest_config', $this->fields['entities_id']); - $max_closedate = $this->fields['closedate']; - - if (in_array("status", $this->updates) - && in_array($this->input["status"], $this->getClosedStatusArray()) - && ($delay == 0) - && ($rate > 0) - && (mt_rand(1, 100) <= $rate)) { - - // For reopened ticket - if ($inquest->getFromDB($this->fields['id'])) { - $resp = $inquest->fields; - $inquest->delete($resp); - } - - $inquest->add( - [ - 'tickets_id' => $this->fields['id'], - 'date_begin' => $_SESSION["glpi_currenttime"], - 'entities_id' => $this->fields['entities_id'], - 'type' => $type, - 'max_closedate' => $max_closedate, - ] - ); - } - } - - - function prepareInputForAdd($input) { - // Standard clean datas - $input = parent::prepareInputForAdd($input); - if ($input === false) { - return false; - } - - if (!isset($input["requesttypes_id"])) { - $input["requesttypes_id"] = RequestType::getDefault('helpdesk'); - } - - if (!isset($input['global_validation'])) { - $input['global_validation'] = CommonITILValidation::NONE; - } - - // Set additional default dropdown - $dropdown_fields = ['users_locations', 'items_locations']; - foreach ($dropdown_fields as $field) { - if (!isset($input[$field])) { - $input[$field] = 0; - } - } - if (!isset($input['itemtype']) || !isset($input['items_id']) || !($input['items_id'] > 0)) { - $input['itemtype'] = ''; - } - - // Get first item location - $item = null; - if (isset($input["items_id"]) - && is_array($input["items_id"]) - && (count($input["items_id"]) > 0)) { - $infocom = new Infocom(); - foreach ($input["items_id"] as $itemtype => $items) { - foreach ($items as $items_id) { - if ($item = getItemForItemtype($itemtype)) { - $item->getFromDB($items_id); - $input['items_states'] = $item->fields['states_id']; - $input['items_locations'] = $item->fields['locations_id']; - if ($infocom->getFromDBforDevice($itemtype, $items_id)) { - $input['items_businesscriticities'] - = Dropdown::getDropdownName('glpi_businesscriticities', - $infocom->fields['businesscriticities_id']); - } - if (isset($item->fields['groups_id'])) { - $input['items_groups'] = $item->fields['groups_id']; - - } - break(2); - } - } - } - } - - // Business Rules do not override manual SLA and OLA - $manual_slas_id = []; - $manual_olas_id = []; - foreach ([SLM::TTR, SLM::TTO] as $slmType) { - list($dateField, $slaField) = SLA::getFieldNames($slmType); - if (isset($input[$slaField]) && ($input[$slaField] > 0)) { - $manual_slas_id[$slmType] = $input[$slaField]; - } - list($dateField, $olaField) = OLA::getFieldNames($slmType); - if (isset($input[$olaField]) && ($input[$olaField] > 0)) { - $manual_olas_id[$slmType] = $input[$olaField]; - } - } - - // fill auto-assign when no tech defined (only for tech) - if (!isset($input['_auto_import']) - && isset($_SESSION['glpiset_default_tech']) && $_SESSION['glpiset_default_tech'] - && Session::getCurrentInterface() == 'central' - && (!isset($input['_users_id_assign']) || $input['_users_id_assign'] == 0) - && Session::haveRight("ticket", Ticket::OWN) - ) { - $input['_users_id_assign'] = Session::getLoginUserID(); - } - - // Process Business Rules - $this->fillInputForBusinessRules($input); - - $rules = new RuleTicketCollection($input['entities_id']); - - // Set unset variables with are needed - $tmprequester = 0; - $user = new User(); - if (isset($input["_users_id_requester"])) { - if (!is_array($input["_users_id_requester"]) - && $user->getFromDB($input["_users_id_requester"])) { - $input['users_locations'] = $user->fields['locations_id']; - $input['users_default_groups'] = $user->fields['groups_id']; - $tmprequester = $input["_users_id_requester"]; - } else if (is_array($input["_users_id_requester"]) && ($user_id = reset($input["_users_id_requester"])) !== false) { - if ($user->getFromDB($user_id)) { - $input['users_locations'] = $user->fields['locations_id']; - $input['users_default_groups'] = $user->fields['groups_id']; - } - } - } - - // Clean new lines before passing to rules - if (isset($input["content"])) { - $input["content"] = preg_replace('/\\\\r\\\\n/', "\\n", $input['content']); - $input["content"] = preg_replace('/\\\\n/', "\\n", $input['content']); - } - - $input = $rules->processAllRules($input, - $input, - ['recursive' => true], - ['condition' => RuleTicket::ONADD]); - $input = Toolbox::stripslashes_deep($input); - - // Recompute default values based on values computed by rules - $input = $this->computeDefaultValuesForAdd($input); - - if (isset($input['_users_id_requester']) - && !is_array($input['_users_id_requester']) - && ($input['_users_id_requester'] != $tmprequester)) { - // if requester set by rule, clear address from mailcollector - unset($input['_users_id_requester_notif']); - } - if (isset($input['_users_id_requester_notif']) - && isset($input['_users_id_requester_notif']['alternative_email']) - && is_array($input['_users_id_requester_notif']['alternative_email'])) { - foreach ($input['_users_id_requester_notif']['alternative_email'] as $email) { - if ($email && !NotificationMailing::isUserAddressValid($email)) { - Session::addMessageAfterRedirect( - sprintf(__('Invalid email address %s'), $email), - false, - ERROR - ); - return false; - } - } - } - - // Manage auto assign - $auto_assign_mode = Entity::getUsedConfig('auto_assign_mode', $input['entities_id']); - - switch ($auto_assign_mode) { - case Entity::CONFIG_NEVER : - break; - - case Entity::AUTO_ASSIGN_HARDWARE_CATEGORY : - if ($item != null) { - // Auto assign tech from item - if ((!isset($input['_users_id_assign']) || ($input['_users_id_assign'] == 0)) - && $item->isField('users_id_tech')) { - $input['_users_id_assign'] = $item->getField('users_id_tech'); - } - // Auto assign group from item - if ((!isset($input['_groups_id_assign']) || ($input['_groups_id_assign'] == 0)) - && $item->isField('groups_id_tech')) { - $input['_groups_id_assign'] = $item->getField('groups_id_tech'); - } - } - // Auto assign tech/group from Category - if (($input['itilcategories_id'] > 0) - && ((!isset($input['_users_id_assign']) || !$input['_users_id_assign']) - || (!isset($input['_groups_id_assign']) || !$input['_groups_id_assign']))) { - - $cat = new ITILCategory(); - $cat->getFromDB($input['itilcategories_id']); - if ((!isset($input['_users_id_assign']) || !$input['_users_id_assign']) - && $cat->isField('users_id')) { - $input['_users_id_assign'] = $cat->getField('users_id'); - } - if ((!isset($input['_groups_id_assign']) || !$input['_groups_id_assign']) - && $cat->isField('groups_id')) { - $input['_groups_id_assign'] = $cat->getField('groups_id'); - } - } - break; - - case Entity::AUTO_ASSIGN_CATEGORY_HARDWARE : - // Auto assign tech/group from Category - if (($input['itilcategories_id'] > 0) - && ((!isset($input['_users_id_assign']) || !$input['_users_id_assign']) - || (!isset($input['_groups_id_assign']) || !$input['_groups_id_assign']))) { - - $cat = new ITILCategory(); - $cat->getFromDB($input['itilcategories_id']); - if ((!isset($input['_users_id_assign']) || !$input['_users_id_assign']) - && $cat->isField('users_id')) { - $input['_users_id_assign'] = $cat->getField('users_id'); - } - if ((!isset($input['_groups_id_assign']) || !$input['_groups_id_assign']) - && $cat->isField('groups_id')) { - $input['_groups_id_assign'] = $cat->getField('groups_id'); - } - } - if ($item != null) { - // Auto assign tech from item - if ((!isset($input['_users_id_assign']) || ($input['_users_id_assign'] == 0)) - && $item->isField('users_id_tech')) { - $input['_users_id_assign'] = $item->getField('users_id_tech'); - } - // Auto assign group from item - if ((!isset($input['_groups_id_assign']) || ($input['_groups_id_assign'] == 0)) - && $item->isField('groups_id_tech')) { - $input['_groups_id_assign'] = $item->getField('groups_id_tech'); - } - } - break; - } - - // Replay setting auto assign if set in rules engine or by auto_assign_mode - // Do not force status if status has been set by rules - if (((isset($input["_users_id_assign"]) - && ((!is_array($input['_users_id_assign']) && $input["_users_id_assign"] > 0) - || is_array($input['_users_id_assign']) && count($input['_users_id_assign']) > 0)) - || (isset($input["_groups_id_assign"]) - && ((!is_array($input['_groups_id_assign']) && $input["_groups_id_assign"] > 0) - || is_array($input['_groups_id_assign']) && count($input['_groups_id_assign']) > 0)) - || (isset($input["_suppliers_id_assign"]) - && ((!is_array($input['_suppliers_id_assign']) && $input["_suppliers_id_assign"] > 0) - || is_array($input['_suppliers_id_assign']) && count($input['_suppliers_id_assign']) > 0))) - && (in_array($input['status'], $this->getNewStatusArray())) - && !$this->isStatusComputationBlocked($input)) { - $input["status"] = self::ASSIGNED; - } - - // Manage SLA / OLA asignment - // Manual SLA / OLA defined : reset due date - // No manual SLA / OLA and due date defined : reset auto SLA / OLA - foreach ([SLM::TTR, SLM::TTO] as $slmType) { - $this->slaAffect($slmType, $input, $manual_slas_id); - $this->olaAffect($slmType, $input, $manual_olas_id); - } - - // auto set type if not set - if (!isset($input["type"])) { - $input['type'] = Entity::getUsedConfig('tickettype', $input['entities_id'], '', - Ticket::INCIDENT_TYPE); - } - - return $input; - } - - - function post_addItem() { - global $CFG_GLPI; - - $this->manageValidationAdd($this->input); - - // Log this event - $username = 'anonymous'; - if (isset($_SESSION["glpiname"])) { - $username = $_SESSION["glpiname"]; - } - Event::log($this->fields['id'], "ticket", 4, "tracking", - sprintf(__('%1$s adds the item %2$s'), $username, - $this->fields['id'])); - - if (isset($this->input["_followup"]) - && is_array($this->input["_followup"]) - && (strlen($this->input["_followup"]['content']) > 0)) { - - $fup = new ITILFollowup(); - $type = "new"; - if (isset($this->fields["status"]) && ($this->fields["status"] == self::SOLVED)) { - $type = "solved"; - } - $toadd = ['type' => $type, - 'items_id' => $this->fields['id'], - 'itemtype' => 'Ticket']; - - if (isset($this->input["_followup"]['content']) - && (strlen($this->input["_followup"]['content']) > 0)) { - $toadd["content"] = $this->input["_followup"]['content']; - } - - if (isset($this->input["_followup"]['is_private'])) { - $toadd["is_private"] = $this->input["_followup"]['is_private']; - } - // $toadd['_no_notif'] = true; - - $fup->add($toadd); - } - - if ((isset($this->input["plan"]) && count($this->input["plan"])) - || (isset($this->input["actiontime"]) && ($this->input["actiontime"] > 0))) { - - $task = new TicketTask(); - $type = "new"; - if (isset($this->fields["status"]) && ($this->fields["status"] == self::SOLVED)) { - $type = "solved"; - } - $toadd = ["type" => $type, - "tickets_id" => $this->fields['id'], - "actiontime" => $this->input["actiontime"]]; - - if (isset($this->input["plan"]) && count($this->input["plan"])) { - $toadd["plan"] = $this->input["plan"]; - } - - if (isset($_SESSION['glpitask_private'])) { - $toadd['is_private'] = $_SESSION['glpitask_private']; - } - - // $toadd['_no_notif'] = true; - - $task->add($toadd); - } - - $ticket_ticket = new Ticket_Ticket(); - - // From interface - if (isset($this->input['_link'])) { - $this->input['_link']['tickets_id_1'] = $this->fields['id']; - // message if ticket's ID doesn't exist - if (!empty($this->input['_link']['tickets_id_2'])) { - if ($ticket_ticket->can(-1, CREATE, $this->input['_link'])) { - $ticket_ticket->add($this->input['_link']); - } else { - Session::addMessageAfterRedirect(__('Unknown ticket'), false, ERROR); - } - } - } - - // From mailcollector : do not check rights - if (isset($this->input["_linkedto"])) { - $input2 = [ - 'tickets_id_1' => $this->fields['id'], - 'tickets_id_2' => $this->input["_linkedto"], - 'link' => Ticket_Ticket::LINK_TO, - ]; - $ticket_ticket->add($input2); - } - - // Manage SLA / OLA Level : add actions - foreach ([SLM::TTR, SLM::TTO] as $slmType) { - list($dateField, $slaField) = SLA::getFieldNames($slmType); - if (isset($this->input[$slaField]) && ($this->input[$slaField] > 0)) { - $this->manageSlaLevel($this->input[$slaField]); - } - list($dateField, $olaField) = OLA::getFieldNames($slmType); - if (isset($this->input[$olaField]) && ($this->input[$olaField] > 0)) { - $this->manageOlaLevel($this->input[$olaField]); - } - } - - // Add project task link if needed - if (isset($this->input['_projecttasks_id'])) { - $projecttask = new ProjectTask(); - if ($projecttask->getFromDB($this->input['_projecttasks_id'])) { - $pt = new ProjectTask_Ticket(); - $pt->add(['projecttasks_id' => $this->input['_projecttasks_id'], - 'tickets_id' => $this->fields['id'], - /*'_no_notif' => true*/]); - } - } - - if (isset($this->input['_promoted_fup_id']) && $this->input['_promoted_fup_id'] > 0) { - $fup = new ITILFollowup(); - $fup->getFromDB($this->input['_promoted_fup_id']); - $fup->update([ - 'id' => $this->input['_promoted_fup_id'], - 'sourceof_items_id' => $this->getID() - ]); - Event::log($this->getID(), "ticket", 4, "tracking", - sprintf(__('%s promotes a followup from ticket %s'), $_SESSION["glpiname"], $fup->fields['items_id'])); - } - - if (!empty($this->input['items_id'])) { - $item_ticket = new Item_Ticket(); - foreach ($this->input['items_id'] as $itemtype => $items) { - foreach ($items as $items_id) { - $item_ticket->add(['items_id' => $items_id, - 'itemtype' => $itemtype, - 'tickets_id' => $this->fields['id'], - '_disablenotif' => true]); - } - } - } - - parent::post_addItem(); - - // Processing Email - if (!isset($this->input['_disablenotif']) && $CFG_GLPI["use_notifications"]) { - // Clean reload of the ticket - $this->getFromDB($this->fields['id']); - - $type = "new"; - if (isset($this->fields["status"]) && ($this->fields["status"] == self::SOLVED)) { - $type = "solved"; - } - NotificationEvent::raiseEvent($type, $this); - } - - if (isset($_SESSION['glpiis_ids_visible']) && !$_SESSION['glpiis_ids_visible']) { - Session::addMessageAfterRedirect(sprintf(__('%1$s (%2$s)'), - __('Your ticket has been registered, its treatment is in progress.'), - sprintf(__('%1$s: %2$s'), __('Ticket'), - "". - $this->fields['id'].""))); - } - - } - - - /** - * Manage Validation add from input - * - * @since 0.85 - * - * @param $input array : input array - * - * @return boolean - **/ - function manageValidationAdd($input) { - - //Action for send_validation rule - if (isset($input["_add_validation"])) { - if (isset($input['entities_id'])) { - $entid = $input['entities_id']; - } else if (isset($this->fields['entities_id'])) { - $entid = $this->fields['entities_id']; - } else { - return false; - } - - $validations_to_send = []; - if (!is_array($input["_add_validation"])) { - $input["_add_validation"] = [$input["_add_validation"]]; - } - - foreach ($input["_add_validation"] as $key => $validation) { - switch ($validation) { - case 'requester_supervisor' : - if (isset($input['_groups_id_requester']) - && $input['_groups_id_requester']) { - $users = Group_User::getGroupUsers( - $input['_groups_id_requester'], - ['is_manager' => 1] - ); - foreach ($users as $data) { - $validations_to_send[] = $data['id']; - } - } - // Add to already set groups - foreach ($this->getGroups(CommonITILActor::REQUESTER) as $d) { - $users = Group_User::getGroupUsers( - $d['groups_id'], - ['is_manager' => 1] - ); - foreach ($users as $data) { - $validations_to_send[] = $data['id']; - } - } - break; - - case 'assign_supervisor' : - if (isset($input['_groups_id_assign']) - && $input['_groups_id_assign']) { - $users = Group_User::getGroupUsers( - $input['_groups_id_assign'], - ['is_manager' => 1] - ); - foreach ($users as $data) { - $validations_to_send[] = $data['id']; - } - } - foreach ($this->getGroups(CommonITILActor::ASSIGN) as $d) { - $users = Group_User::getGroupUsers( - $d['groups_id'], - ['is_manager' => 1] - ); - foreach ($users as $data) { - $validations_to_send[] = $data['id']; - } - } - break; - - case 'requester_responsible': - if (isset($input['_users_id_requester'])) { - if (is_array($input['_users_id_requester'])) { - foreach ($input['_users_id_requester'] as $users_id) { - $user = new User(); - if ($user->getFromDB($users_id)) { - $validations_to_send[] = $user->getField('users_id_supervisor'); - } - } - } else { - $user = new User(); - if ($user->getFromDB($input['_users_id_requester'])) { - $validations_to_send[] = $user->getField('users_id_supervisor'); - } - } - } - break; - - default : - // Group case from rules - if ($key === 'group') { - foreach ($validation as $groups_id) { - $validation_right = 'validate_incident'; - if (isset($input['type']) - && ($input['type'] == Ticket::DEMAND_TYPE)) { - $validation_right = 'validate_request'; - } - $opt = ['groups_id' => $groups_id, - 'right' => $validation_right, - 'entity' => $entid]; - - $data_users = TicketValidation::getGroupUserHaveRights($opt); - - foreach ($data_users as $user) { - $validations_to_send[] = $user['id']; - } - } - } else { - $validations_to_send[] = $validation; - } - } - - } - - // Validation user added on ticket form - if (isset($input['users_id_validate'])) { - if (array_key_exists('groups_id', $input['users_id_validate'])) { - foreach ($input['users_id_validate'] as $key => $validation_to_add) { - if (is_numeric($key)) { - $validations_to_send[] = $validation_to_add; - } - } - } else { - foreach ($input['users_id_validate'] as $key => $validation_to_add) { - if (is_numeric($key)) { - $validations_to_send[] = $validation_to_add; - } - } - } - } - - // Keep only one - $validations_to_send = array_unique($validations_to_send); - - $validation = new TicketValidation(); - - if (count($validations_to_send)) { - $values = []; - $values['tickets_id'] = $this->fields['id']; - if (isset($input['id']) && $input['id'] != $this->fields['id']) { - $values['_ticket_add'] = true; - } - - // to know update by rules - if (isset($input["_rule_process"])) { - $values['_rule_process'] = $input["_rule_process"]; - } - // if auto_import, tranfert it for validation - if (isset($input['_auto_import'])) { - $values['_auto_import'] = $input['_auto_import']; - } - - // Cron or rule process of hability to do - if (Session::isCron() - || isset($input["_auto_import"]) - || isset($input["_rule_process"]) - || $validation->can(-1, CREATE, $values)) { // cron or allowed user - - $add_done = false; - foreach ($validations_to_send as $user) { - // Do not auto add twice same validation - if (!TicketValidation::alreadyExists($values['tickets_id'], $user)) { - $values["users_id_validate"] = $user; - if ($validation->add($values)) { - $add_done = true; - } - } - } - if ($add_done) { - Event::log($this->fields['id'], "ticket", 4, "tracking", - sprintf(__('%1$s updates the item %2$s'), $_SESSION["glpiname"], - $this->fields['id'])); - } - } - } - } - return true; - } - - - /** - * Get active or solved tickets for an hardware last X days - * - * @since 0.83 - * - * @param $itemtype string Item type - * @param $items_id integer ID of the Item - * @param $days integer day number - * - * @return array - **/ - function getActiveOrSolvedLastDaysTicketsForItem($itemtype, $items_id, $days) { - global $DB; - - $result = []; - - $iterator = $DB->request([ - 'FROM' => $this->getTable(), - 'LEFT JOIN' => [ - 'glpi_items_tickets' => [ - 'ON' => [ - 'glpi_items_tickets' => 'tickets_id', - $this->getTable() => 'id' - ] - ] - ], - 'WHERE' => [ - 'glpi_items_tickets.items_id' => $items_id, - 'glpi_items_tickets.itemtype' => $itemtype, - 'OR' => [ - [ - 'NOT' => [ - $this->getTable() . '.status' => array_merge( - $this->getClosedStatusArray(), - $this->getSolvedStatusArray() - ) - ] - ], - [ - 'NOT' => [$this->getTable() . '.solvedate' => null], - new \QueryExpression( - "ADDDATE(" . $DB->quoteName($this->getTable()) . - ".".$DB->quoteName('solvedate').", INTERVAL $days DAY) > NOW()" - ) - ] - ] - ] - ]); - - while ($tick = $iterator->next()) { - $result[$tick['id']] = $tick['name']; - } - - return $result; - } - - - /** - * Count active tickets for an hardware - * - * @since 0.83 - * - * @param $itemtype string Item type - * @param $items_id integer ID of the Item - * - * @return integer - **/ - function countActiveTicketsForItem($itemtype, $items_id) { - global $DB; - - $result = $DB->request([ - 'COUNT' => 'cpt', - 'FROM' => $this->getTable(), - 'LEFT JOIN' => [ - 'glpi_items_tickets' => [ - 'ON' => [ - 'glpi_items_tickets' => 'tickets_id', - $this->getTable() => 'id' - ] - ] - ], - 'WHERE' => [ - 'glpi_items_tickets.itemtype' => $itemtype, - 'glpi_items_tickets.items_id' => $items_id, - 'NOT' => [ - $this->getTable() . '.status' => array_merge( - $this->getSolvedStatusArray(), - $this->getClosedStatusArray() - ) - ] - ] - ])->next(); - return $result['cpt']; - } - - /** - * Get active tickets for an item - * - * @since 9.5 - * - * @param string $itemtype Item type - * @param integer $items_id ID of the Item - * @param string $type Type of the tickets (incident or request) - * - * @return DBmysqlIterator - */ - public function getActiveTicketsForItem($itemtype, $items_id, $type) { - global $DB; - - return $DB->request([ - 'SELECT' => [ - $this->getTable() . '.id', - $this->getTable() . '.name', - $this->getTable() . '.priority', - ], - 'FROM' => $this->getTable(), - 'LEFT JOIN' => [ - 'glpi_items_tickets' => [ - 'ON' => [ - 'glpi_items_tickets' => 'tickets_id', - $this->getTable() => 'id' - ] - ] - ], - 'WHERE' => [ - 'glpi_items_tickets.itemtype' => $itemtype, - 'glpi_items_tickets.items_id' => $items_id, - $this->getTable() . '.is_deleted' => 0, - $this->getTable() . '.type' => $type, - 'NOT' => [ - $this->getTable() . '.status' => array_merge( - $this->getSolvedStatusArray(), - $this->getClosedStatusArray() - ) - ] - ] - ]); - } - - /** - * Count solved tickets for an hardware last X days - * - * @since 0.83 - * - * @param $itemtype string Item type - * @param $items_id integer ID of the Item - * @param $days integer day number - * - * @return integer - **/ - function countSolvedTicketsForItemLastDays($itemtype, $items_id, $days) { - global $DB; - - $result = $DB->request([ - 'COUNT' => 'cpt', - 'FROM' => $this->getTable(), - 'LEFT JOIN' => [ - 'glpi_items_tickets' => [ - 'ON' => [ - 'glpi_items_tickets' => 'tickets_id', - $this->getTable() => 'id' - ] - ] - ], - 'WHERE' => [ - 'glpi_items_tickets.itemtype' => $itemtype, - 'glpi_items_tickets.items_id' => $items_id, - $this->getTable() . '.status' => array_merge( - $this->getSolvedStatusArray(), - $this->getClosedStatusArray() - ), - new \QueryExpression( - "ADDDATE(".$DB->quoteName($this->getTable().".solvedate").", INTERVAL $days DAY) > NOW()" - ), - 'NOT' => [ - $this->getTable() . '.solvedate' => null - ] - ] - ])->next(); - return $result['cpt']; - } - - - /** - * Update date mod of the ticket - * - * @since 0.83.3 new proto - * - * @param $ID ID of the ticket - * @param $no_stat_computation boolean do not cumpute take into account stat (false by default) - * @param $users_id_lastupdater integer to force last_update id (default 0 = not used) - **/ - function updateDateMod($ID, $no_stat_computation = false, $users_id_lastupdater = 0) { - - if ($this->getFromDB($ID)) { - if (!$no_stat_computation - && !$this->isAlreadyTakenIntoAccount() - && ($this->canTakeIntoAccount() || isCommandLine())) { - return $this->update( - [ - 'id' => $ID, - 'takeintoaccount_delay_stat' => $this->computeTakeIntoAccountDelayStat(), - '_disablenotif' => true - ] - ); - } - - parent::updateDateMod($ID, $no_stat_computation, $users_id_lastupdater); - } - } - - - /** - * Overloaded from commonDBTM - * - * @since 0.83 - * - * @param $type itemtype of object to add - * - * @return rights - **/ - function canAddItem($type) { - - if ($type == 'Document') { - if ($this->getField('status') == self::CLOSED) { - return false; - } - - if ($this->canAddFollowups()) { - return true; - } - } - - // as self::canUpdate & $this->canUpdateItem checks more general rights - // (like STEAL or OWN), - // we specify only the rights needed for this action - return $this->checkEntity() - && (Session::haveRight(self::$rightname, UPDATE) - || $this->canRequesterUpdateItem()); - } - - - /** - * Check if user can add followups to the ticket. - * - * @param integer $user_id - * - * @return boolean - */ - public function canUserAddFollowups($user_id) { - - $entity_id = $this->fields['entities_id']; - - $group_user = new Group_User(); - $user_groups = $group_user->getUserGroups($user_id, ['entities_id' => $entity_id]); - $user_groups_ids = []; - foreach ($user_groups as $user_group) { - $user_groups_ids[] = $user_group['id']; - } - - $rightname = ITILFollowup::$rightname; - - return ( - Profile::haveUserRight($user_id, $rightname, ITILFollowup::ADDMYTICKET, $entity_id) - && ($this->isUser(CommonITILActor::REQUESTER, $user_id) - || ( - isset($this->fields['users_id_recipient']) - && ($this->fields['users_id_recipient'] === $user_id) - ) - ) - ) - || Profile::haveUserRight($user_id, $rightname, ITILFollowup::ADDALLTICKET, $entity_id) - || ( - Profile::haveUserRight($user_id, $rightname, ITILFollowup::ADDGROUPTICKET, $entity_id) - && $this->haveAGroup(CommonITILActor::REQUESTER, $user_groups_ids) - ) - || $this->isUser(CommonITILActor::ASSIGN, Session::getLoginUserID()) - || $this->haveAGroup(CommonITILActor::ASSIGN, $user_groups_ids); - } - - - /** - * Get default values to search engine to override - **/ - static function getDefaultSearchRequest() { - - $search = ['criteria' => [0 => ['field' => 12, - 'searchtype' => 'equals', - 'value' => 'notclosed']], - 'sort' => 19, - 'order' => 'DESC']; - - if (Session::haveRight(self::$rightname, self::READALL)) { - $search['criteria'][0]['value'] = 'notold'; - } - return $search; - } - - - /** - * @see CommonDBTM::getSpecificMassiveActions() - **/ - function getSpecificMassiveActions($checkitem = null) { - - $actions = []; - - if (Session::getCurrentInterface() == 'central') { - if (Ticket::canUpdate() && Ticket::canDelete()) { - $actions[__CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'merge_as_followup'] - = "". - __('Merge as Followup'); - } - - if (Item_Ticket::canCreate()) { - $actions['Item_Ticket'.MassiveAction::CLASS_ACTION_SEPARATOR.'add_item'] - = "". - _x('button', 'Add an item'); - } - - if (ITILFollowup::canCreate()) { - $actions['ITILFollowup'.MassiveAction::CLASS_ACTION_SEPARATOR.'add_followup'] - = "". - __('Add a new followup'); - } - - if (TicketTask::canCreate()) { - $actions[__CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'add_task'] - = "". - __('Add a new task'); - } - - if (TicketValidation::canCreate()) { - $actions['TicketValidation'.MassiveAction::CLASS_ACTION_SEPARATOR.'submit_validation'] - = "". - __('Approval request'); - } - - if (Item_Ticket::canDelete()) { - $actions['Item_Ticket'.MassiveAction::CLASS_ACTION_SEPARATOR.'delete_item'] - = _x('button', 'Remove an item'); - } - - if (Session::haveRight(self::$rightname, UPDATE)) { - $actions[__CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'add_actor'] - = "". - __('Add an actor'); - $actions[__CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'update_notif'] - = __('Set notifications for all actors'); - $actions['Ticket_Ticket'.MassiveAction::CLASS_ACTION_SEPARATOR.'add'] - = "". - _x('button', 'Link tickets'); - - KnowbaseItem_Item::getMassiveActionsForItemtype($actions, __CLASS__, 0, $checkitem); - } - } - - $actions += parent::getSpecificMassiveActions($checkitem); - - return $actions; - } - - - static function showMassiveActionsSubForm(MassiveAction $ma) { - switch ($ma->getAction()) { - case 'merge_as_followup' : - $rand = mt_rand(); - $mergeparam = [ - 'name' => "_mergeticket", - 'used' => $ma->items['Ticket'], - 'displaywith' => ['id'], - 'rand' => $rand - ]; - echo ""; - echo "
"; - Ticket::dropdown($mergeparam); - echo "
"; - Html::showCheckbox([ - 'name' => 'with_followups', - 'id' => 'with_followups', - 'checked' => true - ]); - echo ""; - Html::showCheckbox([ - 'name' => 'with_documents', - 'id' => 'with_documents', - 'checked' => true - ]); - echo "
"; - Html::showCheckbox([ - 'name' => 'with_tasks', - 'id' => 'with_tasks', - 'checked' => true - ]); - echo ""; - Html::showCheckbox([ - 'name' => 'with_actors', - 'id' => 'with_actors', - 'checked' => true - ]); - echo "
"; - Dropdown::showFromArray('link_type', [ - 0 => __('None'), - Ticket_Ticket::LINK_TO => __('Linked to'), - Ticket_Ticket::DUPLICATE_WITH => __('Duplicates'), - Ticket_Ticket::SON_OF => __('Son of'), - Ticket_Ticket::PARENT_OF => __('Parent of') - ], ['value' => Ticket_Ticket::SON_OF, 'rand' => $rand]); - echo "
"; - echo Html::submit(_x('button', 'Merge'), [ - 'name' => 'merge', - 'confirm' => __('Confirm the merge? This ticket will be deleted!') - ]); - echo "
"; - return true; - } - return parent::showMassiveActionsSubForm($ma); - } - - - static function processMassiveActionsForOneItemtype(MassiveAction $ma, CommonDBTM $item, - array $ids) { - switch ($ma->getAction()) { - case 'merge_as_followup' : - $input = $ma->getInput(); - $status = []; - $mergeparams = [ - 'linktypes' => [], - 'link_type' => $input['link_type'] - ]; - - if ($input['with_followups']) { - $mergeparams['linktypes'][] = 'ITILFollowup'; - } - if ($input['with_tasks']) { - $mergeparams['linktypes'][] = 'TicketTask'; - } - if ($input['with_documents']) { - $mergeparams['linktypes'][] = 'Document'; - } - if ($input['with_actors']) { - $mergeparams['append_actors'] = [ - CommonITILActor::REQUESTER, - CommonITILActor::OBSERVER, - CommonITILActor::ASSIGN]; - } else { - $mergeparams['append_actors'] = []; - } - - Ticket::merge($input['_mergeticket'], $ids, $status, $mergeparams); - foreach ($status as $id => $status_code) { - if ($status_code == 0) { - $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_OK); - } else if ($status_code == 2) { - $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_NORIGHT); - $ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION)); - } else { - $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO); - $ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION)); - } - } - return; - } - parent::processMassiveActionsForOneItemtype($ma, $item, $ids); - } - - - function rawSearchOptions() { - global $DB; - - $tab = []; - - $tab = array_merge($tab, $this->getSearchOptionsMain()); - - $tab[] = [ - 'id' => '155', - 'table' => $this->getTable(), - 'field' => 'time_to_own', - 'name' => __('Time to own'), - 'datatype' => 'datetime', - 'maybefuture' => true, - 'massiveaction' => false, - 'additionalfields' => ['status'] - ]; - - $tab[] = [ - 'id' => '158', - 'table' => $this->getTable(), - 'field' => 'time_to_own', - 'name' => __('Time to own + Progress'), - 'massiveaction' => false, - 'nosearch' => true, - 'additionalfields' => ['status'] - ]; - - $tab[] = [ - 'id' => '159', - 'table' => 'glpi_tickets', - 'field' => 'is_late', - 'name' => __('Time to own exceedeed'), - 'datatype' => 'bool', - 'massiveaction' => false, - 'computation' => 'IF('.$DB->quoteName('TABLE.time_to_own').' IS NOT NULL - AND '.$DB->quoteName('TABLE.status').' <> '.self::WAITING.' - AND ('.$DB->quoteName('TABLE.takeintoaccount_delay_stat').' - > TIME_TO_SEC(TIMEDIFF('.$DB->quoteName('TABLE.time_to_own').', - '.$DB->quoteName('TABLE.date').')) - OR ('.$DB->quoteName('TABLE.takeintoaccount_delay_stat').' = 0 - AND '.$DB->quoteName('TABLE.time_to_own').' < NOW())), - 1, 0)' - ]; - - $tab[] = [ - 'id' => '180', - 'table' => $this->getTable(), - 'field' => 'internal_time_to_resolve', - 'name' => __('Internal time to resolve'), - 'datatype' => 'datetime', - 'maybefuture' => true, - 'massiveaction' => false, - 'additionalfields' => ['status'] - ]; - - $tab[] = [ - 'id' => '181', - 'table' => $this->getTable(), - 'field' => 'internal_time_to_resolve', - 'name' => __('Internal time to resolve + Progress'), - 'massiveaction' => false, - 'nosearch' => true, - 'additionalfields' => ['status'] - ]; - - $tab[] = [ - 'id' => '182', - 'table' => $this->getTable(), - 'field' => 'is_late', - 'name' => __('Internal time to resolve exceedeed'), - 'datatype' => 'bool', - 'massiveaction' => false, - 'computation' => 'IF('.$DB->quoteName('TABLE.internal_time_to_resolve').' IS NOT NULL - AND '.$DB->quoteName('TABLE.status').' <> 4 - AND ('.$DB->quoteName('TABLE.solvedate').' > '.$DB->quoteName('TABLE.internal_time_to_resolve').' - OR ('.$DB->quoteName('TABLE.solvedate').' IS NULL - AND '.$DB->quoteName('TABLE.internal_time_to_resolve').' < NOW())), - 1, 0)' - ]; - - $tab[] = [ - 'id' => '185', - 'table' => $this->getTable(), - 'field' => 'internal_time_to_own', - 'name' => __('Internal time to own'), - 'datatype' => 'datetime', - 'maybefuture' => true, - 'massiveaction' => false, - 'additionalfields' => ['status'] - ]; - - $tab[] = [ - 'id' => '186', - 'table' => $this->getTable(), - 'field' => 'internal_time_to_own', - 'name' => __('Internal time to own + Progress'), - 'massiveaction' => false, - 'nosearch' => true, - 'additionalfields' => ['status'] - ]; - - $tab[] = [ - 'id' => '187', - 'table' => 'glpi_tickets', - 'field' => 'is_late', - 'name' => __('Internal time to own exceedeed'), - 'datatype' => 'bool', - 'massiveaction' => false, - 'computation' => 'IF('.$DB->quoteName('TABLE.internal_time_to_own').' IS NOT NULL - AND '.$DB->quoteName('TABLE.status').' <> '.self::WAITING.' - AND ('.$DB->quoteName('TABLE.takeintoaccount_delay_stat').' - > TIME_TO_SEC(TIMEDIFF('.$DB->quoteName('TABLE.internal_time_to_own').', - '.$DB->quoteName('TABLE.date').')) - OR ('.$DB->quoteName('TABLE.takeintoaccount_delay_stat').' = 0 - AND '.$DB->quoteName('TABLE.internal_time_to_own').' < NOW())), - 1, 0)' - ]; - - $max_date = '99999999'; - $tab[] = [ - 'id' => '188', - 'table' => $this->getTable(), - 'field' => 'next_escalation_level', - 'name' => __('Next escalation level'), - 'datatype' => 'datetime', - 'usehaving' => true, - 'maybefuture' => true, - 'massiveaction' => false, - // Get least value from TTO/TTR fields: - // - use TTO fields only if ticket not already taken into account, - // - use TTR fields only if ticket not already solved, - // - replace NULL or not kept values with 99999999 to be sure that they will not be returned by the LEAST function, - // - replace 99999999 by empty string to keep only valid values. - 'computation' => "REPLACE( - LEAST( - IF(".$DB->quoteName('TABLE.takeintoaccount_delay_stat')." <= 0, - COALESCE(".$DB->quoteName('TABLE.time_to_own').", $max_date), - $max_date), - IF(".$DB->quoteName('TABLE.takeintoaccount_delay_stat')." <= 0, - COALESCE(".$DB->quoteName('TABLE.internal_time_to_own').", $max_date), - $max_date), - IF(".$DB->quoteName('TABLE.solvedate')." IS NULL, - COALESCE(".$DB->quoteName('TABLE.time_to_resolve').", $max_date), - $max_date), - IF(".$DB->quoteName('TABLE.solvedate')." IS NULL, - COALESCE(".$DB->quoteName('TABLE.internal_time_to_resolve').", $max_date), - $max_date) - ), $max_date, '')" - ]; - - $tab[] = [ - 'id' => '14', - 'table' => $this->getTable(), - 'field' => 'type', - 'name' => __('Type'), - 'searchtype' => 'equals', - 'datatype' => 'specific' - ]; - - $tab[] = [ - 'id' => '13', - 'table' => 'glpi_items_tickets', - 'field' => 'items_id', - 'name' => _n('Associated element', 'Associated elements', Session::getPluralNumber()), - 'datatype' => 'specific', - 'comments' => true, - 'nosort' => true, - 'nosearch' => true, - 'additionalfields' => ['itemtype'], - 'joinparams' => [ - 'jointype' => 'child' - ], - 'forcegroupby' => true, - 'massiveaction' => false - ]; - - $tab[] = [ - 'id' => '131', - 'table' => 'glpi_items_tickets', - 'field' => 'itemtype', - 'name' => _n('Associated item type', 'Associated item types', Session::getPluralNumber()), - 'datatype' => 'itemtypename', - 'itemtype_list' => 'ticket_types', - 'nosort' => true, - 'additionalfields' => ['itemtype'], - 'joinparams' => [ - 'jointype' => 'child' - ], - 'forcegroupby' => true, - 'massiveaction' => false - ]; - - $tab[] = [ - 'id' => '9', - 'table' => 'glpi_requesttypes', - 'field' => 'name', - 'name' => __('Request source'), - 'datatype' => 'dropdown' - ]; - - $location_so = Location::rawSearchOptionsToAdd(); - foreach ($location_so as &$so) { - //duplicated search options :( - switch ($so['id']) { - case 3: - $so['id'] = 83; - break; - case 91: - $so['id'] = 84; - break; - case 92: - $so['id'] = 85; - break; - case 93: - $so['id'] = 86; - break; - } - } - $tab = array_merge($tab, $location_so); - - $tab = array_merge($tab, $this->getSearchOptionsActors()); - - $tab[] = [ - 'id' => 'sla', - 'name' => __('SLA') - ]; - - $tab[] = [ - 'id' => '37', - 'table' => 'glpi_slas', - 'field' => 'name', - 'linkfield' => 'slas_id_tto', - 'name' => __('SLA')." ".__('Time to own'), - 'massiveaction' => false, - 'datatype' => 'dropdown', - 'joinparams' => [ - 'condition' => "AND NEWTABLE.`type` = '".SLM::TTO."'" - ], - 'condition' => "`glpi_slas`.`type` = '".SLM::TTO."'" - ]; - - $tab[] = [ - 'id' => '30', - 'table' => 'glpi_slas', - 'field' => 'name', - 'linkfield' => 'slas_id_ttr', - 'name' => __('SLA')." ".__('Time to resolve'), - 'massiveaction' => false, - 'datatype' => 'dropdown', - 'joinparams' => [ - 'condition' => "AND NEWTABLE.`type` = '".SLM::TTR."'" - ], - 'condition' => "`glpi_slas`.`type` = '".SLM::TTR."'" - ]; - - $tab[] = [ - 'id' => '32', - 'table' => 'glpi_slalevels', - 'field' => 'name', - 'name' => __('SLA')." ".__('Escalation level'), - 'massiveaction' => false, - 'datatype' => 'dropdown', - 'joinparams' => [ - 'beforejoin' => [ - 'table' => 'glpi_slalevels_tickets', - 'joinparams' => [ - 'jointype' => 'child' - ] - ] - ], - 'forcegroupby' => true - ]; - - $tab[] = [ - 'id' => 'ola', - 'name' => __('OLA') - ]; - - $tab[] = [ - 'id' => '190', - 'table' => 'glpi_olas', - 'field' => 'name', - 'linkfield' => 'olas_id_tto', - 'name' => __('OLA')." ".__('Internal time to own'), - 'massiveaction' => false, - 'datatype' => 'dropdown', - 'joinparams' => [ - 'condition' => "AND NEWTABLE.`type` = '".SLM::TTO."'" - ], - 'condition' => "`glpi_olas`.`type` = '".SLM::TTO."'" - ]; - - $tab[] = [ - 'id' => '191', - 'table' => 'glpi_olas', - 'field' => 'name', - 'linkfield' => 'olas_id_ttr', - 'name' => __('OLA')." ".__('Internal time to resolve'), - 'massiveaction' => false, - 'datatype' => 'dropdown', - 'joinparams' => [ - 'condition' => "AND NEWTABLE.`type` = '".SLM::TTR."'" - ], - 'condition' => "`glpi_olas`.`type` = '".SLM::TTR."'" - ]; - - $tab[] = [ - 'id' => '192', - 'table' => 'glpi_olalevels', - 'field' => 'name', - 'name' => __('OLA')." ".__('Escalation level'), - 'massiveaction' => false, - 'datatype' => 'dropdown', - 'joinparams' => [ - 'beforejoin' => [ - 'table' => 'glpi_olalevels_tickets', - 'joinparams' => [ - 'jointype' => 'child' - ] - ] - ], - 'forcegroupby' => true - ]; - - $validation_options = TicketValidation::rawSearchOptionsToAdd(); - if (!Session::haveRightsOr( - 'ticketvalidation', - [ - TicketValidation::CREATEINCIDENT, - TicketValidation::CREATEREQUEST - ] - )) { - foreach ($validation_options as &$validation_option) { - if (isset($validation_option['table'])) { - $validation_option['massiveaction'] = false; - } - } - } - $tab = array_merge($tab, $validation_options); - - $tab[] = [ - 'id' => 'satisfaction', - 'name' => __('Satisfaction survey') - ]; - - $tab[] = [ - 'id' => '31', - 'table' => 'glpi_ticketsatisfactions', - 'field' => 'type', - 'name' => __('Type'), - 'massiveaction' => false, - 'searchtype' => ['equals', 'notequals'], - 'searchequalsonfield' => true, - 'joinparams' => [ - 'jointype' => 'child' - ], - 'datatype' => 'specific' - ]; - - $tab[] = [ - 'id' => '60', - 'table' => 'glpi_ticketsatisfactions', - 'field' => 'date_begin', - 'name' => __('Creation date'), - 'datatype' => 'datetime', - 'massiveaction' => false, - 'joinparams' => [ - 'jointype' => 'child' - ] - ]; - - $tab[] = [ - 'id' => '61', - 'table' => 'glpi_ticketsatisfactions', - 'field' => 'date_answered', - 'name' => __('Response date'), - 'datatype' => 'datetime', - 'massiveaction' => false, - 'joinparams' => [ - 'jointype' => 'child' - ] - ]; - - $tab[] = [ - 'id' => '62', - 'table' => 'glpi_ticketsatisfactions', - 'field' => 'satisfaction', - 'name' => __('Satisfaction'), - 'datatype' => 'number', - 'massiveaction' => false, - 'joinparams' => [ - 'jointype' => 'child' - ] - ]; - - $tab[] = [ - 'id' => '63', - 'table' => 'glpi_ticketsatisfactions', - 'field' => 'comment', - 'name' => __('Comments'), - 'datatype' => 'text', - 'massiveaction' => false, - 'joinparams' => [ - 'jointype' => 'child' - ] - ]; - - $tab = array_merge($tab, ITILFollowup::rawSearchOptionsToAdd()); - - $tab = array_merge($tab, TicketTask::rawSearchOptionsToAdd()); - - $tab = array_merge($tab, $this->getSearchOptionsStats()); - - $tab[] = [ - 'id' => '150', - 'table' => $this->getTable(), - 'field' => 'takeintoaccount_delay_stat', - 'name' => __('Take into account time'), - 'datatype' => 'timestamp', - 'forcegroupby' => true, - 'massiveaction' => false - ]; - - if (Session::haveRightsOr(self::$rightname, - [self::READALL, self::READASSIGN, self::OWN])) { - $tab[] = [ - 'id' => 'linktickets', - 'name' => _n('Linked ticket', 'Linked tickets', Session::getPluralNumber()) - ]; - - $tab[] = [ - 'id' => '40', - 'table' => 'glpi_tickets_tickets', - 'field' => 'tickets_id_1', - 'name' => __('All linked tickets'), - 'massiveaction' => false, - 'forcegroupby' => true, - 'searchtype' => 'equals', - 'joinparams' => [ - 'jointype' => 'item_item' - ], - 'additionalfields' => ['tickets_id_2'] - ]; - - $tab[] = [ - 'id' => '47', - 'table' => 'glpi_tickets_tickets', - 'field' => 'tickets_id_1', - 'name' => __('Duplicated tickets'), - 'massiveaction' => false, - 'searchtype' => 'equals', - 'joinparams' => [ - 'jointype' => 'item_item', - 'condition' => 'AND NEWTABLE.`link` = '.Ticket_Ticket::DUPLICATE_WITH - ], - 'additionalfields' => ['tickets_id_2'], - 'forcegroupby' => true - ]; - - $tab[] = [ - 'id' => '41', - 'table' => 'glpi_tickets_tickets', - 'field' => 'id', - 'name' => __('Number of all linked tickets'), - 'massiveaction' => false, - 'datatype' => 'count', - 'usehaving' => true, - 'joinparams' => [ - 'jointype' => 'item_item' - ] - ]; - - $tab[] = [ - 'id' => '46', - 'table' => 'glpi_tickets_tickets', - 'field' => 'id', - 'name' => __('Number of duplicated tickets'), - 'massiveaction' => false, - 'datatype' => 'count', - 'usehaving' => true, - 'joinparams' => [ - 'jointype' => 'item_item', - 'condition' => 'AND NEWTABLE.`link` = '.Ticket_Ticket::DUPLICATE_WITH - ] - ]; - - $tab[] = [ - 'id' => '50', - 'table' => 'glpi_tickets', - 'field' => 'id', - 'linkfield' => 'tickets_id_2', - 'name' => __('Parent tickets'), - 'massiveaction' => false, - 'searchtype' => 'equals', - 'datatype' => 'itemlink', - 'usehaving' => true, - 'joinparams' => [ - 'beforejoin' => [ - 'table' => 'glpi_tickets_tickets', - 'joinparams' => [ - 'jointype' => 'child', - 'linkfield' => 'tickets_id_1', - 'condition' => 'AND NEWTABLE.`link` = '.Ticket_Ticket::SON_OF, - ] - ] - ], - 'forcegroupby' => true - ]; - - $tab[] = [ - 'id' => '67', - 'table' => 'glpi_tickets', - 'field' => 'id', - 'linkfield' => 'tickets_id_1', - 'name' => __('Child tickets'), - 'massiveaction' => false, - 'searchtype' => 'equals', - 'datatype' => 'itemlink', - 'usehaving' => true, - 'joinparams' => [ - 'beforejoin' => [ - 'table' => 'glpi_tickets_tickets', - 'joinparams' => [ - 'jointype' => 'child', - 'linkfield' => 'tickets_id_2', - 'condition' => 'AND NEWTABLE.`link` = '.Ticket_Ticket::SON_OF, - ] - ] - ], - 'forcegroupby' => true - ]; - - $tab[] = [ - 'id' => '68', - 'table' => 'glpi_tickets_tickets', - 'field' => 'id', - 'name' => __('Number of sons tickets'), - 'massiveaction' => false, - 'datatype' => 'count', - 'usehaving' => true, - 'joinparams' => [ - 'linkfield' => 'tickets_id_2', - 'jointype' => 'child', - 'condition' => 'AND NEWTABLE.`link` = '.Ticket_Ticket::SON_OF - ], - 'forcegroupby' => true - ]; - - $tab[] = [ - 'id' => '69', - 'table' => 'glpi_tickets_tickets', - 'field' => 'id', - 'name' => __('Number of parent tickets'), - 'massiveaction' => false, - 'datatype' => 'count', - 'usehaving' => true, - 'joinparams' => [ - 'linkfield' => 'tickets_id_1', - 'jointype' => 'child', - 'condition' => 'AND NEWTABLE.`link` = '.Ticket_Ticket::SON_OF - ], - 'additionalfields' => ['tickets_id_2'] - ]; - - $tab = array_merge($tab, $this->getSearchOptionsSolution()); - - if (Session::haveRight('ticketcost', READ)) { - $tab = array_merge($tab, TicketCost::rawSearchOptionsToAdd()); - } - } - - if (Session::haveRight('problem', READ)) { - $tab[] = [ - 'id' => 'problem', - 'name' => __('Problems') - ]; - - $tab[] = [ - 'id' => '141', - 'table' => 'glpi_problems_tickets', - 'field' => 'id', - 'name' => _x('quantity', 'Number of problems'), - 'forcegroupby' => true, - 'usehaving' => true, - 'datatype' => 'count', - 'massiveaction' => false, - 'joinparams' => [ - 'jointype' => 'child' - ] - ]; - } - - // Filter search fields for helpdesk - if (!Session::isCron() // no filter for cron - && (Session::getCurrentInterface() != 'central')) { - $tokeep = ['common', 'requester','satisfaction']; - if (Session::haveRightsOr('ticketvalidation', - array_merge(TicketValidation::getValidateRights(), - TicketValidation::getCreateRights()))) { - $tokeep[] = 'validation'; - } - $keep = false; - foreach ($tab as $key => &$val) { - if (!isset($val['table'])) { - $keep = in_array($val['id'], $tokeep); - } - if (!$keep) { - if (isset($val['table'])) { - $val['nosearch'] = true; - } - } - } - } - return $tab; - } - - - /** - * @since 0.84 - * - * @param $field - * @param $values - * @param $options array - **/ - static function getSpecificValueToDisplay($field, $values, array $options = []) { - - if (!is_array($values)) { - $values = [$field => $values]; - } - switch ($field) { - case 'content' : - $content = Toolbox::unclean_cross_side_scripting_deep(Html::entity_decode_deep($values[$field])); - $content = Html::clean($content); - if (empty($content)) { - $content = ' '; - } - return nl2br($content); - - case 'type': - return self::getTicketTypeName($values[$field]); - } - return parent::getSpecificValueToDisplay($field, $values, $options); - } - - - /** - * @since 0.84 - * - * @param $field - * @param $name (default '') - * @param $values (default '') - * @param $options array - * - * @return string - **/ - static function getSpecificValueToSelect($field, $name = '', $values = '', array $options = []) { - - if (!is_array($values)) { - $values = [$field => $values]; - } - $options['display'] = false; - switch ($field) { - case 'content' : - return ""; - - case 'type': - $options['value'] = $values[$field]; - return self::dropdownType($name, $options); - } - return parent::getSpecificValueToSelect($field, $name, $values, $options); - } - - - /** - * Dropdown of ticket type - * - * @param $name select name - * @param $options array of options: - * - value : integer / preselected value (default 0) - * - toadd : array / array of specific values to add at the begining - * - on_change : string / value to transmit to "onChange" - * - display : boolean / display or get string (default true) - * - * @return string id of the select - **/ - static function dropdownType($name, $options = []) { - - $params = [ - 'value' => 0, - 'toadd' => [], - 'on_change' => '', - 'display' => true, - ]; - - if (is_array($options) && count($options)) { - foreach ($options as $key => $val) { - $params[$key] = $val; - } - } - - $items = []; - if (count($params['toadd']) > 0) { - $items = $params['toadd']; - } - - $items += self::getTypes(); - - return Dropdown::showFromArray($name, $items, $params); - } - - - /** - * Get ticket types - * - * @return array of types - **/ - static function getTypes() { - - $options = [ - self::INCIDENT_TYPE => __('Incident'), - self::DEMAND_TYPE => __('Request'), - ]; - - return $options; - } - - - /** - * Get ticket type Name - * - * @param $value type ID - **/ - static function getTicketTypeName($value) { - - switch ($value) { - case self::INCIDENT_TYPE : - return __('Incident'); - - case self::DEMAND_TYPE : - return __('Request'); - - default : - // Return $value if not defined - return $value; - } - } - - - /** - * get the Ticket status list - * - * @param $withmetaforsearch boolean (false by default) - * - * @return array - **/ - static function getAllStatusArray($withmetaforsearch = false) { - - // To be overridden by class - $tab = [self::INCOMING => _x('status', 'New'), - self::ASSIGNED => _x('status', 'Processing (assigned)'), - self::PLANNED => _x('status', 'Processing (planned)'), - self::WAITING => __('Pending'), - self::SOLVED => _x('status', 'Solved'), - self::CLOSED => _x('status', 'Closed')]; - - if ($withmetaforsearch) { - $tab['notold'] = _x('status', 'Not solved'); - $tab['notclosed'] = _x('status', 'Not closed'); - $tab['process'] = __('Processing'); - $tab['old'] = _x('status', 'Solved + Closed'); - $tab['all'] = __('All'); - } - return $tab; - } - - - /** - * Get the ITIL object closed status list - * - * @since 0.83 - * - * @return array - **/ - static function getClosedStatusArray() { - return [self::CLOSED]; - } - - - /** - * Get the ITIL object solved status list - * - * @since 0.83 - * - * @return array - **/ - static function getSolvedStatusArray() { - return [self::SOLVED]; - } - - /** - * Get the ITIL object new status list - * - * @since 0.83.8 - * - * @return array - **/ - static function getNewStatusArray() { - return [self::INCOMING]; - } - - /** - * Get the ITIL object assign or plan status list - * - * @since 0.83 - * - * @return array - **/ - static function getProcessStatusArray() { - return [self::ASSIGNED, self::PLANNED]; - } - - - /** - * Calculate Ticket TCO for an item - * - *@param $item CommonDBTM object of the item - * - *@return float - **/ - static function computeTco(CommonDBTM $item) { - global $DB; - - $totalcost = 0; - - $iterator = $DB->request([ - 'SELECT' => 'glpi_ticketcosts.*', - 'FROM' => 'glpi_ticketcosts', - 'LEFT JOIN' => [ - 'glpi_items_tickets' => [ - 'ON' => [ - 'glpi_items_tickets' => 'tickets_id', - 'glpi_ticketcosts' => 'tickets_id' - ] - ] - ], - 'WHERE' => [ - 'glpi_items_tickets.itemtype' => get_class($item), - 'glpi_items_tickets.items_id' => $item->getField('id'), - 'OR' => [ - 'glpi_ticketcosts.cost_time' => ['>', 0], - 'glpi_ticketcosts.cost_fixed' => ['>', 0], - 'glpi_ticketcosts.cost_material' => ['>', 0] - ] - ] - ]); - - while ($data = $iterator->next()) { - $totalcost += TicketCost::computeTotalCost( - $data["actiontime"], - $data["cost_time"], - $data["cost_fixed"], - $data["cost_material"] - ); - } - return $totalcost; - } - - - /** - * Print the helpdesk form - * - * @param $ID integer ID of the user who want to display the Helpdesk - * @param $ticket_template boolean ticket template for preview : false if not used for preview - * (false by default) - * - * @return void - **/ - function showFormHelpdesk($ID, $ticket_template = false) { - global $CFG_GLPI; - - if (!self::canCreate()) { - return false; - } - - if (!$ticket_template - && Session::haveRightsOr('ticketvalidation', TicketValidation::getValidateRights())) { - - $opt = []; - $opt['reset'] = 'reset'; - $opt['criteria'][0]['field'] = 55; // validation status - $opt['criteria'][0]['searchtype'] = 'equals'; - $opt['criteria'][0]['value'] = CommonITILValidation::WAITING; - $opt['criteria'][0]['link'] = 'AND'; - - $opt['criteria'][1]['field'] = 59; // validation aprobator - $opt['criteria'][1]['searchtype'] = 'equals'; - $opt['criteria'][1]['value'] = Session::getLoginUserID(); - $opt['criteria'][1]['link'] = 'AND'; - - $url_validate = Ticket::getSearchURL()."?".Toolbox::append_params($opt, - '&'); - - if (TicketValidation::getNumberToValidate(Session::getLoginUserID()) > 0) { - echo "". - __('Tickets awaiting approval')."

"; - } - } - - $email = UserEmail::getDefaultForUser($ID); - $default_use_notif = Entity::getUsedConfig('is_notif_enable_default', $_SESSION['glpiactive_entity'], '', 1); - - // Set default values... - $default_values = ['_users_id_requester_notif' - => ['use_notification' - => (($email == "")?0:$default_use_notif)], - 'nodelegate' => 1, - '_users_id_requester' => 0, - '_users_id_observer' => [0], - '_users_id_observer_notif' - => ['use_notification' => $default_use_notif], - 'name' => '', - 'content' => '', - 'itilcategories_id' => 0, - 'locations_id' => 0, - 'urgency' => 3, - 'items_id' => 0, - 'entities_id' => $_SESSION['glpiactive_entity'], - 'plan' => [], - 'global_validation' => CommonITILValidation::NONE, - '_add_validation' => 0, - 'type' => Entity::getUsedConfig('tickettype', - $_SESSION['glpiactive_entity'], - '', Ticket::INCIDENT_TYPE), - '_right' => "id", - '_content' => [], - '_tag_content' => [], - '_filename' => [], - '_tag_filename' => [], - '_tasktemplates_id' => []]; - - // Get default values from posted values on reload form - if (!$ticket_template) { - if (isset($_POST)) { - $options = $_POST; - } - } - - if (isset($options['name'])) { - $order = ["\\'", '\\"', "\\\\"]; - $replace = ["'", '"', "\\"]; - $options['name'] = str_replace($order, $replace, $options['name']); - } - - // Restore saved value or override with page parameter - $saved = $this->restoreInput(); - foreach ($default_values as $name => $value) { - if (!isset($options[$name])) { - if (isset($saved[$name])) { - $options[$name] = $saved[$name]; - } else { - $options[$name] = $value; - } - } - } - - // Check category / type validity - if ($options['itilcategories_id']) { - $cat = new ITILCategory(); - if ($cat->getFromDB($options['itilcategories_id'])) { - switch ($options['type']) { - case self::INCIDENT_TYPE : - if (!$cat->getField('is_incident')) { - $options['itilcategories_id'] = 0; - } - break; - - case self::DEMAND_TYPE : - if (!$cat->getField('is_request')) { - $options['itilcategories_id'] = 0; - } - break; - - default : - break; - } - } - } - - // Load ticket template if available : - $tt = $this->getITILTemplateToUse($ticket_template, $options['type'], - $options['itilcategories_id'], - $_SESSION["glpiactive_entity"]); - - // Put ticket template on $options for actors - $options['_tickettemplate'] = $tt; - - if (!$ticket_template) { - echo "
"; - } - - $delegating = User::getDelegateGroupsForUser($options['entities_id']); - - if (count($delegating) || $CFG_GLPI['use_check_pref']) { - echo "
"; - } - - if (count($delegating)) { - echo ""; - echo ""; - - echo "
".__('This ticket concerns me')." "; - - $rand = Dropdown::showYesNo("nodelegate", $options['nodelegate']); - - $params = ['nodelegate' => '__VALUE__', - 'rand' => $rand, - 'right' => "delegate", - '_users_id_requester' - => $options['_users_id_requester'], - '_users_id_requester_notif' - => $options['_users_id_requester_notif'], - 'use_notification' - => $options['_users_id_requester_notif']['use_notification'], - 'entity_restrict' - => $_SESSION["glpiactive_entity"]]; - - Ajax::UpdateItemOnSelectEvent("dropdown_nodelegate".$rand, "show_result".$rand, - $CFG_GLPI["root_doc"]."/ajax/dropdownDelegationUsers.php", - $params); - - $class = 'right'; - if ($CFG_GLPI['use_check_pref'] && $options['nodelegate']) { - echo "".__('Check your personnal information'); - $class = 'center'; - } - - echo "
"; - echo "
"; - - $self = new self(); - if ($options["_users_id_requester"] == 0) { - $options['_users_id_requester'] = Session::getLoginUserID(); - } else { - $options['_right'] = "delegate"; - } - $self->showActorAddFormOnCreate(CommonITILActor::REQUESTER, $options); - echo "
"; - if ($CFG_GLPI['use_check_pref'] && $options['nodelegate']) { - echo "
"; - User::showPersonalInformation(Session::getLoginUserID()); - } - echo "
"; - echo ""; - - } else { - // User as requester - $options['_users_id_requester'] = Session::getLoginUserID(); - - if ($CFG_GLPI['use_check_pref']) { - echo "".__('Check your personnal information').""; - echo ""; - User::showPersonalInformation(Session::getLoginUserID()); - echo ""; - echo ""; - } - } - - echo ""; - echo ""; - - // Predefined fields from template : reset them - if (isset($options['_predefined_fields'])) { - $options['_predefined_fields'] - = Toolbox::decodeArrayFromInput($options['_predefined_fields']); - } else { - $options['_predefined_fields'] = []; - } - - // Store predefined fields to be able not to take into account on change template - $predefined_fields = []; - $key = $this->getTemplateFormFieldName(); - - if (isset($tt->predefined) && count($tt->predefined)) { - foreach ($tt->predefined as $predeffield => $predefvalue) { - if (isset($options[$predeffield]) && isset($default_values[$predeffield])) { - // Is always default value : not set - // Set if already predefined field - // Set if ticket template change - if (((count($options['_predefined_fields']) == 0) - && ($options[$predeffield] == $default_values[$predeffield])) - || (isset($options['_predefined_fields'][$predeffield]) - && ($options[$predeffield] == $options['_predefined_fields'][$predeffield])) - || (isset($options[$key]) - && ($options[$key] != $tt->getID()))) { - $options[$predeffield] = $predefvalue; - $predefined_fields[$predeffield] = $predefvalue; - } - } else { // Not defined options set as hidden field - echo ""; - } - } - // All predefined override : add option to say predifined exists - if (count($predefined_fields) == 0) { - $predefined_fields['_all_predefined_override'] = 1; - } - } else { // No template load : reset predefined values - if (count($options['_predefined_fields'])) { - foreach ($options['_predefined_fields'] as $predeffield => $predefvalue) { - if ($options[$predeffield] == $predefvalue) { - $options[$predeffield] = $default_values[$predeffield]; - } - } - } - } - - if (isset($options['_tasktemplates_id'])) { - foreach ($options['_tasktemplates_id'] as $tasktemplates_id) { - echo ""; - } - } - - if (($CFG_GLPI['urgency_mask'] == (1<<3)) - || $tt->isHiddenField('urgency')) { - // Dont show dropdown if only 1 value enabled or field is hidden - echo ""; - } - - // Display predefined fields if hidden - if ($tt->isHiddenField('items_id')) { - if (!empty($options['items_id'])) { - foreach ($options['items_id'] as $itemtype => $items) { - foreach ($items as $items_id) { - echo ""; - } - } - } - } - if ($tt->isHiddenField('locations_id')) { - echo ""; - } - echo ""; - echo "
"; - - Plugin::doHook("pre_item_form", ['item' => $this, 'options' => &$options]); - - echo ""; - - echo ""; - echo ""; - echo ""; - - echo ""; - echo ""; - echo ""; - - if ($CFG_GLPI['urgency_mask'] != (1<<3)) { - if (!$tt->isHiddenField('urgency')) { - echo ""; - echo ""; - echo ""; - } - } - -/** if (empty($delegating) - && NotificationTargetTicket::isAuthorMailingActivatedForHelpdesk()) { - echo ""; - echo ""; - echo ""; - } -*/ - if (($_SESSION["glpiactiveprofile"]["helpdesk_hardware"] != 0) - && (count($_SESSION["glpiactiveprofile"]["helpdesk_item_type"]))) { - if (!$tt->isHiddenField('items_id')) { - echo ""; - echo ""; - echo ""; - } - } - - if (!$tt->isHiddenField('locations_id')) { - echo ""; - } - - if (!$tt->isHiddenField('_users_id_observer') - || $tt->isPredefinedField('_users_id_observer')) { - echo ""; - echo ""; - echo ""; - } - - if (!$tt->isHiddenField('name') - || $tt->isPredefinedField('name')) { - echo ""; - echo ""; - } - - if (!$tt->isHiddenField('content') - || $tt->isPredefinedField('content')) { - echo ""; - echo ""; - } - Plugin::doHook("post_item_form", ['item' => $this, 'options' => &$options]); - - if (!$ticket_template) { - echo ""; - echo ""; - } - - echo "
".__('Describe the incident or request').""; - if (Session::isMultiEntitiesMode()) { - echo "(".Dropdown::getDropdownName("glpi_entities", $_SESSION["glpiactive_entity"]).")"; - } - echo "
".sprintf(__('%1$s%2$s'), __('Type'), $tt->getMandatoryMark('type')).""; - self::dropdownType('type', ['value' => $options['type'], - 'on_change' => 'this.form.submit()']); - echo "
".sprintf(__('%1$s%2$s'), __('Category'), - $tt->getMandatoryMark('itilcategories_id')).""; - - $condition = ['is_helpdeskvisible' => 1]; - switch ($options['type']) { - case self::DEMAND_TYPE : - $condition['is_request'] = 1; - break; - default: // self::INCIDENT_TYPE : - $condition['is_incident'] = 1; - } - $opt = ['value' => $options['itilcategories_id'], - 'condition' => $condition, - 'entity' => $_SESSION["glpiactive_entity"], - 'on_change' => 'this.form.submit()']; - - if ($options['itilcategories_id'] && $tt->isMandatoryField("itilcategories_id")) { - $opt['display_emptychoice'] = false; - } - - ITILCategory::dropdown($opt); - echo "
".sprintf(__('%1$s%2$s'), __('Urgency'), $tt->getMandatoryMark('urgency')). - ""; - self::dropdownUrgency(['value' => $options["urgency"]]); - echo "
".__('Inform me about the actions taken').""; - if ($options["_users_id_requester"] == 0) { - $options['_users_id_requester'] = Session::getLoginUserID(); - } - $_POST['value'] = $options['_users_id_requester']; - $_POST['field'] = '_users_id_requester_notif'; - $_POST['use_notification'] = $options['_users_id_requester_notif']['use_notification']; - include (GLPI_ROOT."/ajax/uemailUpdate.php"); - - echo "
".sprintf(__('%1$s%2$s'), _n('Associated element', 'Associated elements', Session::getPluralNumber()), - $tt->getMandatoryMark('items_id')).""; - $options['_canupdate'] = Session::haveRight('ticket', CREATE); - Item_Ticket::itemAddForm($this, $options); - echo "
"; - printf(__('%1$s%2$s'), __('Location'), $tt->getMandatoryMark('locations_id')); - echo ""; - Location::dropdown(['value' => $options["locations_id"]]); - echo "
".sprintf(__('%1$s%2$s'), _n('Watcher', 'Watchers', 2), - $tt->getMandatoryMark('_users_id_observer')).""; - $options['_right'] = "all"; - - if (!$tt->isHiddenField('_users_id_observer')) { - // Observer - - if ($tt->isPredefinedField('_users_id_observer') - && !is_array($options['_users_id_observer'])) { - - //convert predefined value to array - $options['_users_id_observer'] = [$options['_users_id_observer']]; - $options['_users_id_observer_notif']['use_notification'] = - [$options['_users_id_observer_notif']['use_notification']]; - - // add new line to permit adding more observers - $options['_users_id_observer'][1] = 0; - $options['_users_id_observer_notif']['use_notification'][1] = 1; - } - - echo "
"; - if (isset($options['_users_id_observer'])) { - $observers = $options['_users_id_observer']; - foreach ($observers as $index_observer => $observer) { - $options = array_merge($options, ['_user_index' => $index_observer]); - self::showFormHelpdeskObserver($options); - } - } - echo "
"; - - } else { // predefined value - if (isset($options["_users_id_observer"]) && $options["_users_id_observer"]) { - echo self::getActorIcon('user', CommonITILActor::OBSERVER)." "; - echo Dropdown::getDropdownName("glpi_users", $options["_users_id_observer"]); - echo ""; - } - } - echo "
".sprintf(__('%1$s%2$s'), __('Title'), $tt->getMandatoryMark('name')).""; - if (!$tt->isHiddenField('name')) { - $opt = [ - 'value' => $options['name'], - 'maxlength' => 250, - 'size' => 80, - ]; - - if ($tt->isMandatoryField('name')) { - $opt['required'] = 'required'; - } - echo Html::input('name', $opt); - } else { - echo $options['name']; - echo ""; - } - echo "
".sprintf(__('%1$s%2$s'), __('Description'), $tt->getMandatoryMark('content')); - - $rand = mt_rand(); - $rand_text = mt_rand(); - - $cols = 100; - $rows = 10; - $content_id = "content$rand"; - echo ""; - - $content = $options['content']; - if (!$ticket_template) { - $content = Html::cleanPostForTextArea($options['content']); - } - $content = Html::setRichTextContent($content_id, $content, $rand); - - echo "
"; - $uploads = []; - if (isset($options['_content'])) { - $uploads['_content'] = $options['_content']; - $uploads['_tag_content'] = $options['_tag_content']; - } - Html::textarea([ - 'name' => 'content', - 'filecontainer' => 'content_info', - 'editor_id' => $content_id, - 'required' => $tt->isMandatoryField('content'), - 'cols' => $cols, - 'rows' => $rows, - 'enable_richtext' => true, - 'value' => $content, - 'uploads' => $uploads, - ]); - echo "
"; - - if (!$tt->isHiddenField('_documents_id')) { - if (isset($options['_filename'])) { - $uploads['_filename'] = $options['_filename']; - $uploads['_tag_filename'] = $options['_tag_filename']; - } - Html::file([ - // 'editor_id' => $content_id, - 'showtitle' => false, - 'multiple' => true, - 'uploads' => $uploads, - ]); - } - - echo "
"; - - if ($tt->isField('id') && ($tt->fields['id'] > 0)) { - echo ""; - echo ""; - } - echo ""; - echo "
"; - if (!$ticket_template) { - Html::closeForm(); - } - } - - /** - * Display a single oberver selector - * - * * @param $options array options for default values ($options of showActorAddFormOnCreate) - **/ - static function showFormHelpdeskObserver($options = []) { - global $CFG_GLPI; - - //default values - $ticket = new Ticket(); - $params = [ - '_users_id_observer_notif' => [ - 'use_notification' => true - ], - '_users_id_observer' => 0, - 'entities_id' => $_SESSION["glpiactive_entity"], - '_right' => "all", - ]; - - // overide default value by function parameters - if (is_array($options) && count($options)) { - foreach ($options as $key => $val) { - $params[$key] = $val; - } - } - - // add a user selector - $rand_observer = $ticket->showActorAddFormOnCreate(CommonITILActor::OBSERVER, $params); - - if (isset($params['_tickettemplate'])) { - // Replace template object by ID for ajax - $params['_tickettemplate'] = $params['_tickettemplate']->getID(); - } - - // add an additionnal observer on user selection - Ajax::updateItemOnSelectEvent("dropdown__users_id_observer[]$rand_observer", - "observer_$rand_observer", - $CFG_GLPI["root_doc"]."/ajax/helpdesk_observer.php", - $params); - - //remove 'new observer' anchor on user selection - echo Html::scriptBlock(" - $('#dropdown__users_id_observer__$rand_observer').on('change', function(event) { - $('#addObserver$rand_observer').remove(); - });"); - - // add "new observer" anchor - echo ""; - echo Html::image($CFG_GLPI['root_doc']."/pics/meta_plus.png", ['alt' => __('Add')]); - echo ""; - - // add an additionnal observer on anchor click - Ajax::updateItemOnEvent("addObserver$rand_observer", - "observer_$rand_observer", - $CFG_GLPI["root_doc"]."/ajax/helpdesk_observer.php", - $params, ['click']); - - // div for an additionnal observer - echo "
"; - - } - - static function getDefaultValues($entity = 0) { - global $CFG_GLPI; - - if (is_numeric(Session::getLoginUserID(false))) { - $users_id_requester = Session::getLoginUserID(); - $users_id_assign = Session::getLoginUserID(); - // No default requester if own ticket right = tech and update_ticket right to update requester - if (Session::haveRightsOr(self::$rightname, [UPDATE, self::OWN]) && !$_SESSION['glpiset_default_requester']) { - $users_id_requester = 0; - } - if (!Session::haveRight(self::$rightname, self::OWN) || !$_SESSION['glpiset_default_tech']) { - $users_id_assign = 0; - } - $entity = $_SESSION['glpiactive_entity']; - $requesttype = $_SESSION['glpidefault_requesttypes_id']; - } else { - $users_id_requester = 0; - $users_id_assign = 0; - $requesttype = $CFG_GLPI['default_requesttypes_id']; - } - - $type = Entity::getUsedConfig('tickettype', $entity, '', Ticket::INCIDENT_TYPE); - - $default_use_notif = Entity::getUsedConfig('is_notif_enable_default', $entity, '', 1); - - // Set default values... - return ['_users_id_requester' => $users_id_requester, - '_users_id_requester_notif' => ['use_notification' => [$default_use_notif], - 'alternative_email' => ['']], - '_groups_id_requester' => 0, - '_users_id_assign' => $users_id_assign, - '_users_id_assign_notif' => ['use_notification' => [$default_use_notif], - 'alternative_email' => ['']], - '_groups_id_assign' => 0, - '_users_id_observer' => 0, - '_users_id_observer_notif' => ['use_notification' => [$default_use_notif], - 'alternative_email' => ['']], - '_groups_id_observer' => 0, - '_link' => ['tickets_id_2' => '', - 'link' => ''], - '_suppliers_id_assign' => 0, - '_suppliers_id_assign_notif' => ['use_notification' => [$default_use_notif], - 'alternative_email' => ['']], - 'name' => '', - 'content' => '', - 'itilcategories_id' => 0, - 'urgency' => 3, - 'impact' => 3, - 'priority' => self::computePriority(3, 3), - 'requesttypes_id' => $requesttype, - 'actiontime' => 0, - 'date' => null, - 'entities_id' => $entity, - 'status' => self::INCOMING, - 'followup' => [], - 'itemtype' => '', - 'items_id' => 0, - 'locations_id' => 0, - 'plan' => [], - 'global_validation' => CommonITILValidation::NONE, - 'time_to_resolve' => 'NULL', - 'time_to_own' => 'NULL', - 'slas_id_tto' => 0, - 'slas_id_ttr' => 0, - 'internal_time_to_resolve' => 'NULL', - 'internal_time_to_own' => 'NULL', - 'olas_id_tto' => 0, - 'olas_id_ttr' => 0, - '_add_validation' => 0, - 'users_id_validate' => [], - 'type' => $type, - '_documents_id' => [], - '_tasktemplates_id' => [], - '_content' => [], - '_tag_content' => [], - '_filename' => [], - '_tag_filename' => []]; - } - - /** - * Get ticket template to use - * Use force_template first, then try on template define for type and category - * then use default template of active profile of connected user and then use default entity one - * - * @param $force_template integer itiltemplate_id to used (case of preview for example) - * (default 0) - * @param $type integer type of the ticket (default 0) - * @param $itilcategories_id integer ticket category (default 0) - * @param $entities_id integer (default -1) - * - * @since 0.84 - * @deprecated 9.5.0 - * - * @return ticket template object - **/ - function getTicketTemplateToUse($force_template = 0, $type = 0, $itilcategories_id = 0, - $entities_id = -1) { - Toolbox::deprecated('Use getITILTemplateToUse()'); - return $this->getITILTemplateToUse( - $force_template, - $type, - $itilcategories_id, - $entities_id - ); - } - - - function showForm($ID, $options = []) { - global $CFG_GLPI; - - if (isset($options['_add_fromitem']) && isset($options['itemtype'])) { - $item = new $options['itemtype']; - $item->getFromDB($options['items_id'][$options['itemtype']][0]); - $options['entities_id'] = $item->fields['entities_id']; - } - - $default_values = self::getDefaultValues(); - - // Restore saved value or override with page parameter - $saved = $this->restoreInput(); - - foreach ($default_values as $name => $value) { - if (!isset($options[$name])) { - if (isset($saved[$name])) { - $options[$name] = $saved[$name]; - } else { - $options[$name] = $value; - } - } - } - - if (isset($options['content'])) { - // Clean new lines to be fix encoding - $order = ['\\r', '\\n', "\\'", '\\"', "\\\\"]; - $replace = ["", "", "'", '"', "\\"]; - $options['content'] = str_replace($order, $replace, $options['content']); - } - if (isset($options['name'])) { - $order = ["\\'", '\\"', "\\\\"]; - $replace = ["'", '"', "\\"]; - $options['name'] = str_replace($order, $replace, $options['name']); - } - - if (!isset($options['_skip_promoted_fields'])) { - $options['_skip_promoted_fields'] = false; - } - - if (!$ID) { - // Override defaut values from projecttask if needed - if (isset($options['_projecttasks_id'])) { - $pt = new ProjectTask(); - if ($pt->getFromDB($options['_projecttasks_id'])) { - $options['name'] = $pt->getField('name'); - $options['content'] = $pt->getField('name'); - } - } - // Override defaut values from followup if needed - if (isset($options['_promoted_fup_id']) && !$options['_skip_promoted_fields']) { - $fup = new ITILFollowup(); - if ($fup->getFromDB($options['_promoted_fup_id'])) { - $options['content'] = $fup->getField('content'); - $options['_users_id_requester'] = $fup->fields['users_id']; - $options['_link'] = [ - 'link' => Ticket_Ticket::SON_OF, - 'tickets_id_2' => $fup->fields['items_id'] - ]; - } - //Allow overriding the default values - $options['_skip_promoted_fields'] = true; - } - } - - // Check category / type validity - if ($options['itilcategories_id']) { - $cat = new ITILCategory(); - if ($cat->getFromDB($options['itilcategories_id'])) { - switch ($options['type']) { - case self::INCIDENT_TYPE : - if (!$cat->getField('is_incident')) { - $options['itilcategories_id'] = 0; - } - break; - - case self::DEMAND_TYPE : - if (!$cat->getField('is_request')) { - $options['itilcategories_id'] = 0; - } - break; - - default : - break; - } - } - } - - // Default check - if ($ID > 0) { - $this->check($ID, READ); - } else { - // Create item - $this->check(-1, CREATE, $options); - } - - if (!$ID) { - $this->userentities = []; - if ($options["_users_id_requester"]) { - //Get all the user's entities - $requester_entities = Profile_User::getUserEntities($options["_users_id_requester"], true, - true); - $user_entities = $_SESSION['glpiactiveentities']; - $this->userentities = array_intersect($requester_entities, $user_entities); - } - $this->countentitiesforuser = count($this->userentities); - - if (($this->countentitiesforuser > 0) - && !in_array($this->fields["entities_id"], $this->userentities)) { - // If entity is not in the list of user's entities, - // then use as default value the first value of the user's entites list - $this->fields["entities_id"] = $this->userentities[0]; - // Pass to values - $options['entities_id'] = $this->userentities[0]; - } - } - - if ($options['type'] <= 0) { - $options['type'] = Entity::getUsedConfig('tickettype', $options['entities_id'], '', - Ticket::INCIDENT_TYPE); - } - - if (!isset($options['template_preview'])) { - $options['template_preview'] = 0; - } - - if (!isset($options['_promoted_fup_id'])) { - $options['_promoted_fup_id'] = 0; - } - - // Load template if available : - $tt = $this->getITILTemplateToUse( - $options['template_preview'], - $this->fields['type'], - ($ID ? $this->fields['itilcategories_id'] : $options['itilcategories_id']), - ($ID ? $this->fields['entities_id'] : $options['entities_id']) - ); - - // Predefined fields from template : reset them - if (isset($options['_predefined_fields'])) { - $options['_predefined_fields'] - = Toolbox::decodeArrayFromInput($options['_predefined_fields']); - } else { - $options['_predefined_fields'] = []; - } - - // Store predefined fields to be able not to take into account on change template - // Only manage predefined values on ticket creation - $predefined_fields = []; - $tpl_key = $this->getTemplateFormFieldName(); - if (!$ID) { - - if (isset($tt->predefined) && count($tt->predefined)) { - foreach ($tt->predefined as $predeffield => $predefvalue) { - if (isset($default_values[$predeffield])) { - // Is always default value : not set - // Set if already predefined field - // Set if ticket template change - if (((count($options['_predefined_fields']) == 0) - && ($options[$predeffield] == $default_values[$predeffield])) - || (isset($options['_predefined_fields'][$predeffield]) - && ($options[$predeffield] == $options['_predefined_fields'][$predeffield])) - || (isset($options[$tpl_key]) - && ($options[$tpl_key] != $tt->getID())) - // user pref for requestype can't overwrite requestype from template - // when change category - || (($predeffield == 'requesttypes_id') - && empty($saved))) { - - // Load template data - $options[$predeffield] = $predefvalue; - $this->fields[$predeffield] = $predefvalue; - $predefined_fields[$predeffield] = $predefvalue; - } - } - } - // All predefined override : add option to say predifined exists - if (count($predefined_fields) == 0) { - $predefined_fields['_all_predefined_override'] = 1; - } - - } else { // No template load : reset predefined values - if (count($options['_predefined_fields'])) { - foreach ($options['_predefined_fields'] as $predeffield => $predefvalue) { - if ($options[$predeffield] == $predefvalue) { - $options[$predeffield] = $default_values[$predeffield]; - } - } - } - } - } - // Put ticket template on $options for actors - $options[str_replace('s_id', '', $tpl_key)] = $tt; - - // check right used for this ticket - $canupdate = !$ID - || (Session::getCurrentInterface() == "central" - && $this->canUpdateItem()); - $can_requester = $this->canRequesterUpdateItem(); - $canpriority = Session::haveRight(self::$rightname, self::CHANGEPRIORITY); - $canassign = $this->canAssign(); - $canassigntome = $this->canAssignTome(); - - if ($ID && in_array($this->fields['status'], $this->getClosedStatusArray())) { - $canupdate = false; - // No update for actors - $options['_noupdate'] = true; - } - - $showuserlink = 0; - if (Session::haveRight('user', READ)) { - $showuserlink = 1; - } - - if ($options['template_preview']) { - // Add all values to fields of tickets for template preview - foreach ($options as $key => $val) { - if (!isset($this->fields[$key])) { - $this->fields[$key] = $val; - } - } - } - - // In percent - $colsize1 = '13'; - $colsize2 = '29'; - $colsize3 = '13'; - $colsize4 = '45'; - - $this->showFormHeader($options); - - echo ""; - echo ""; - echo $tt->getBeginHiddenFieldText('date'); - if (!$ID) { - printf(__('%1$s%2$s'), __('Opening date'), $tt->getMandatoryMark('date')); - } else { - echo __('Opening date'); - } - echo $tt->getEndHiddenFieldText('date'); - echo ""; - echo ""; - echo $tt->getBeginHiddenFieldValue('date'); - $date = $this->fields["date"]; - - if ($canupdate) { - Html::showDateTimeField("date", ['value' => $date, - 'maybeempty' => false, - 'required' => ($tt->isMandatoryField('date') && !$ID)]); - } else { - echo Html::convDateTime($date); - } - echo $tt->getEndHiddenFieldValue('date', $this); - echo ""; - - if ($ID) { - echo "".__('By').""; - echo ""; - if ($canupdate) { - User::dropdown(['name' => 'users_id_recipient', - 'value' => $this->fields["users_id_recipient"], - 'entity' => $this->fields["entities_id"], - 'right' => 'all']); - } else { - echo getUserName($this->fields["users_id_recipient"], $showuserlink); - } - - echo ""; - } else { - echo ""; - echo ""; - } - echo ""; - - echo ""; - if ($ID) { - echo "".__('Last update').""; - echo ""; - if ($this->fields['users_id_lastupdater'] > 0) { - //TRANS: %1$s is the update date, %2$s is the last updater name - printf(__('%1$s by %2$s'), Html::convDateTime($this->fields["date_mod"]), - getUserName($this->fields["users_id_lastupdater"], $showuserlink)); - } - echo ""; - } - echo ""; - - // SLAs - echo ""; - echo "".$tt->getBeginHiddenFieldText('time_to_own'); - if (!$ID) { - printf(__('%1$s%2$s'), __('Time to own'), $tt->getMandatoryMark('time_to_own')); - } else { - echo __('Time to own'); - } - echo $tt->getEndHiddenFieldText('time_to_own'); - echo ""; - echo ""; - $sla = new SLA(); - $sla->showForTicket($this, SLM::TTO, $tt, $canupdate); - echo ""; - echo "".$tt->getBeginHiddenFieldText('time_to_resolve'); - if (!$ID) { - printf(__('%1$s%2$s'), __('Time to resolve'), $tt->getMandatoryMark('time_to_resolve')); - } else { - echo __('Time to resolve'); - } - echo $tt->getEndHiddenFieldText('time_to_resolve'); - echo ""; - echo ""; - $sla->showForTicket($this, SLM::TTR, $tt, $canupdate); - echo ""; - echo ""; - - // OLAs - echo ""; - echo "".$tt->getBeginHiddenFieldText('internal_time_to_own'); - if (!$ID) { - printf(__('%1$s%2$s'), __('Internal time to own'), $tt->getMandatoryMark('internal_time_to_own')); - } else { - echo __('Internal time to own'); - } - echo $tt->getEndHiddenFieldText('internal_time_to_own'); - echo ""; - echo ""; - $ola = new OLA(); - $ola->showForTicket($this, SLM::TTO, $tt, $canupdate); - echo ""; - echo "".$tt->getBeginHiddenFieldText('internal_time_to_resolve'); - if (!$ID) { - printf(__('%1$s%2$s'), __('Internal time to resolve'), $tt->getMandatoryMark('internal_time_to_resolve')); - } else { - echo __('Internal time to resolve'); - } - echo $tt->getEndHiddenFieldText('internal_time_to_resolve'); - echo ""; - echo ""; - $ola->showForTicket($this, SLM::TTR, $tt, $canupdate); - echo ""; - echo ""; - - if ($ID - && (in_array($this->fields["status"], $this->getSolvedStatusArray()) - || in_array($this->fields["status"], $this->getClosedStatusArray()))) { - - echo ""; - echo "".__('Resolution date').""; - echo ""; - Html::showDateTimeField("solvedate", ['value' => $this->fields["solvedate"], - 'maybeempty' => false, - 'canedit' => $canupdate]); - echo ""; - if (in_array($this->fields["status"], $this->getClosedStatusArray())) { - echo "".__('Close date').""; - echo ""; - Html::showDateTimeField("closedate", ['value' => $this->fields["closedate"], - 'maybeempty' => false, - 'canedit' => $canupdate]); - echo ""; - } else { - echo " "; - } - echo ""; - } - - if ($ID) { - echo ""; - echo ""; - } - - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - - if (!$ID) { - echo "
".sprintf(__('%1$s%2$s'), __('Type'), - $tt->getMandatoryMark('type')).""; - // Permit to set type when creating ticket without update right - if ($canupdate) { - $opt = ['value' => $this->fields["type"]]; - /// Auto submit to load template - if (!$ID) { - $opt['on_change'] = 'this.form.submit()'; - } - $rand = self::dropdownType('type', $opt); - if ($ID) { - $params = ['type' => '__VALUE__', - 'entity_restrict' => $this->fields['entities_id'], - 'value' => $this->fields['itilcategories_id'], - 'currenttype' => $this->fields['type']]; - - Ajax::updateItemOnSelectEvent("dropdown_type$rand", "show_category_by_type", - $CFG_GLPI["root_doc"]."/ajax/dropdownTicketCategories.php", - $params); - } - } else { - echo self::getTicketTypeName($this->fields["type"]); - } - echo "".sprintf(__('%1$s%2$s'), __('Category'), - $tt->getMandatoryMark('itilcategories_id')).""; - // Permit to set category when creating ticket without update right - if ($canupdate || $can_requester) { - $conditions = []; - - $opt = ['value' => $this->fields["itilcategories_id"], - 'entity' => $this->fields["entities_id"]]; - if (Session::getCurrentInterface() == "helpdesk") { - $conditions['is_helpdeskvisible'] = 1; - } - /// Auto submit to load template - if (!$ID) { - $opt['on_change'] = 'this.form.submit()'; - } - /// if category mandatory, no empty choice - /// no empty choice is default value set on ticket creation, else yes - if (($ID || $options['itilcategories_id']) - && $tt->isMandatoryField("itilcategories_id") - && ($this->fields["itilcategories_id"] > 0)) { - $opt['display_emptychoice'] = false; - } - - switch ($this->fields["type"]) { - case self::INCIDENT_TYPE : - $conditions['is_incident'] = 1; - break; - - case self::DEMAND_TYPE : - $conditions['is_request'] = 1; - break; - - default : - break; - } - echo ""; - $opt['condition'] = $conditions; - ITILCategory::dropdown($opt); - echo ""; - } else { - echo Dropdown::getDropdownName("glpi_itilcategories", $this->fields["itilcategories_id"]); - } - echo "
"; - $this->showActorsPartForm($ID, $options); - echo ""; - } - - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - - echo ""; - echo ""; - echo ""; - // Display validation state - echo ""; - echo ""; - - echo ""; - echo ""; - echo ""; - - echo ""; - echo ""; - echo ""; - - echo ""; - echo ""; - echo ""; - - if (!$ID) { - echo ""; - echo ""; - } else { - echo ""; - echo ""; - } - echo ""; - - if (!$ID - && Session::haveRight('followup', ITILFollowup::ADDALLTICKET)) { - - echo ""; - // Need comment right to add a followup with the actiontime - echo ""; - echo ""; - echo ""; - } - - echo "
".$tt->getBeginHiddenFieldText('status'); - printf(__('%1$s%2$s'), __('Status'), $tt->getMandatoryMark('status')); - echo $tt->getEndHiddenFieldText('status').""; - echo $tt->getBeginHiddenFieldValue('status'); - if ($canupdate) { - self::dropdownStatus(['value' => $this->fields["status"], - 'showtype' => 'allowed']); - TicketValidation::alertValidation($this, 'status'); - } else { - echo self::getStatus($this->fields["status"]); - if ($this->canReopen()) { - $link = $this->getLinkURL(). "&_openfollowup=1&forcetab="; - $link .= "Ticket$1"; - echo " ". __('Reopen').""; - } - } - echo $tt->getEndHiddenFieldValue('status', $this); - - echo "".$tt->getBeginHiddenFieldText('requesttypes_id'); - printf(__('%1$s%2$s'), __('Request source'), $tt->getMandatoryMark('requesttypes_id')); - echo $tt->getEndHiddenFieldText('requesttypes_id').""; - echo $tt->getBeginHiddenFieldValue('requesttypes_id'); - if ($canupdate) { - RequestType::dropdown(['value' => $this->fields["requesttypes_id"], 'condition' => ['is_active' => 1, 'is_ticketheader' => 1]]); - } else { - echo Dropdown::getDropdownName('glpi_requesttypes', $this->fields["requesttypes_id"]); - echo Html::hidden('requesttypes_id', ['value' => $this->fields["requesttypes_id"]]); - } - echo $tt->getEndHiddenFieldValue('requesttypes_id', $this); - echo "
".$tt->getBeginHiddenFieldText('urgency'); - printf(__('%1$s%2$s'), __('Urgency'), $tt->getMandatoryMark('urgency')); - echo $tt->getEndHiddenFieldText('urgency').""; - - if ($canupdate || $can_requester) { - echo $tt->getBeginHiddenFieldValue('urgency'); - $idurgency = self::dropdownUrgency(['value' => $this->fields["urgency"]]); - echo $tt->getEndHiddenFieldValue('urgency', $this); - - } else { - $idurgency = "value_urgency".mt_rand(); - echo ""; - echo $tt->getBeginHiddenFieldValue('urgency'); - echo parent::getUrgencyName($this->fields["urgency"]); - echo $tt->getEndHiddenFieldValue('urgency', $this); - } - echo ""; - if (!$ID) { - echo $tt->getBeginHiddenFieldText('_add_validation'); - printf(__('%1$s%2$s'), __('Approval request'), $tt->getMandatoryMark('_add_validation')); - echo $tt->getEndHiddenFieldText('_add_validation'); - } else { - echo $tt->getBeginHiddenFieldText('global_validation'); - echo __('Approval'); - echo $tt->getEndHiddenFieldText('global_validation'); - } - echo ""; - if (!$ID) { - echo $tt->getBeginHiddenFieldValue('_add_validation'); - $validation_right = ''; - if (($options['type'] == self::INCIDENT_TYPE) - && Session::haveRight('ticketvalidation', TicketValidation::CREATEINCIDENT)) { - $validation_right = 'validate_incident'; - } - if (($options['type'] == self::DEMAND_TYPE) - && Session::haveRight('ticketvalidation', TicketValidation::CREATEREQUEST)) { - $validation_right = 'validate_request'; - } - - if (!empty($validation_right)) { - echo ""; - - $params = ['name' => "users_id_validate", - 'entity' => $this->fields['entities_id'], - 'right' => $validation_right, - 'users_id_validate' => $options['users_id_validate']]; - TicketValidation::dropdownValidator($params); - } - echo $tt->getEndHiddenFieldValue('_add_validation', $this); - if ($tt->isPredefinedField('global_validation')) { - echo ""; - } - } else { - echo $tt->getBeginHiddenFieldValue('global_validation'); - - if (Session::haveRightsOr('ticketvalidation', TicketValidation::getCreateRights()) - && $canupdate) { - TicketValidation::dropdownStatus('global_validation', - ['global' => true, - 'value' => $this->fields['global_validation']]); - } else { - echo TicketValidation::getStatus($this->fields['global_validation']); - } - echo $tt->getEndHiddenFieldValue('global_validation', $this); - - } - echo "
".$tt->getBeginHiddenFieldText('impact'); - printf(__('%1$s%2$s'), __('Impact'), $tt->getMandatoryMark('impact')); - echo $tt->getEndHiddenFieldText('impact').""; - echo $tt->getBeginHiddenFieldValue('impact'); - - if ($canupdate) { - $idimpact = self::dropdownImpact(['value' => $this->fields["impact"]]); - } else { - $idimpact = "value_impact".mt_rand(); - echo ""; - echo parent::getImpactName($this->fields["impact"]); - } - echo $tt->getEndHiddenFieldValue('impact', $this); - echo "".$tt->getBeginHiddenFieldText('locations_id'); - printf(__('%1$s%2$s'), __('Location'), $tt->getMandatoryMark('locations_id')); - echo $tt->getEndHiddenFieldText('locations_id').""; - echo $tt->getBeginHiddenFieldValue('locations_id'); - if ($canupdate) { - Location::dropdown(['value' => $this->fields['locations_id'], - 'entity' => $this->fields['entities_id']]); - } else { - echo Dropdown::getDropdownName('glpi_locations', $this->fields["locations_id"]); - } - echo $tt->getEndHiddenFieldValue('locations_id', $this); - echo "
".$tt->getBeginHiddenFieldText('priority'); - printf(__('%1$s%2$s'), __('Priority'), $tt->getMandatoryMark('priority')); - echo $tt->getEndHiddenFieldText('priority').""; - $idajax = 'change_priority_' . mt_rand(); - - if ($canpriority - && !$tt->isHiddenField('priority')) { - $idpriority = parent::dropdownPriority(['value' => $this->fields["priority"], - 'withmajor' => true]); - $idpriority = 'dropdown_priority'.$idpriority; - echo " "; - - } else { - $idpriority = 0; - echo $tt->getBeginHiddenFieldValue('priority'); - echo "".parent::getPriorityName($this->fields["priority"]).""; - echo ""; - echo $tt->getEndHiddenFieldValue('priority', $this); - } - - if ($canupdate || $can_requester) { - $params = ['urgency' => '__VALUE0__', - 'impact' => '__VALUE1__', - 'priority' => $idpriority]; - Ajax::updateItemOnSelectEvent(['dropdown_urgency'.$idurgency, - 'dropdown_impact'.$idimpact], - $idajax, - $CFG_GLPI["root_doc"]."/ajax/priority.php", $params); - } - echo "".$tt->getBeginHiddenFieldText('items_id'); - printf(__('%1$s%2$s'), _n('Associated element', 'Associated elements', Session::getPluralNumber()), $tt->getMandatoryMark('items_id')); - echo $tt->getEndHiddenFieldText('items_id'); - echo ""; - echo $tt->getBeginHiddenFieldValue('items_id'); - $options['_canupdate'] = Session::haveRight('ticket', CREATE); - if ($options['_canupdate']) { - Item_Ticket::itemAddForm($this, $options); - } - echo $tt->getEndHiddenFieldValue('items_id', $this); - echo "
".$tt->getBeginHiddenFieldText('actiontime'); - printf(__('%1$s%2$s'), __('Total duration'), $tt->getMandatoryMark('actiontime')); - echo $tt->getEndHiddenFieldText('actiontime').""; - echo $tt->getBeginHiddenFieldValue('actiontime'); - Dropdown::showTimeStamp('actiontime', ['value' => $options['actiontime'], - 'addfirstminutes' => true]); - echo $tt->getEndHiddenFieldValue('actiontime', $this); - echo "
"; - if ($ID) { - $this->showActorsPartForm($ID, $options); - } - - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - - echo ""; - echo ""; - echo ""; - echo ""; - - echo ""; - echo "'; - echo ""; - echo ""; - - if (!in_array($this->fields['status'], $this->getClosedStatusArray())) { - // View files added - echo ""; - // Permit to add doc when creating a ticket - echo ""; - echo ""; - echo ""; - } - - Plugin::doHook("post_item_form", ['item' => $this, 'options' => &$options]); - - echo "
".$tt->getBeginHiddenFieldText('name'); - printf(__('%1$s%2$s'), __('Title'), $tt->getMandatoryMark('name')); - echo $tt->getEndHiddenFieldText('name').""; - if ($canupdate || $can_requester) { - echo $tt->getBeginHiddenFieldValue('name'); - echo "isMandatoryField('name') ? " required='required'" : '') . - " value=\"".Html::cleanInputText($this->fields["name"])."\">"; - echo $tt->getEndHiddenFieldValue('name', $this); - } else { - if (empty($this->fields["name"])) { - echo __('Without title'); - } else { - echo $this->fields["name"]; - } - } - echo "
".$tt->getBeginHiddenFieldText('content'); - printf(__('%1$s%2$s'), __('Description'), $tt->getMandatoryMark('content')); - if ($canupdate || $can_requester) { - $content = Toolbox::unclean_cross_side_scripting_deep(Html::entity_decode_deep($this->fields['content'])); - Html::showTooltip(nl2br(Html::Clean($content))); - } - echo $tt->getEndHiddenFieldText('content').""; - - echo $tt->getBeginHiddenFieldValue('content'); - $rand = mt_rand(); - $rand_text = mt_rand(); - $rows = 10; - $content_id = "content$rand"; - - $content = $this->fields['content']; - if (!isset($options['template_preview'])) { - $content = Html::cleanPostForTextArea($content); - } - - $content = Html::setRichTextContent( - $content_id, - $content, - $rand, - !$canupdate - ); - - echo "
"; - if ($canupdate || $can_requester) { - $uploads = []; - if (isset($this->input['_content'])) { - $uploads['_content'] = $this->input['_content']; - $uploads['_tag_content'] = $this->input['_tag_content']; - } - Html::textarea([ - 'name' => 'content', - 'filecontainer' => 'content_info', - 'editor_id' => $content_id, - 'required' => $tt->isMandatoryField('content'), - 'rows' => $rows, - 'enable_richtext' => true, - 'value' => $content, - 'uploads' => $uploads, - ]); - echo "
"; - } else { - echo Toolbox::getHtmlToDisplay($content); - } - echo $tt->getEndHiddenFieldValue('content', $this); - - echo "
". _n('Linked ticket', 'Linked tickets', - Session::getPluralNumber()); - $rand_linked_ticket = mt_rand(); - if ($canupdate) { - echo "" . __s('Add') . ""; - } - echo '"; - if ($canupdate) { - echo ""; - - if (isset($options["_link"]) - && !empty($options["_link"]['tickets_id_2'])) { - echo ""; - } - } - - Ticket_Ticket::displayLinkedTicketsTo($ID); - echo "
"; - echo $tt->getBeginHiddenFieldText('_documents_id'); - $doctitle = sprintf(__('File (%s)'), Document::getMaxUploadSize()); - printf(__('%1$s%2$s'), $doctitle, $tt->getMandatoryMark('_documents_id')); - // Do not show if hidden. - if (!$tt->isHiddenField('_documents_id')) { - DocumentType::showAvailableTypesLink(); - } - echo $tt->getEndHiddenFieldText('_documents_id'); - echo ""; - // Do not set values - echo $tt->getEndHiddenFieldValue('_documents_id'); - if ($tt->isPredefinedField('_documents_id')) { - if (isset($options['_documents_id']) - && is_array($options['_documents_id']) - && count($options['_documents_id'])) { - - echo "".__('Default documents:').''; - echo "
"; - $doc = new Document(); - foreach ($options['_documents_id'] as $key => $val) { - if ($doc->getFromDB($val)) { - echo ""; - echo "- ".$doc->getNameID()."
"; - } - } - } - } - if (!$tt->isHiddenField('_documents_id')) { - $uploads = []; - if (isset($this->input['_filename'])) { - $uploads['_filename'] = $this->input['_filename']; - $uploads['_tag_filename'] = $this->input['_tag_filename']; - } - Html::file([ - 'filecontainer' => 'fileupload_info_ticket', - // 'editor_id' => $content_id, - 'showtitle' => false, - 'multiple' => true, - 'uploads' => $uploads, - ]); - } - echo "
"; - - $display_save_btn = (!array_key_exists('locked', $options) || !$options['locked']) - && ($canupdate || $can_requester || $canpriority || $canassign || $canassigntome); - - if ($display_save_btn - && !$options['template_preview']) { - if ($ID) { - echo "
"; - if ($this->fields["is_deleted"] == 1) { - if (self::canDelete()) { - echo "      "; - } - } else { - if ($display_save_btn) { - echo "      "; - } - } - if ($this->fields["is_deleted"] == 1) { - if (self::canPurge()) { - echo ""; - } - } else { - if ($this->canDeleteItem()) { - echo ""; - } - } - echo ""; - echo "
"; - } else { - echo "
"; - $add_params = ['name' => 'add']; - if ($options['_promoted_fup_id']) { - $add_params['confirm'] = __('Confirm the promotion?'); - } - echo Html::submit(_x('button', 'Add'), $add_params); - if ($tt->isField('id') && ($tt->fields['id'] > 0)) { - echo ""; - echo ""; - } - echo Html::hidden('_promoted_fup_id', ['value' => $options['_promoted_fup_id']]); - echo Html::hidden('_skip_promoted_fields', ['value' => $options['_skip_promoted_fields']]); - echo '
'; - } - } - - echo ""; - echo ""; - - echo ""; - - if (!$options['template_preview']) { - Html::closeForm(); - } - - return true; - } - - - /** - * @param $size (default 25) - **/ - static function showDocumentAddButton($size = 25) { - echo ""; - echo "'); - nbfiles++; - if (nbfiles==maxfiles) { - ".Html::jsHide('addfilebutton')." - } - }\" - " . __s('Add') . ""; - } - - - /** - * @param $start - * @param $status (default ''process) - * @param $showgrouptickets (true by default) - */ - static function showCentralList($start, $status = "process", $showgrouptickets = true) { - global $DB; - - if (!Session::haveRightsOr(self::$rightname, [CREATE, self::READALL, self::READASSIGN]) - && !Session::haveRightsOr('ticketvalidation', TicketValidation::getValidateRights())) { - - return false; - } - - $JOINS = []; - $WHERE = [ - 'is_deleted' => 0 - ]; - $search_users_id = [ - 'glpi_tickets_users.users_id' => Session::getLoginUserID(), - 'glpi_tickets_users.type' => CommonITILActor::REQUESTER - ]; - $search_assign = [ - 'glpi_tickets_users.users_id' => Session::getLoginUserID(), - 'glpi_tickets_users.type' => CommonITILActor::ASSIGN - ]; - $search_observer = [ - 'glpi_tickets_users.users_id' => Session::getLoginUserID(), - 'glpi_tickets_users.type' => CommonITILActor::OBSERVER - ]; - - if ($showgrouptickets) { - $search_users_id = [0]; - $search_assign = [0]; - - if (count($_SESSION['glpigroups'])) { - $search_assign = [ - 'glpi_groups_tickets.groups_id' => $_SESSION['glpigroups'], - 'glpi_groups_tickets.type' => CommonITILActor::ASSIGN - ]; - - if (Session::haveRight(self::$rightname, self::READGROUP)) { - $search_users_id = [ - 'glpi_groups_tickets.groups_id' => $_SESSION['glpigroups'], - 'glpi_groups_tickets.type' => CommonITILActor::REQUESTER - ]; - $search_observer = [ - 'glpi_groups_tickets.groups_id' => $_SESSION['glpigroups'], - 'glpi_groups_tickets.type' => CommonITILActor::OBSERVER - ]; - } - } - } - - switch ($status) { - case "waiting" : // waiting tickets - $WHERE = array_merge( - $WHERE, - $search_assign, - ['glpi_tickets.status' => self::WAITING] - ); - break; - - case "process" : // planned or assigned tickets - $WHERE = array_merge( - $WHERE, - $search_assign, - ['glpi_tickets.status' => self::getProcessStatusArray()] - ); - break; - - case "toapprove" : //tickets waiting for approval - $ORWHERE = ['AND' => $search_users_id]; - if (!$showgrouptickets && Session::haveRight('ticket', Ticket::SURVEY)) { - $ORWHERE[] = ['glpi_tickets.users_id_recipient' => Session::getLoginUserID()]; - } - $WHERE[] = ['OR' => $ORWHERE]; - $WHERE['glpi_tickets.status'] = self::SOLVED; - break; - - case "tovalidate" : // tickets waiting for validation - $JOINS['LEFT JOIN'] = [ - 'glpi_ticketvalidations' => [ - 'ON' => [ - 'glpi_ticketvalidations' => 'tickets_id', - 'glpi_tickets' => 'id' - ] - ] - ]; - $WHERE = array_merge( - $WHERE, - [ - 'users_id_validate' => Session::getLoginUserID(), - 'glpi_ticketvalidations.status' => CommonITILValidation::WAITING, - 'glpi_tickets.global_validation' => CommonITILValidation::WAITING, - 'NOT' => [ - 'glpi_tickets.status' => [self::SOLVED, self::CLOSED] - ] - ] - ); - break; - - case "validation.rejected" : // tickets with rejected validation (approval) - case "rejected": //old ambiguous key - $WHERE = array_merge( - $WHERE, - $search_assign, - [ - 'glpi_tickets.status' => ['<>', self::CLOSED], - 'glpi_tickets.global_validation' => CommonITILValidation::REFUSED - ] - ); - break; - - case "solution.rejected" : // tickets with rejected solution - $subq = new QuerySubQuery([ - 'SELECT' => 'last_solution.id', - 'FROM' => 'glpi_itilsolutions AS last_solution', - 'WHERE' => [ - 'last_solution.items_id' => new QueryExpression($DB->quoteName('glpi_tickets.id')), - 'last_solution.itemtype' => 'Ticket' - ], - 'ORDER' => 'last_solution.id DESC', - 'LIMIT' => 1 - ]); - - $JOINS['LEFT JOIN'] = [ - 'glpi_itilsolutions' => [ - 'ON' => [ - 'glpi_itilsolutions' => 'id', - $subq - ] - ] - ]; - - $WHERE = array_merge( - $WHERE, - $search_assign, - [ - 'glpi_tickets.status' => ['<>', self::CLOSED], - 'glpi_itilsolutions.status' => CommonITILValidation::REFUSED - ] - ); - break; - case "observed" : - $WHERE = array_merge( - $WHERE, - $search_observer, - [ - 'glpi_tickets.status' => [ - self::INCOMING, - self::PLANNED, - self::ASSIGNED, - self::WAITING - ], - 'NOT' => [ - $search_assign, - $search_users_id - ] - ] - ); - break; - - case "survey" : // tickets dont l'enqu??te de satisfaction n'est pas remplie et encore valide - $JOINS['INNER JOIN'] = [ - 'glpi_ticketsatisfactions' => [ - 'ON' => [ - 'glpi_ticketsatisfactions' => 'tickets_id', - 'glpi_tickets' => 'id' - ] - ], - 'glpi_entities' => [ - 'ON' => [ - 'glpi_tickets' => 'entities_id', - 'glpi_entities' => 'id' - ] - ] - ]; - $ORWHERE = ['AND' => $search_users_id]; - if (!$showgrouptickets && Session::haveRight('ticket', Ticket::SURVEY)) { - $ORWHERE[] = ['glpi_tickets.users_id_recipient' => Session::getLoginUserID()]; - } - $WHERE[] = ['OR' => $ORWHERE]; - - $WHERE = array_merge( - $WHERE, - [ - 'glpi_tickets.status' => self::CLOSED, - ['OR' => [ - 'glpi_entities.inquest_duration' => 0, - new \QueryExpression( - 'DATEDIFF(ADDDATE(' . $DB->quoteName('glpi_ticketsatisfactions.date_begin') . - ', INTERVAL ' . $DB->quoteName('glpi_entities.inquest_duration') . ' DAY), CURDATE()) > 0' - ) - ]], - 'glpi_ticketsatisfactions.date_answered' => null - ] - ); - break; - - case "requestbyself" : // on affiche les tickets demand??s le user qui sont planifi??s ou assign??s - // ?? quelqu'un d'autre (exclut les self-tickets) - - default : - $WHERE = array_merge( - $WHERE, - $search_users_id, - [ - 'glpi_tickets.status' => [ - self::INCOMING, - self::PLANNED, - self::ASSIGNED, - self::WAITING - ], - 'NOT' => $search_assign - ] - ); - } - - $criteria = [ - 'SELECT' => ['glpi_tickets.id', 'glpi_tickets.date_mod'], - 'DISTINCT' => true, - 'FROM' => 'glpi_tickets', - 'LEFT JOIN' => [ - 'glpi_tickets_users' => [ - 'ON' => [ - 'glpi_tickets_users' => 'tickets_id', - 'glpi_tickets' => 'id' - ] - ], - 'glpi_groups_tickets' => [ - 'ON' => [ - 'glpi_groups_tickets' => 'tickets_id', - 'glpi_tickets' => 'id' - ] - ] - ], - 'WHERE' => $WHERE + getEntitiesRestrictCriteria('glpi_tickets'), - 'ORDERBY' => 'glpi_tickets.date_mod DESC' - ]; - if (count($JOINS)) { - $criteria = array_merge_recursive($criteria, $JOINS); - } - $iterator = $DB->request($criteria); - $numrows = count($iterator); - $number = 0; - - if ($_SESSION['glpidisplay_count_on_home'] > 0) { - $iterator = $DB->request( - $criteria + [ - 'START' => (int)$start, - 'LIMIT' => (int)$_SESSION['glpidisplay_count_on_home'] - ] - ); - $number = count($iterator); - } - - if ($numrows > 0) { - echo ""; - echo ""; - if ($number) { - echo ""; - echo ""; - echo ""; - echo ""; - while ($data = $iterator->next()) { - self::showVeryShort($data['id'], $forcetab); - } - } - echo "
"; - - $options = [ - 'criteria' => [], - 'reset' => 'reset', - ]; - $forcetab = ''; - if ($showgrouptickets) { - switch ($status) { - case "toapprove" : - $options['criteria'][0]['field'] = 12; // status - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = self::SOLVED; - $options['criteria'][0]['link'] = 'AND'; - - $options['criteria'][1]['field'] = 71; // groups_id - $options['criteria'][1]['searchtype'] = 'equals'; - $options['criteria'][1]['value'] = 'mygroups'; - $options['criteria'][1]['link'] = 'AND'; - $forcetab = 'Ticket$2'; - - echo "". - Html::makeTitle(__('Your tickets to close'), $number, $numrows).""; - break; - - case "waiting" : - $options['criteria'][0]['field'] = 12; // status - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = self::WAITING; - $options['criteria'][0]['link'] = 'AND'; - - $options['criteria'][1]['field'] = 8; // groups_id_assign - $options['criteria'][1]['searchtype'] = 'equals'; - $options['criteria'][1]['value'] = 'mygroups'; - $options['criteria'][1]['link'] = 'AND'; - - echo "". - Html::makeTitle(__('Tickets on pending status'), $number, $numrows).""; - break; - - case "process" : - $options['criteria'][0]['field'] = 12; // status - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = 'process'; - $options['criteria'][0]['link'] = 'AND'; - - $options['criteria'][1]['field'] = 8; // groups_id_assign - $options['criteria'][1]['searchtype'] = 'equals'; - $options['criteria'][1]['value'] = 'mygroups'; - $options['criteria'][1]['link'] = 'AND'; - - echo "". - Html::makeTitle(__('Tickets to be processed'), $number, $numrows).""; - break; - - case "observed": - $options['criteria'][0]['field'] = 12; // status - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = 'notold'; - $options['criteria'][0]['link'] = 'AND'; - - $options['criteria'][1]['field'] = 65; // groups_id - $options['criteria'][1]['searchtype'] = 'equals'; - $options['criteria'][1]['value'] = 'mygroups'; - $options['criteria'][1]['link'] = 'AND'; - - echo "". - Html::makeTitle(__('Your observed tickets'), $number, $numrows).""; - break; - - case "requestbyself" : - default : - $options['criteria'][0]['field'] = 12; // status - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = 'notold'; - $options['criteria'][0]['link'] = 'AND'; - - $options['criteria'][1]['field'] = 71; // groups_id - $options['criteria'][1]['searchtype'] = 'equals'; - $options['criteria'][1]['value'] = 'mygroups'; - $options['criteria'][1]['link'] = 'AND'; - - echo "". - Html::makeTitle(__('Your tickets in progress'), $number, $numrows).""; - } - - } else { - switch ($status) { - case "waiting" : - $options['criteria'][0]['field'] = 12; // status - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = self::WAITING; - $options['criteria'][0]['link'] = 'AND'; - - $options['criteria'][1]['field'] = 5; // users_id_assign - $options['criteria'][1]['searchtype'] = 'equals'; - $options['criteria'][1]['value'] = Session::getLoginUserID(); - $options['criteria'][1]['link'] = 'AND'; - - echo "". - Html::makeTitle(__('Tickets on pending status'), $number, $numrows).""; - break; - - case "process" : - $options['criteria'][0]['field'] = 5; // users_id_assign - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = Session::getLoginUserID(); - $options['criteria'][0]['link'] = 'AND'; - - $options['criteria'][1]['field'] = 12; // status - $options['criteria'][1]['searchtype'] = 'equals'; - $options['criteria'][1]['value'] = 'process'; - $options['criteria'][1]['link'] = 'AND'; - - echo "". - Html::makeTitle(__('Tickets to be processed'), $number, $numrows).""; - break; - - case "tovalidate" : - $options['criteria'][0]['field'] = 55; // validation status - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = CommonITILValidation::WAITING; - $options['criteria'][0]['link'] = 'AND'; - - $options['criteria'][1]['field'] = 59; // validation aprobator - $options['criteria'][1]['searchtype'] = 'equals'; - $options['criteria'][1]['value'] = Session::getLoginUserID(); - $options['criteria'][1]['link'] = 'AND'; - - $options['criteria'][2]['field'] = 12; // validation aprobator - $options['criteria'][2]['searchtype'] = 'equals'; - $options['criteria'][2]['value'] = 'old'; - $options['criteria'][2]['link'] = 'AND NOT'; - - $options['criteria'][3]['field'] = 52; // global validation status - $options['criteria'][3]['searchtype'] = 'equals'; - $options['criteria'][3]['value'] = CommonITILValidation::WAITING; - $options['criteria'][3]['link'] = 'AND'; - $forcetab = 'TicketValidation$1'; - - echo "". - Html::makeTitle(__('Your tickets to validate'), $number, $numrows).""; - - break; - - case "validation.rejected" : - case "rejected" : // old ambiguous key - $options['criteria'][0]['field'] = 52; // validation status - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = CommonITILValidation::REFUSED; - $options['criteria'][0]['link'] = 'AND'; - - $options['criteria'][1]['field'] = 5; // assign user - $options['criteria'][1]['searchtype'] = 'equals'; - $options['criteria'][1]['value'] = Session::getLoginUserID(); - $options['criteria'][1]['link'] = 'AND'; - - echo "". - Html::makeTitle(__('Your tickets having rejected approval status'), $number, $numrows).""; - - break; - - case "solution.rejected" : - $options['criteria'][0]['field'] = 39; // last solution status - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = CommonITILValidation::REFUSED; - $options['criteria'][0]['link'] = 'AND'; - - $options['criteria'][1]['field'] = 5; // assign user - $options['criteria'][1]['searchtype'] = 'equals'; - $options['criteria'][1]['value'] = Session::getLoginUserID(); - $options['criteria'][1]['link'] = 'AND'; - - echo "". - Html::makeTitle(__('Your tickets having rejected solution'), $number, $numrows).""; - - break; - - case "toapprove" : - $options['criteria'][0]['field'] = 12; // status - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = self::SOLVED; - $options['criteria'][0]['link'] = 'AND'; - - $options['criteria'][1]['field'] = 4; // users_id_assign - $options['criteria'][1]['searchtype'] = 'equals'; - $options['criteria'][1]['value'] = Session::getLoginUserID(); - $options['criteria'][1]['link'] = 'AND'; - - $options['criteria'][2]['field'] = 22; // users_id_recipient - $options['criteria'][2]['searchtype'] = 'equals'; - $options['criteria'][2]['value'] = Session::getLoginUserID(); - $options['criteria'][2]['link'] = 'OR'; - - $options['criteria'][3]['field'] = 12; // status - $options['criteria'][3]['searchtype'] = 'equals'; - $options['criteria'][3]['value'] = self::SOLVED; - $options['criteria'][3]['link'] = 'AND'; - - $forcetab = 'Ticket$2'; - - echo "". - Html::makeTitle(__('Your tickets to close'), $number, $numrows).""; - break; - - case "observed" : - $options['criteria'][0]['field'] = 66; // users_id - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = Session::getLoginUserID(); - $options['criteria'][0]['link'] = 'AND'; - - $options['criteria'][1]['field'] = 12; // status - $options['criteria'][1]['searchtype'] = 'equals'; - $options['criteria'][1]['value'] = 'notold'; - $options['criteria'][1]['link'] = 'AND'; - - echo "". - Html::makeTitle(__('Your observed tickets'), $number, $numrows).""; - break; - - case "survey" : - $options['criteria'][0]['field'] = 12; // status - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = self::CLOSED; - $options['criteria'][0]['link'] = 'AND'; - - $options['criteria'][1]['field'] = 60; // enquete generee - $options['criteria'][1]['searchtype'] = 'contains'; - $options['criteria'][1]['value'] = '^'; - $options['criteria'][1]['link'] = 'AND'; - - $options['criteria'][2]['field'] = 61; // date_answered - $options['criteria'][2]['searchtype'] = 'contains'; - $options['criteria'][2]['value'] = 'NULL'; - $options['criteria'][2]['link'] = 'AND'; - - if (Session::haveRight('ticket', Ticket::SURVEY)) { - $options['criteria'][3]['field'] = 22; // author - $options['criteria'][3]['searchtype'] = 'equals'; - $options['criteria'][3]['value'] = Session::getLoginUserID(); - $options['criteria'][3]['link'] = 'AND'; - } else { - $options['criteria'][3]['field'] = 4; // requester - $options['criteria'][3]['searchtype'] = 'equals'; - $options['criteria'][3]['value'] = Session::getLoginUserID(); - $options['criteria'][3]['link'] = 'AND'; - } - $forcetab = 'Ticket$3'; - - echo "". - Html::makeTitle(__('Satisfaction survey'), $number, $numrows).""; - break; - - case "requestbyself" : - default : - $options['criteria'][0]['field'] = 4; // users_id - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = Session::getLoginUserID(); - $options['criteria'][0]['link'] = 'AND'; - - $options['criteria'][1]['field'] = 12; // status - $options['criteria'][1]['searchtype'] = 'equals'; - $options['criteria'][1]['value'] = 'notold'; - $options['criteria'][1]['link'] = 'AND'; - - echo "". - Html::makeTitle(__('Your tickets in progress'), $number, $numrows).""; - } - } - - echo "
".__('ID')."".__('Requester').""._n('Associated element', 'Associated elements', Session::getPluralNumber())."".__('Description')."
"; - - } - } - - /** - * Get tickets count - * - * @param $foruser boolean : only for current login user as requester (false by default) - **/ - static function showCentralCount($foruser = false) { - global $DB, $CFG_GLPI; - - // show a tab with count of jobs in the central and give link - if (!Session::haveRight(self::$rightname, self::READALL) && !self::canCreate()) { - return false; - } - if (!Session::haveRight(self::$rightname, self::READALL)) { - $foruser = true; - } - - $table = self::getTable(); - $criteria = [ - 'SELECT' => [ - 'glpi_tickets.status', - 'COUNT DISTINCT' => ["$table.id AS COUNT"], - ], - 'FROM' => $table, - 'WHERE' => getEntitiesRestrictCriteria($table), - 'GROUPBY' => 'status' - ]; - - if ($foruser) { - $criteria['LEFT JOIN'] = [ - 'glpi_tickets_users' => [ - 'ON' => [ - 'glpi_tickets_users' => 'tickets_id', - $table => 'id', [ - 'AND' => [ - 'glpi_tickets_users.type' => CommonITILActor::REQUESTER - ] - ] - ] - ], - 'glpi_ticketvalidations' => [ - 'ON' => [ - 'glpi_ticketvalidations' => 'tickets_id', - $table => 'id' - ] - ] - ]; - - if (Session::haveRight(self::$rightname, self::READGROUP) - && isset($_SESSION["glpigroups"]) - && count($_SESSION["glpigroups"])) { - $criteria['LEFT JOIN']['glpi_groups_tickets'] = [ - 'ON' => [ - 'glpi_groups_tickets' => 'tickets_id', - $table => 'id', [ - 'AND' => ['glpi_groups_tickets.type' => CommonITILActor::REQUESTER] - ] - ] - ]; - } - } - - if ($foruser) { - $ORWHERE = ['OR' => [ - 'glpi_tickets_users.users_id' => Session::getLoginUserID(), - 'glpi_tickets.users_id_recipient' => Session::getLoginUserID(), - 'glpi_ticketvalidations.users_id_validate' => Session::getLoginUserID() - ]]; - - if (Session::haveRight(self::$rightname, self::READGROUP) - && isset($_SESSION["glpigroups"]) - && count($_SESSION["glpigroups"])) { - $ORWHERE['OR']['glpi_groups_tickets.groups_id'] = $_SESSION['glpigroups']; - } - $criteria['WHERE'][] = $ORWHERE; - } - - $deleted_criteria = $criteria; - $criteria['WHERE']['glpi_tickets.is_deleted'] = 0; - $deleted_criteria['WHERE']['glpi_tickets.is_deleted'] = 1; - $iterator = $DB->request($criteria); - $deleted_iterator = $DB->request($deleted_criteria); - - $status = []; - foreach (self::getAllStatusArray() as $key => $val) { - $status[$key] = 0; - } - - while ($data = $iterator->next()) { - $status[$data["status"]] = $data["COUNT"]; - } - - $number_deleted = 0; - while ($data = $deleted_iterator->next()) { - $number_deleted += $data["COUNT"]; - } - - $options = [ - 'criteria' => [], - 'reset' => 'reset', - ]; - $options['criteria'][0]['field'] = 12; - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = 'process'; - $options['criteria'][0]['link'] = 'AND'; - - echo ""; - echo ""; - echo " - "; - - if (Session::haveRightsOr('ticketvalidation', TicketValidation::getValidateRights())) { - $number_waitapproval = TicketValidation::getNumberToValidate(Session::getLoginUserID()); - - $opt = [ - 'criteria' => [], - 'reset' => 'reset', - ]; - $opt['criteria'][0]['field'] = 55; // validation status - $opt['criteria'][0]['searchtype'] = 'equals'; - $opt['criteria'][0]['value'] = CommonITILValidation::WAITING; - $opt['criteria'][0]['link'] = 'AND'; - - $opt['criteria'][1]['field'] = 59; // validation aprobator - $opt['criteria'][1]['searchtype'] = 'equals'; - $opt['criteria'][1]['value'] = Session::getLoginUserID(); - $opt['criteria'][1]['link'] = 'AND'; - - echo ""; - echo ""; - echo ""; - } - - foreach ($status as $key => $val) { - $options['criteria'][0]['value'] = $key; - echo ""; - echo ""; - echo ""; - } - - $options['criteria'][0]['value'] = 'all'; - $options['is_deleted'] = 1; - echo ""; - echo ""; - echo ""; - - echo "
"; - - if (Session::getCurrentInterface() != "central") { - echo "". - __('Create a ticket')." ". __s('Add').""; - } else { - echo "".__('Ticket followup').""; - } - echo "
"._n('Ticket', 'Tickets', Session::getPluralNumber()).""._x('quantity', 'Number')."
".__('Ticket waiting for your approval')."".$number_waitapproval."
".self::getStatus($key)."$val
".__('Deleted')."".$number_deleted."

"; - } - - - static function showCentralNewList() { - global $DB; - - if (!Session::haveRight(self::$rightname, self::READALL)) { - return false; - } - - $criteria = self::getCommonCriteria(); - $criteria['WHERE'] = [ - 'status' => self::INCOMING, - 'is_deleted' => 0 - ] + getEntitiesRestrictCriteria(self::getTable()); - $criteria['LIMIT'] = (int)$_SESSION['glpilist_limit']; - $iterator = $DB->request($criteria); - $number = count($iterator); - - if ($number > 0) { - Session::initNavigateListItems('Ticket'); - - $options = [ - 'criteria' => [], - 'reset' => 'reset', - ]; - $options['criteria'][0]['field'] = 12; - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = self::INCOMING; - $options['criteria'][0]['link'] = 'AND'; - - echo "
"; - //TRANS: %d is the number of new tickets - echo ""; - - self::commonListHeader(Search::HTML_OUTPUT); - - while ($data = $iterator->next()) { - Session::addToNavigateListItems('Ticket', $data["id"]); - self::showShort($data["id"]); - } - echo "
".sprintf(_n('%d new ticket', '%d new tickets', $number), $number); - echo "".__('Show all').""; - echo "
"; - - } else { - echo "
"; - echo ""; - echo ""; - echo "
".__('No ticket found.')."
"; - echo "

"; - } - } - - /** - * Display tickets for an item - * - * Will also display tickets of linked items - * - * @param CommonDBTM $item CommonDBTM object - * @param integer $withtemplate (default 0) - * - * @return void (display a table) - **/ - static function showListForItem(CommonDBTM $item, $withtemplate = 0) { - global $DB; - - if (!Session::haveRightsOr(self::$rightname, - [self::READALL, self::READMY, self::READASSIGN, CREATE])) { - return false; - } - - if ($item->isNewID($item->getID())) { - return false; - } - - $criteria = self::getCommonCriteria(); - $restrict = []; - $options = [ - 'criteria' => [], - 'reset' => 'reset', - ]; - - switch ($item->getType()) { - case 'User' : - $restrict['glpi_tickets_users.users_id'] = $item->getID(); - $restrict['glpi_tickets_users.type'] = CommonITILActor::REQUESTER; - - $options['criteria'][0]['field'] = 4; // status - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = $item->getID(); - $options['criteria'][0]['link'] = 'AND'; - break; - - case 'SLA' : - $restrict[] = [ - 'OR' => [ - 'slas_id_tto' => $item->getID(), - 'slas_id_ttr' => $item->getID() - ] - ]; - $criteria['ORDERBY'] = 'glpi_tickets.time_to_resolve DESC'; - - $options['criteria'][0]['field'] = 30; - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = $item->getID(); - $options['criteria'][0]['link'] = 'AND'; - break; - - case 'OLA' : - $restrict[] = [ - 'OR' => [ - 'olas_id_tto' => $item->getID(), - 'olas_id_ttr' => $item->getID() - ] - ]; - $criteria['ORDERBY'] = 'glpi_tickets.internal_time_to_resolve DESC'; - - $options['criteria'][0]['field'] = 30; - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = $item->getID(); - $options['criteria'][0]['link'] = 'AND'; - break; - - case 'Supplier' : - $restrict['glpi_suppliers_tickets.suppliers_id'] = $item->getID(); - $restrict['glpi_suppliers_tickets.type'] = CommonITILActor::ASSIGN; - - $options['criteria'][0]['field'] = 6; - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = $item->getID(); - $options['criteria'][0]['link'] = 'AND'; - break; - - case 'Group' : - // Mini search engine - if ($item->haveChildren()) { - $tree = Session::getSavedOption(__CLASS__, 'tree', 0); - echo ""; - echo ""; - echo "
".__('Last tickets')."
"; - echo __('Child groups')." "; - Dropdown::showYesNo('tree', $tree, -1, - ['on_change' => 'reloadTab("start=0&tree="+this.value)']); - } else { - $tree = 0; - } - echo "
"; - - $restrict['glpi_groups_tickets.groups_id'] = ($tree ? getSonsOf('glpi_groups', $item->getID()) : $item->getID()); - $restrict['glpi_groups_tickets.type'] = CommonITILActor::REQUESTER; - - $options['criteria'][0]['field'] = 71; - $options['criteria'][0]['searchtype'] = ($tree ? 'under' : 'equals'); - $options['criteria'][0]['value'] = $item->getID(); - $options['criteria'][0]['link'] = 'AND'; - break; - - default : - $restrict['glpi_items_tickets.items_id'] = $item->getID(); - $restrict['glpi_items_tickets.itemtype'] = $item->getType(); - - // you can only see your tickets - if (!Session::haveRight(self::$rightname, self::READALL)) { - $or = [ - 'glpi_tickets.users_id_recipient' => Session::getLoginUserID(), - [ - 'AND' => [ - 'glpi_tickets_users.tickets_id' => new \QueryExpression('glpi_tickets.id'), - 'glpi_tickets_users.users_id' => Session::getLoginUserID() - ] - ] - ]; - if (count($_SESSION['glpigroups'])) { - $or['glpi_groups_tickets.groups_id'] = $_SESSION['glpigroups']; - } - $restrict[] = ['OR' => $or]; - } - - $options['criteria'][0]['field'] = 12; - $options['criteria'][0]['searchtype'] = 'equals'; - $options['criteria'][0]['value'] = 'all'; - $options['criteria'][0]['link'] = 'AND'; - - $options['metacriteria'][0]['itemtype'] = $item->getType(); - $options['metacriteria'][0]['field'] = Search::getOptionNumber($item->getType(), - 'id'); - $options['metacriteria'][0]['searchtype'] = 'equals'; - $options['metacriteria'][0]['value'] = $item->getID(); - $options['metacriteria'][0]['link'] = 'AND'; - break; - } - - $criteria['WHERE'] = $restrict + getEntitiesRestrictCriteria(self::getTable()); - $criteria['WHERE']['glpi_tickets.is_deleted'] = 0; - $criteria['LIMIT'] = (int)$_SESSION['glpilist_limit']; - $iterator = $DB->request($criteria); - $number = count($iterator); - - $colspan = 11; - if (count($_SESSION["glpiactiveentities"]) > 1) { - $colspan++; - } - - // Ticket for the item - // Link to open a new ticket - if ($item->getID() - && !$item->isDeleted() - && Ticket::isPossibleToAssignType($item->getType()) - && self::canCreate() - && !(!empty($withtemplate) && ($withtemplate == 2)) - && (!isset($item->fields['is_template']) || ($item->fields['is_template'] == 0))) { - echo "
"; - Html::showSimpleForm(Ticket::getFormURL(), - '_add_fromitem', __('New ticket for this item...'), - ['itemtype' => $item->getType(), - 'items_id' => $item->getID()]); - echo "
"; - } - - if ($item->getID() - && ($item->getType() == 'User') - && self::canCreate() - && !(!empty($withtemplate) && ($withtemplate == 2))) { - echo "
"; - Html::showSimpleForm(Ticket::getFormURL(), - '_add_fromitem', __('New ticket for this item...'), - ['_users_id_requester' => $item->getID()]); - echo "
"; - } - - echo "
"; - - if ($number > 0) { - echo ""; - if (Session::haveRight(self::$rightname, self::READALL)) { - Session::initNavigateListItems('Ticket', - //TRANS : %1$s is the itemtype name, %2$s is the name of the item (used for headings of a list) - sprintf(__('%1$s = %2$s'), $item->getTypeName(1), - $item->getName())); - - echo ""; - } else { - echo ""; - } - - } else { - echo "
"; - $title = sprintf(_n('Last %d ticket', 'Last %d tickets', $number), $number); - $link = "".__('Show all').""; - $title = printf(__('%1$s (%2$s)'), $title, $link); - echo "
".__("You don't have right to see all tickets")."
"; - echo ""; - } - - // Ticket list - if ($number > 0) { - self::commonListHeader(Search::HTML_OUTPUT); - - while ($data = $iterator->next()) { - Session::addToNavigateListItems('Ticket', $data["id"]); - self::showShort($data["id"]); - } - self::commonListHeader(Search::HTML_OUTPUT); - } - - echo "
".__('No ticket found.')."
"; - - // Tickets for linked items - $linkeditems = $item->getLinkedItems(); - $restrict = []; - if (count($linkeditems)) { - foreach ($linkeditems as $ltype => $tab) { - foreach ($tab as $lID) { - $restrict[] = ['AND' => ['itemtype' => $ltype, 'items_id' => $lID]]; - } - } - } - - if (count($restrict) - && Session::haveRight(self::$rightname, self::READALL)) { - $criteria = self::getCommonCriteria(); - $criteria['WHERE'] = ['OR' => $restrict] - + getEntitiesRestrictCriteria(self::getTable()); - $iterator = $DB->request($criteria); - $number = count($iterator); - - echo "
"; - echo ""; - if ($number > 0) { - self::commonListHeader(Search::HTML_OUTPUT); - while ($data = $iterator->next()) { - // Session::addToNavigateListItems(TRACKING_TYPE,$data["id"]); - self::showShort($data["id"]); - } - self::commonListHeader(Search::HTML_OUTPUT); - } else { - echo ""; - } - echo "
"; - echo _n('Ticket on linked items', 'Tickets on linked items', $number); - echo "
".__('No ticket found.')."
"; - - } // Subquery for linked item - - } - - /** - * @param $ID - * @param $forcetab string name of the tab to force at the display (default '') - **/ - static function showVeryShort($ID, $forcetab = '') { - // Prints a job in short form - // Should be called in a -segment - // Print links or not in case of user view - // Make new job object and fill it from database, if success, print it - $showprivate = false; - if (Session::haveRight('followup', ITILFollowup::SEEPRIVATE)) { - $showprivate = true; - } - - $job = new self(); - $rand = mt_rand(); - if ($job->getFromDBwithData($ID, 0)) { - $bgcolor = $_SESSION["glpipriority_".$job->fields["priority"]]; - $name = sprintf(__('%1$s: %2$s'), __('ID'), $job->fields["id"]); - // $rand = mt_rand(); - echo ""; - echo ""; - echo ""; - - echo ""; - - // Finish Line - echo ""; - } else { - echo ""; - echo ""; - } - } - - - public static function getCommonCriteria() { - $criteria = parent::getCommonCriteria(); - - $criteria['LEFT JOIN']['glpi_tickettasks'] = [ - 'ON' => [ - self::getTable() => 'id', - 'glpi_tickettasks' => 'tickets_id' - ] - ]; - - return $criteria; - } - - - /** - * @deprecated 9.5.0 - */ - static function getCommonSelect() { - Toolbox::deprecated('Use getCommonCriteria with db iterator'); - $SELECT = ""; - if (count($_SESSION["glpiactiveentities"])>1) { - $SELECT .= ", `glpi_entities`.`completename` AS entityname, - `glpi_tickets`.`entities_id` AS entityID "; - } - - return " DISTINCT `glpi_tickets`.*, - `glpi_itilcategories`.`completename` AS catname - $SELECT"; - } - - - /** - * @deprecated 9.5.0 - */ - static function getCommonLeftJoin() { - Toolbox::deprecated('Use getCommonCriteria with db iterator'); - - $FROM = ""; - if (count($_SESSION["glpiactiveentities"])>1) { - $FROM .= " LEFT JOIN `glpi_entities` - ON (`glpi_entities`.`id` = `glpi_tickets`.`entities_id`) "; - } - - return " LEFT JOIN `glpi_groups_tickets` - ON (`glpi_tickets`.`id` = `glpi_groups_tickets`.`tickets_id`) - LEFT JOIN `glpi_tickets_users` - ON (`glpi_tickets`.`id` = `glpi_tickets_users`.`tickets_id`) - LEFT JOIN `glpi_suppliers_tickets` - ON (`glpi_tickets`.`id` = `glpi_suppliers_tickets`.`tickets_id`) - LEFT JOIN `glpi_itilcategories` - ON (`glpi_tickets`.`itilcategories_id` = `glpi_itilcategories`.`id`) - LEFT JOIN `glpi_tickettasks` - ON (`glpi_tickets`.`id` = `glpi_tickettasks`.`tickets_id`) - LEFT JOIN `glpi_items_tickets` - ON (`glpi_tickets`.`id` = `glpi_items_tickets`.`tickets_id`) - $FROM"; - - } - - - /** - * @param $output - **/ - static function showPreviewAssignAction($output) { - - //If ticket is assign to an object, display this information first - if (isset($output["entities_id"]) - && isset($output["items_id"]) - && isset($output["itemtype"])) { - - if ($item = getItemForItemtype($output["itemtype"])) { - if ($item->getFromDB($output["items_id"])) { - echo ""; - echo ""; - - echo ""; - echo ""; - } - } - - unset($output["items_id"]); - unset($output["itemtype"]); - } - unset($output["entities_id"]); - return $output; - } - - - /** - * Give cron information - * - * @param $name : task's name - * - * @return array of information - **/ - static function cronInfo($name) { - - switch ($name) { - case 'closeticket' : - return ['description' => __('Automatic tickets closing')]; - - case 'alertnotclosed' : - return ['description' => __('Not solved tickets')]; - - case 'createinquest' : - return ['description' => __('Generation of satisfaction surveys')]; - - case 'purgeticket': - return ['description' => __('Automatic closed tickets purge')]; - } - return []; - } - - - /** - * Cron for ticket's automatic close - * - * @param $task : crontask object - * - * @return integer (0 : nothing done - 1 : done) - **/ - static function cronCloseTicket($task) { - global $DB; - - $ticket = new self(); - - // Recherche des entit??s - $tot = 0; - - $entities = $DB->request( - [ - 'SELECT' => 'id', - 'FROM' => Entity::getTable(), - ] - ); - foreach ($entities as $entity) { - $delay = Entity::getUsedConfig('autoclose_delay', $entity['id'], '', Entity::CONFIG_NEVER); - if ($delay >= 0) { - $criteria = [ - 'FROM' => self::getTable(), - 'WHERE' => [ - 'entities_id' => $entity['id'], - 'status' => self::SOLVED, - 'is_deleted' => 0 - ] - ]; - - if ($delay > 0) { - $calendars_id = Entity::getUsedConfig('calendars_id', $entity['id']); - $calendar = new Calendar(); - if ($calendars_id && $calendar->getFromDB($calendars_id) && $calendar->hasAWorkingDay()) { - $end_date = $calendar->computeEndDate( - date('Y-m-d H:i:s'), - - $delay * DAY_TIMESTAMP, - 0, - true - ); - $criteria['WHERE']['solvedate'] = ['<=', $end_date]; - } else { - // no calendar, remove all days - $criteria['WHERE'][] = new \QueryExpression( - "ADDDATE(" . $DB->quoteName('solvedate') . ", INTERVAL $delay DAY) < NOW()" - ); - } - } - - $nb = 0; - $iterator = $DB->request($criteria); - while ($tick = $iterator->next()) { - $ticket->update([ - 'id' => $tick['id'], - 'status' => self::CLOSED, - '_auto_update' => true - ]); - $nb++; - } - - if ($nb) { - $tot += $nb; - $task->addVolume($nb); - $task->log(Dropdown::getDropdownName('glpi_entities', $entity['id'])." : $nb"); - } - } - } - - return ($tot > 0 ? 1 : 0); - } - - - /** - * Cron for alert old tickets which are not solved - * - * @param $task : crontask object - * - * @return integer (0 : nothing done - 1 : done) - **/ - static function cronAlertNotClosed($task) { - global $DB, $CFG_GLPI; - - if (!$CFG_GLPI["use_notifications"]) { - return 0; - } - // Recherche des entit??s - $tot = 0; - foreach (Entity::getEntitiesToNotify('notclosed_delay') as $entity => $value) { - $iterator = $DB->request([ - 'FROM' => self::getTable(), - 'WHERE' => [ - 'entities_id' => $entity, - 'is_deleted' => 0, - 'status' => [ - self::INCOMING, - self::ASSIGNED, - self::PLANNED, - self::WAITING - ], - 'closedate' => null, - new QueryExpression("ADDDATE(" . $DB->quoteName('date') . ", INTERVAL $value DAY) < NOW()") - ] - ]); - $tickets = []; - while ($tick = $iterator->next()) { - $tickets[] = $tick; - } - - if (!empty($tickets)) { - if (NotificationEvent::raiseEvent('alertnotclosed', new self(), - ['items' => $tickets, - 'entities_id' => $entity])) { - - $tot += count($tickets); - $task->addVolume(count($tickets)); - $task->log(sprintf(__('%1$s: %2$s'), - Dropdown::getDropdownName('glpi_entities', $entity), - count($tickets))); - } - } - } - - return ($tot > 0 ? 1 : 0); - } - - - /** - * Cron for ticketsatisfaction's automatic generated - * - * @param $task : crontask object - * - * @return integer (0 : nothing done - 1 : done) - **/ - static function cronCreateInquest($task) { - global $DB; - - $conf = new Entity(); - $inquest = new TicketSatisfaction(); - $tot = 0; - $maxentity = []; - $tabentities = []; - - $rate = Entity::getUsedConfig('inquest_config', 0, 'inquest_rate'); - if ($rate > 0) { - $tabentities[0] = $rate; - } - - foreach ($DB->request('glpi_entities') as $entity) { - $rate = Entity::getUsedConfig('inquest_config', $entity['id'], 'inquest_rate'); - $parent = Entity::getUsedConfig('inquest_config', $entity['id'], 'entities_id'); - - if ($rate > 0) { - $tabentities[$entity['id']] = $rate; - } - } - - foreach ($tabentities as $entity => $rate) { - $parent = Entity::getUsedConfig('inquest_config', $entity, 'entities_id'); - $delay = Entity::getUsedConfig('inquest_config', $entity, 'inquest_delay'); - $duration = Entity::getUsedConfig('inquest_config', $entity, 'inquest_duration'); - $type = Entity::getUsedConfig('inquest_config', $entity); - $max_closedate = Entity::getUsedConfig('inquest_config', $entity, 'max_closedate'); - - $table = self::getTable(); - $iterator = $DB->request([ - 'SELECT' => [ - "$table.id", - "$table.closedate", - "$table.entities_id" - ], - 'FROM' => $table, - 'LEFT JOIN' => [ - 'glpi_ticketsatisfactions' => [ - 'ON' => [ - 'glpi_ticketsatisfactions' => 'tickets_id', - 'glpi_tickets' => 'id' - ] - ], - 'glpi_entities' => [ - 'ON' => [ - 'glpi_tickets' => 'entities_id', - 'glpi_entities' => 'id' - ] - ] - ], - 'WHERE' => [ - "$table.entities_id" => $entity, - "$table.is_deleted" => 0, - "$table.status" => self::CLOSED, - "$table.closedate" => ['>', $max_closedate], - new QueryExpression("ADDDATE(" . $DB->quoteName("$table.closedate") . ", INTERVAL $delay DAY) <= NOW()"), - new QueryExpression("ADDDATE(" . $DB->quoteName("glpi_entities.max_closedate") . ", INTERVAL $duration DAY) <= NOW()"), - "glpi_ticketsatisfactions.id" => null - ], - 'ORDERBY' => 'closedate ASC' - ]); - - $nb = 0; - $max_closedate = ''; - - while ($tick = $iterator->next()) { - $max_closedate = $tick['closedate']; - if (mt_rand(1, 100) <= $rate) { - if ($inquest->add(['tickets_id' => $tick['id'], - 'date_begin' => $_SESSION["glpi_currenttime"], - 'entities_id' => $tick['entities_id'], - 'type' => $type])) { - $nb++; - } - } - } - - // conservation de toutes les max_closedate des entites filles - if (!empty($max_closedate) - && (!isset($maxentity[$parent]) - || ($max_closedate > $maxentity[$parent]))) { - $maxentity[$parent] = $max_closedate; - } - - if ($nb) { - $tot += $nb; - $task->addVolume($nb); - $task->log(sprintf(__('%1$s: %2$s'), - Dropdown::getDropdownName('glpi_entities', $entity), $nb)); - } - } - - // Sauvegarde du max_closedate pour ne pas tester les m??me tickets 2 fois - foreach ($maxentity as $parent => $maxdate) { - $conf->getFromDB($parent); - $conf->update(['id' => $conf->fields['id'], - //'entities_id' => $parent, - 'max_closedate' => $maxdate]); - } - - return ($tot > 0 ? 1 : 0); - } - - - /** - * Cron for ticket's automatic purge - * - * @param CronTask $task CronTask object - * - * @return integer (0 : nothing done - 1 : done) - **/ - static function cronPurgeTicket(CronTask $task) { - global $DB; - - $ticket = new self(); - - //search entities - $tot = 0; - - $entities = $DB->request( - [ - 'SELECT' => 'id', - 'FROM' => Entity::getTable(), - ] - ); - - foreach ($entities as $entity) { - $delay = Entity::getUsedConfig('autopurge_delay', $entity['id'], '', Entity::CONFIG_NEVER); - if ($delay >= 0) { - $criteria = [ - 'FROM' => $ticket->getTable(), - 'WHERE' => [ - 'entities_id' => $entity['id'], - 'status' => $ticket->getClosedStatusArray(), - ] - ]; - - if ($delay > 0) { - // remove all days - $criteria['WHERE'][] = new \QueryExpression("ADDDATE(`closedate`, INTERVAL ".$delay." DAY) < NOW()"); - } - - $iterator = $DB->request($criteria); - $nb = 0; - - foreach ($iterator as $tick) { - $ticket->delete( - [ - 'id' => $tick['id'], - '_auto_update' => true - ], - true - ); - $nb++; - } - - if ($nb) { - $tot += $nb; - $task->addVolume($nb); - $task->log(Dropdown::getDropdownName('glpi_entities', $entity['id'])." : $nb"); - } - } - } - - return ($tot > 0 ? 1 : 0); - } - - /** - * Display debug information for current object - **/ - function showDebug() { - NotificationEvent::debugEvent($this); - } - - - /** - * @since 0.85 - * - * @see commonDBTM::getRights() - **/ - function getRights($interface = 'central') { - - $values = parent::getRights(); - unset($values[READ]); - $values[self::READMY] = __('See my ticket'); - //TRANS: short for : See tickets created by my groups - $values[self::READGROUP] = ['short' => __('See group ticket'), - 'long' => __('See tickets created by my groups')]; - if ($interface == 'central') { - $values[self::READALL] = __('See all tickets'); - //TRANS: short for : See assigned tickets (group associated) - $values[self::READASSIGN] = ['short' => __('See assigned'), - 'long' => __('See assigned tickets')]; - //TRANS: short for : Assign a ticket - $values[self::ASSIGN] = ['short' => __('Assign'), - 'long' => __('Assign a ticket')]; - //TRANS: short for : Steal a ticket - $values[self::STEAL] = ['short' => __('Steal'), - 'long' => __('Steal a ticket')]; - //TRANS: short for : To be in charge of a ticket - $values[self::OWN] = ['short' => __('Beeing in charge'), - 'long' => __('To be in charge of a ticket')]; - $values[self::CHANGEPRIORITY] = __('Change the priority'); - $values[self::SURVEY] = ['short' => __('Approve solution/Reply survey (my ticket)'), - 'long' => __('Approve solution and reply to survey for ticket created by me')]; - } - if ($interface == 'helpdesk') { - unset($values[UPDATE], $values[DELETE], $values[PURGE]); - } - return $values; - } - - /** - * Convert img of the collector for ticket - * - * @since 0.85 - * - * @param string $html html content of input - * @param array $files filenames - * @param array $tags image tags - * - * @return string html content - **/ - static function convertContentForTicket($html, $files, $tags) { - - preg_match_all("/src\s*=\s*['|\"](.+?)['|\"]/", $html, $matches, PREG_PATTERN_ORDER); - if (isset($matches[1]) && count($matches[1])) { - // Get all image src - - foreach ($matches[1] as $src) { - // Set tag if image matches - foreach ($files as $data => $filename) { - if (preg_match("/".$data."/i", $src)) { - $html = preg_replace("`]*\>`", "

".Document::getImageTag($tags[$filename])."

", $html); - } - } - } - } - - return $html; - - } - - - /** - * @since 0.90 - * - * @param $tickets_id - * @param $action (default 'add') - **/ - static function getSplittedSubmitButtonHtml($tickets_id, $action = "add") { - - $locale = _sx('button', 'Add'); - if ($action == 'update') { - $locale = _x('button', 'Save'); - } - $ticket = new self(); - $ticket->getFromDB($tickets_id); - $all_status = Ticket::getAllowedStatusArray($ticket->fields['status']); - $rand = mt_rand(); - - $html = "
- -   -
    "; - foreach ($all_status as $status_key => $status_label) { - $checked = ""; - if ($status_key == $ticket->fields['status']) { - $checked = "checked='checked'"; - } - $html .= "
  • "; - $html .= ""; - $html .= ""; - $html .= "
  • "; - } - $html .= "
"; - - $html.= ""; - return $html; - } - - - /** - * Get correct Calendar: Entity or Sla - * - * @since 0.90.4 - * - **/ - function getCalendar() { - - if (isset($this->fields['slas_id_ttr']) && $this->fields['slas_id_ttr'] > 0) { - $slm = new SLM(); - if ($slm->getFromDB($this->fields['slas_id_ttr'])) { - // not -1: calendar of the entity - if ($slm->getField('calendars_id') >= 0) { - return $slm->getField('calendars_id'); - } - } - } - return parent::getCalendar(); - } - - - /** - * Select a field using standard system - * - * @since 9.1 - */ - function getValueToSelect($field_id_or_search_options, $name = '', $values = '', $options = []) { - if (isset($field_id_or_search_options['linkfield'])) { - switch ($field_id_or_search_options['linkfield']) { - case 'requesttypes_id': - if (isset($field_id_or_search_options['joinparams']) && Toolbox::in_array_recursive('glpi_itilfollowups', $field_id_or_search_options['joinparams'])) { - $opt = ['is_itilfollowup' => 1]; - } else { - $opt = [ - 'OR' => [ - 'is_mail_default' => 1, - 'is_ticketheader' => 1 - ] - ]; - } - if ($field_id_or_search_options['linkfield'] == $name) { - $opt['is_active'] = 1; - } - if (isset( $options['condition'] )) { - if (!is_array($options['condition'])) { - $options['condition'] = [$options['condition']]; - } - $opt = array_merge($opt, $options['condition']); - } - $options['condition'] = $opt; - break; - } - } - return parent::getValueToSelect($field_id_or_search_options, $name, $values, $options); - } - - function showStatsDates() { - $now = time(); - $date_creation = strtotime($this->fields['date']); - $date_takeintoaccount = $date_creation + $this->fields['takeintoaccount_delay_stat']; - if ($date_takeintoaccount == $date_creation) { - $date_takeintoaccount = 0; - } - $internal_time_to_own = strtotime($this->fields['internal_time_to_own']); - $time_to_own = strtotime($this->fields['time_to_own']); - $internal_time_to_resolve = strtotime($this->fields['internal_time_to_resolve']); - $time_to_resolve = strtotime($this->fields['time_to_resolve']); - $solvedate = strtotime($this->fields['solvedate']); - $closedate = strtotime($this->fields['closedate']); - $goal_takeintoaccount = ($date_takeintoaccount > 0 ? $date_takeintoaccount : $now); - $goal_solvedate = ($solvedate > 0 ? $solvedate : $now); - - $sla = new SLA; - $ola = new OLA; - $sla_tto_link = - $sla_ttr_link = - $ola_tto_link = - $ola_ttr_link = ""; - - if ($sla->getFromDB($this->fields['slas_id_tto'])) { - $sla_tto_link = " - "; - } - if ($sla->getFromDB($this->fields['slas_id_ttr'])) { - $sla_ttr_link = " - "; - } - if ($ola->getFromDB($this->fields['olas_id_tto'])) { - $ola_tto_link = " - "; - } - if ($ola->getFromDB($this->fields['olas_id_ttr'])) { - $ola_ttr_link = " - "; - } - - $dates = [ - $date_creation.'_date_creation' => [ - 'timestamp' => $date_creation, - 'label' => __('Opening date'), - 'class' => 'creation' - ], - $date_takeintoaccount.'_date_takeintoaccount' => [ - 'timestamp' => $date_takeintoaccount, - 'label' => __('Take into account'), - 'class' => 'checked' - ], - $internal_time_to_own.'_internal_time_to_own' => [ - 'timestamp' => $internal_time_to_own, - 'label' => __('Internal time to own')." ".$ola_tto_link, - 'class' => ($internal_time_to_own < $goal_takeintoaccount - ? 'passed' : '')." ". - ($date_takeintoaccount != '' - ? 'checked' : ''), - ], - $time_to_own.'_time_to_own' => [ - 'timestamp' => $time_to_own, - 'label' => __('Time to own')." ".$sla_tto_link, - 'class' => ($time_to_own < $goal_takeintoaccount - ? 'passed' : '')." ". - ($date_takeintoaccount != '' - ? 'checked' : ''), - ], - $internal_time_to_resolve.'_internal_time_to_resolve' => [ - 'timestamp' => $internal_time_to_resolve, - 'label' => __('Internal time to resolve')." ".$ola_ttr_link, - 'class' => ($internal_time_to_resolve < $goal_solvedate - ? 'passed' : '')." ". - ($solvedate != '' - ? 'checked' : '') - ], - $time_to_resolve.'_time_to_resolve' => [ - 'timestamp' => $time_to_resolve, - 'label' => __('Time to resolve')." ".$sla_ttr_link, - 'class' => ($time_to_resolve < $goal_solvedate - ? 'passed' : '')." ". - ($solvedate != '' - ? 'checked' : '') - ], - $solvedate.'_solvedate' => [ - 'timestamp' => $solvedate, - 'label' => __('Resolution date'), - 'class' => 'checked' - ], - $closedate.'_closedate' => [ - 'timestamp' => $closedate, - 'label' => __('Closing date'), - 'class' => 'end' - ] - ]; - - Html::showDatesTimelineGraph([ - 'title' => _n('Date', 'Dates', Session::getPluralNumber()), - 'dates' => $dates, - 'add_now' => $this->getField('closedate') == "" - ]); - } - - /** - * Fill input with values related to business rules. - * - * @param array $input - * - * @return void - */ - private function fillInputForBusinessRules(array &$input) { - global $DB; - - $entities_id = isset($input['entities_id']) - ? $input['entities_id'] - : $this->fields['entities_id']; - - // If creation date is not set, then we're called during ticket creation - $creation_date = !empty($this->fields['date_creation']) - ? strtotime($this->fields['date_creation']) - : time(); - - // add calendars matching date creation (for business rules) - $calendars = []; - $ite_calendar = $DB->request([ - 'SELECT' => ['id'], - 'FROM' => Calendar::getTable(), - 'WHERE' => getEntitiesRestrictCriteria('', '', $entities_id, true) - ]); - foreach ($ite_calendar as $calendar_data) { - $calendar = new Calendar(); - $calendar->getFromDB($calendar_data['id']); - if ($calendar->isAWorkingHour($creation_date)) { - $calendars[] = $calendar_data['id']; - } - } - if (count($calendars)) { - $input['_date_creation_calendars_id'] = $calendars; - } - } - - /** - * Build parent condition for search - * - * @param string $fieldID field used in the condition: tickets_id, items_id - * - * @return string - */ - public static function buildCanViewCondition($fieldID) { - - $condition = ""; - $user = Session::getLoginUserID(); - $groups = "'" . implode("','", $_SESSION['glpigroups']) . "'"; - - $requester = CommonITILActor::REQUESTER; - $assign = CommonITILActor::ASSIGN; - $obs = CommonITILActor::OBSERVER; - - // Avoid empty IN () - if ($groups == "''") { - $groups = '-1'; - } - - if (Session::haveRight("ticket", Ticket::READMY)) { - // Add tickets where the users is requester, observer or recipient - // Subquery for requester/observer user - $user_query = "SELECT `tickets_id` - FROM `glpi_tickets_users` - WHERE `users_id` = '$user' AND type IN ($requester, $obs)"; - $condition .= "OR `$fieldID` IN ($user_query) "; - - // Subquery for recipient - $recipient_query = "SELECT `id` - FROM `glpi_tickets` - WHERE `users_id_recipient` = '$user'"; - $condition .= "OR `$fieldID` IN ($recipient_query) "; - } - - if (Session::haveRight("ticket", Ticket::READGROUP)) { - // Add tickets where the users is in a requester or observer group - // Subquery for requester/observer group - $group_query = "SELECT `tickets_id` - FROM `glpi_groups_tickets` - WHERE `groups_id` IN ($groups) AND type IN ($requester, $obs)"; - $condition .= "OR `$fieldID` IN ($group_query) "; - } - - if (Session::haveRightsOr("ticket", [ - Ticket::OWN, - Ticket::READASSIGN - ])) { - // Add tickets where the users is assigned - // Subquery for assigned user - $user_query = "SELECT `tickets_id` - FROM `glpi_tickets_users` - WHERE `users_id` = '$user' AND type = $assign"; - $condition .= "OR `$fieldID` IN ($user_query) "; - } - - if (Session::haveRight("ticket", Ticket::READASSIGN)) { - // Add tickets where the users is part of an assigned group - // Subquery for assigned group - $group_query = "SELECT `tickets_id` - FROM `glpi_groups_tickets` - WHERE `groups_id` IN ($groups) AND type = $assign"; - $condition .= "OR `$fieldID` IN ($group_query) "; - - if (Session::haveRight('ticket', Ticket::ASSIGN)) { - // Add new tickets - $tickets_query = "SELECT `id` - FROM `glpi_tickets` - WHERE `status` = '" . CommonITILObject::INCOMING . "'"; - $condition .= "OR `$fieldID` IN ($tickets_query) "; - } - } - - if (Session::haveRightsOr('ticketvalidation', [ - TicketValidation::VALIDATEINCIDENT, - TicketValidation::VALIDATEREQUEST - ])) { - // Add tickets where the users is the validator - // Subquery for validator - $validation_query = "SELECT `tickets_id` - FROM `glpi_ticketvalidations` - WHERE `users_id_validate` = '$user'"; - $condition .= "OR `$fieldID` IN ($validation_query) "; - } - - return $condition; - } - - public function getForbiddenSingleMassiveActions() { - $excluded = parent::getForbiddenSingleMassiveActions(); - if (in_array($this->fields['status'], $this->getClosedStatusArray())) { - //for closed Tickets, only keep transfer and unlock - $excluded[] = 'TicketValidation:submit_validation'; - $excluded[] = 'Ticket:*'; - } - return $excluded; - } - - public function getWhitelistedSingleMassiveActions() { - $whitelist = parent::getWhitelistedSingleMassiveActions(); - - if (!in_array($this->fields['status'], $this->getClosedStatusArray())) { - $whitelist[] = 'Item_Ticket:add_item'; - } - - return $whitelist; - } - - /** - * Merge one or more tickets into another existing ticket. - * Optionally sub-items like followups, documents, and tasks can be copied into the merged ticket. - * If a ticket cannot be merged, the process continues on to the next ticket. - * @param int $merge_target_id The ID of the ticket that the other tickets will be merged into - * @param array $ticket_ids Array of IDs of tickets to merge into the ticket with ID $merge_target_id - * @param array $params Array of parameters for the ticket merge. - * linktypes - Array of itemtypes that will be duplicated into the ticket $merge_target_id. - * By default, no sub-items are copied. Currently supported link types are ITILFollowup, Document, and TicketTask. - * full_transaction - Boolean value indicating if the entire merge must complete successfully, or if partial merges are allowed. - * By default, the full merge must complete. On failure, all database operations performed are rolled back. - * link_type - Integer indicating the link type of the merged tickets (See types in Ticket_Ticket). - * By default, this is Ticket_Ticket::SON_OF. To disable linking, use 0 or a negative value. - * append_actors - Array of actor types to migrate into the ticket $merge_ticket. See types in CommonITILActor. - * By default, all actors are added to the ticket. - * @param array $status Reference array that this function uses to store the status of each ticket attempted to be merged. - * id => status (0 = Success, 1 = Error, 2 = Insufficient Rights). - * @return boolean True if the merge was successful if "full_transaction" is true. - * Otherwise, true if any ticket was successfully merged. - * @since 9.5.0 - */ - public static function merge(int $merge_target_id, array $ticket_ids, array &$status, array $params = []) { - global $DB; - $p = [ - 'linktypes' => [], - 'full_transaction' => true, - 'link_type' => Ticket_Ticket::SON_OF, - 'append_actors' => [CommonITILActor::REQUESTER, CommonITILActor::OBSERVER, CommonITILActor::ASSIGN] - ]; - $p = array_replace($p, $params); - $ticket = new Ticket(); - $merge_target = new Ticket(); - $merge_target->getFromDB($merge_target_id); - $fup = new ITILFollowup(); - $document_item = new Document_Item(); - $task = new TicketTask(); - - if (!$merge_target->canAddFollowups()) { - foreach ($ticket_ids as $id) { - Toolbox::logError(sprintf(__('Not enough rights to merge tickets %d and %d'), $merge_target_id, $id)); - // Set status = 2 : Rights issue - $status[$id] = 2; - } - return false; - } - $in_transaction = $DB->inTransaction(); - - if ($p['full_transaction'] && !$in_transaction) { - $DB->beginTransaction(); - } - foreach ($ticket_ids as $id) { - try { - if (!$p['full_transaction'] && !$in_transaction) { - $DB->beginTransaction(); - } - if ($merge_target->canUpdateItem() && $ticket->can($id, DELETE)) { - if (!$ticket->getFromDB($id)) { - //Cannot retrieve ticket. Abort/fail the merge - throw new \RuntimeException(sprintf(__('Failed to load ticket %d'), $id), 1); - } - //Build followup from the original ticket - $input = [ - 'itemtype' => 'Ticket', - 'items_id' => $merge_target_id, - 'content' => $DB->escape($ticket->fields['name']."\n\n".$ticket->fields['content']), - 'users_id' => $ticket->fields['users_id_recipient'], - 'date_creation' => $ticket->fields['date_creation'], - 'date_mod' => $ticket->fields['date_mod'], - 'date' => $ticket->fields['date_creation'], - 'sourceitems_id' => $ticket->getID() - ]; - if (!$fup->add($input)) { - //Cannot add followup. Abort/fail the merge - throw new \RuntimeException(sprintf(__('Failed to add followup to ticket %d'), $merge_target_id), 1); - } - if (in_array('ITILFollowup', $p['linktypes'])) { - // Copy any followups to the ticket - $tomerge = $fup->find([ - 'items_id' => $id, - 'itemtype' => 'Ticket' - ]); - foreach ($tomerge as $fup2) { - $fup2['items_id'] = $merge_target_id; - $fup2['sourceitems_id'] = $id; - $fup2['content'] = $DB->escape($fup2['content']); - unset($fup2['id']); - if (!$fup->add($fup2)) { - // Cannot add followup. Abort/fail the merge - throw new \RuntimeException(sprintf(__('Failed to add followup to ticket %d'), $merge_target_id), 1); - } - } - } - if (in_array('TicketTask', $p['linktypes'])) { - $merge_tmp = ['tickets_id' => $merge_target_id]; - if (!$task->can(-1, CREATE, $merge_tmp)) { - throw new \RuntimeException(sprintf(__('Not enough rights to merge tickets %d and %d'), $merge_target_id, $id), 2); - } - // Copy any tasks to the ticket - $tomerge = $task->find([ - 'tickets_id' => $id - ]); - foreach ($tomerge as $task2) { - $task2['tickets_id'] = $merge_target_id; - $task2['sourceitems_id'] = $id; - $task2['content'] = $DB->escape($task2['content']); - unset($task2['id']); - unset($task2['uuid']); - if (!$task->add($task2)) { - //Cannot add followup. Abort/fail the merge - throw new \RuntimeException(sprintf(__('Failed to add task to ticket %d'), $merge_target_id), 1); - } - } - } - if (in_array('Document', $p['linktypes'])) { - if (!$merge_target->canAddItem('Document')) { - throw new \RuntimeException(sprintf(__('Not enough rights to merge tickets %d and %d'), $merge_target_id, $id), 2); - } - $tomerge = $document_item->find([ - 'itemtype' => 'Ticket', - 'items_id' => $id, - 'NOT' => [ - 'documents_id' => new \QuerySubQuery([ - 'SELECT' => 'documents_id', - 'FROM' => $document_item->getTable(), - 'WHERE' => [ - 'itemtype' => 'Ticket', - 'items_id' => $merge_target_id - ] - ]) - ] - ]); - - foreach ($tomerge as $document_item2) { - $document_item2['items_id'] = $merge_target_id; - unset($document_item2['id']); - if (!$document_item->add($document_item2)) { - //Cannot add document. Abort/fail the merge - throw new \RuntimeException(sprintf(__('Failed to add document to ticket %d'), $merge_target_id), 1); - } - } - } - if ($p['link_type'] > 0 && $p['link_type'] < 5) { - //Add relation (this is parent of merge target) - $tt = new Ticket_Ticket(); - $linkparams = [ - 'link' => $p['link_type'], - 'tickets_id_1' => $id, - 'tickets_id_2' => $merge_target_id - ]; - $tt->deleteByCriteria([ - 'OR' => [ - [ - 'AND' => [ - 'tickets_id_1' => $merge_target_id, - 'tickets_id_2' => $id - ] - ], - [ - 'AND' => [ - 'tickets_id_2' => $merge_target_id, - 'tickets_id_1' => $id - ] - ] - ] - ]); - if (!$tt->add($linkparams)) { - //Cannot link tickets. Abort/fail the merge - throw new \RuntimeException(sprintf(__('Failed to link tickets %d and %d'), $merge_target_id, $id), 1); - } - } - if (isset($p['append_actors'])) { - $tu = new Ticket_User(); - $existing_users = $tu->find(['tickets_id' => $merge_target_id]); - $gt = new Group_Ticket(); - $existing_groups = $gt->find(['tickets_id' => $merge_target_id]); - $st = new Supplier_Ticket(); - $existing_suppliers = $st->find(['tickets_id' => $merge_target_id]); - - foreach ($p['append_actors'] as $actor_type) { - $users = $tu->find([ - 'tickets_id' => $id, - 'type' => $actor_type - ]); - $groups = $gt->find([ - 'tickets_id' => $id, - 'type' => $actor_type - ]); - $suppliers = $st->find([ - 'tickets_id' => $id, - 'type' => $actor_type - ]); - $users = array_filter($users, function($user) use ($existing_users) { - foreach ($existing_users as $existing_user) { - if ($existing_user['users_id'] > 0 && $user['users_id'] > 0 && - $existing_user['users_id'] === $user['users_id'] && - $existing_user['type'] === $user['type']) { - // Internal users - return false; - } else if ($existing_user['users_id'] == 0 && $user['users_id'] == 0 && - $existing_user['alternative_email'] === $user['alternative_email'] && - $existing_user['type'] === $user['type']) { - // External users - return false; - } - } - return true; - }); - $groups = array_filter($groups, function($group) use ($existing_groups) { - foreach ($existing_groups as $existing_group) { - if ($existing_group['groups_id'] === $group['groups_id'] && - $existing_group['type'] === $group['type']) { - return false; - } - } - return true; - }); - $suppliers = array_filter($suppliers, function($supplier) use ($existing_suppliers) { - foreach ($existing_suppliers as $existing_supplier) { - if ($existing_supplier['suppliers_id'] > 0 && $supplier['suppliers_id'] > 0 && - $existing_supplier['suppliers_id'] === $supplier['suppliers_id'] && - $existing_supplier['type'] === $supplier['type']) { - // Internal suppliers - return false; - } else if ($existing_supplier['suppliers_id'] == 0 && $supplier['suppliers_id'] == 0 && - $existing_supplier['alternative_email'] === $supplier['alternative_email'] && - $existing_supplier['type'] === $supplier['type']) { - // External suppliers - return false; - } - } - return true; - }); - foreach ($users as $user) { - $user['tickets_id'] = $merge_target_id; - unset($user['id']); - $tu->add($user); - } - foreach ($groups as $group) { - $group['tickets_id'] = $merge_target_id; - unset($group['id']); - $gt->add($group); - } - foreach ($suppliers as $supplier) { - $supplier['tickets_id'] = $merge_target_id; - unset($supplier['id']); - $st->add($supplier); - } - } - } - //Delete this ticket - if (!$ticket->delete(['id' => $id, '_disablenotif' => true])) { - throw new \RuntimeException(sprintf(__('Failed to delete ticket %d'), $id), 1); - } - if (!$p['full_transaction'] && !$in_transaction) { - $DB->commit(); - } - $status[$id] = 0; - Event::log($merge_target_id, 'ticket', 4, 'tracking', - sprintf(__('%s merges ticket %s into %s'), $_SESSION['glpiname'], - $id, $merge_target_id)); - } else { - throw new \RuntimeException(sprintf(__('Not enough rights to merge tickets %d and %d'), $merge_target_id, $id), 2); - } - } catch (\RuntimeException $e) { - if ($e->getCode() < 1 || $e->getCode() > 2) { - $status[$id] = 1; - } else { - $status[$id] = $e->getCode(); - } - Toolbox::logError($e->getMessage()); - if (!$in_transaction) { - $DB->rollBack(); - } - if ($p['full_transaction']) { - return false; - } - } - } - if ($p['full_transaction'] && !$in_transaction) { - $DB->commit(); - } - return true; - } - - - static function getIcon() { - return "fas fa-exclamation-circle"; - } -} diff --git a/debian/CAS-1.3.8.tgz b/debian/CAS-1.3.8.tgz deleted file mode 100644 index eb5c0ee..0000000 Binary files a/debian/CAS-1.3.8.tgz and /dev/null differ diff --git a/debian/Dockerfile b/debian/Dockerfile deleted file mode 100644 index 4856f2d..0000000 --- a/debian/Dockerfile +++ /dev/null @@ -1,50 +0,0 @@ -FROM php:7.4-apache-buster -MAINTAINER Benoit LORAND - -WORKDIR /root -ENV GLPI_CONFIG_DIR=/etc/glpi -ENV GLPI_VAR_DIR=/var/lib/glpi -ENV GLPI_LOG_DIR=/var/log/glpi -ENV GLPI_VERSION=9.5.1 -ENV FUSIONINVENTORY_VERSION=9.5.0+1.0 - -RUN \ -apt-get update && \ -apt-get install --no-install-recommends -y \ - runit \ - cron \ - libbz2-dev \ - libzip-dev \ - libxml2-dev \ - libldap2-dev \ - libicu-dev \ - libpng-dev \ - zlib1g-dev \ - default-mysql-client \ - && \ -pecl install apcu && docker-php-ext-enable apcu && \ -docker-php-ext-configure mysqli && docker-php-ext-install mysqli && \ -docker-php-ext-configure gd && docker-php-ext-install gd && \ -docker-php-ext-configure intl && docker-php-ext-install intl && \ -docker-php-ext-configure ldap && docker-php-ext-install ldap && \ -docker-php-ext-configure xmlrpc && docker-php-ext-install xmlrpc && \ -docker-php-ext-configure exif && docker-php-ext-install exif && \ -docker-php-ext-configure zip && docker-php-ext-install zip && \ -docker-php-ext-configure bz2 && docker-php-ext-install bz2 && \ -docker-php-ext-configure opcache && docker-php-ext-install opcache - -COPY CAS-1.3.8.tgz /root/ -RUN pear install /root/CAS-1.3.8.tgz -COPY service/ /etc/service/ -COPY glpi_init.sh /root/glpi_init.sh -COPY glpi.cron /etc/cron.d/glpi -ADD https://github.com/glpi-project/glpi/releases/download/${GLPI_VERSION}/glpi-${GLPI_VERSION}.tgz /root/glpi-${GLPI_VERSION}.tgz -ADD https://github.com/fusioninventory/fusioninventory-for-glpi/releases/download/glpi${FUSIONINVENTORY_VERSION}/fusioninventory-${FUSIONINVENTORY_VERSION}.tar.bz2 /root/fusioninventory-${FUSIONINVENTORY_VERSION}.tar.bz2 - -RUN \ -chmod a+x /root/glpi_init.sh && \ -rm -f /var/www/html/* /root/CAS-1.3.8.tgz && \ -apt-get clean && \ -rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - -ENTRYPOINT ["/usr/bin/runsvdir", "-P", "/etc/service"] diff --git a/debian/README.md b/debian/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/debian/docker-compose.yml b/debian/docker-compose.yml deleted file mode 100644 index 917a90c..0000000 --- a/debian/docker-compose.yml +++ /dev/null @@ -1,26 +0,0 @@ -version: '3.5' -services: - web: - container_name: glpi-web - build: . - restart: always - ports: - - 8089:80 - volumes: - - ./etc/:/etc/glpi/ - - ./files/:/var/lib/glpi/ - - ./log/:/var/log/glpi/ - env_file: - - ./mysql_settings.ini - depends_on: - - db - - db: - image: mariadb - container_name: glpi-db - command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci - restart: always - env_file: - - ./mysql_settings.ini - volumes: - - ./db/:/var/lib/mysql/ diff --git a/debian/glpi.cron b/debian/glpi.cron deleted file mode 100644 index 1b31779..0000000 --- a/debian/glpi.cron +++ /dev/null @@ -1,5 +0,0 @@ -GLPI_CONFIG_DIR=/etc/glpi -GLPI_VAR_DIR=/var/lib/glpi -GLPI_LOG_DIR=/var/log/glpi - -*/1 * * * * www-data /usr/local/bin/php /var/www/html/front/cron.php diff --git a/debian/glpi_init.sh b/debian/glpi_init.sh deleted file mode 100644 index 8843288..0000000 --- a/debian/glpi_init.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/sh -GLPI_TARBALL="/root/glpi-9.5.1.tgz" -FUSION_TARBALL="/root/fusioninventory-9.5.0+1.0.tar.bz2" -NORMAL='\e[39m' -RED='\e[31m' -GREEN='\e[32m' - -msglog() { - case "${1}" in - green) - TEXT_COLOR="${GREEN}" - ;; - red) - TEXT_COLOR="${RED}" - ;; - normal) - TEXT_COLOR="${NORMAL}" - ;; - esac - DATE=$(date '+%Y %b %d %H:%M:%S') - echo ${DATE} ${TEXT_COLOR}${2}${NORMAL} -} - -waiting_for_db() { -while ! mysqlshow -h db -uroot -p${MYSQL_ROOT_PASSWORD} 2>&1 | grep "^| ${MYSQL_DATABASE}" > /dev/null 2>&1 ; do - msglog red "Waiting for mysql database initilization..." - sleep 5 -done -} - - -if [ -z "$(ls -A /var/www/html)" ] ; then - waiting_for_db - msglog red "Initialazing ${GLPI_TARBALL}..." - cd /root - tar xf ${GLPI_TARBALL} - cp -r /root/glpi/config/. /etc/glpi/. - cp -r /root/glpi/files/. /var/lib/glpi/. - rm -r /root/glpi/config /root/glpi/files - cp -r /root/glpi/. /var/www/html/. - cd /var/www/html/plugins - tar xf ${FUSION_TARBALL} - rm -r /root/glpi - mysql --host=db --user=root --password=${MYSQL_ROOT_PASSWORD} << EOF -use mysql; -GRANT SELECT ON time_zone_name TO '${MYSQL_USER}'@'%'; -EOF - cd /var/www/html - php bin/console db:install --config-dir=${GLPI_CONFIG_DIR} -L fr_FR -H db -d ${MYSQL_DATABASE} -u ${MYSQL_USER} -p ${MYSQL_PASSWORD} -n - php bin/console glpi:plugin:install -u glpi fusioninventory -n - php bin/console glpi:plugin:activate fusioninventory -n - rm install/install.php - chown -R www-data:www-data /var/www/html /etc/glpi /var/lib/glpi /var/log/glpi - msglog green "Initialazing complete..." -else - msglog green "GLPI is already initialized" - cd /var/www/html - GLPI_ACTUAL_VERSION=$(awk -F", '" '/^define\(.GLPI_VERSION/ { print $2 }' inc/define.php | sed 's/\([0-9\.]*\).*/\1/') - FUSIONINVENTORY_ACTUAL_VERSION=$(awk -F', "' '/^define \(.PLUGIN_FUSIONINVENTORY_VERSION/ { print $2 }' plugins/fusioninventory/setup.php | sed 's/\([0-9\.+]*\).*/\1/') - if [ "${GLPI_ACTUAL_VERSION}" = "${GLPI_VERSION}" -a "${FUSIONINVENTORY_ACTUAL_VERSION}" = "${FUSIONINVENTORY_VERSION}" ] ; then - msglog green "GLPI already up2date" - exit - fi - msglog red "Updating GLPI from ${GLPI_ACTUAL_VERSION} to ${GLPI_VERSION}" - waiting_for_db - php bin/console glpi:maintenance:enable -n - php bin/console glpi:plugin:deactivate fusioninventory -n - cd /root - tar xf ${GLPI_TARBALL} - rm -r glpi/config glpi/files /var/www/html - mv glpi /var/www/html - cd /var/www/html/plugins - tar xf ${FUSION_TARBALL} - rm /var/www/html/install/install.php - cd /var/www/html - php bin/console db:update --config-dir=${GLPI_CONFIG_DIR} -n - php bin/console glpi:maintenance:disable -n - chown -R www-data:www-data /var/www/html /etc/glpi /var/lib/glpi /var/log/glpi -fi diff --git a/debian/mysql_settings.ini b/debian/mysql_settings.ini deleted file mode 100644 index b66e7ca..0000000 --- a/debian/mysql_settings.ini +++ /dev/null @@ -1,4 +0,0 @@ -MYSQL_DATABASE= -MYSQL_USER= -MYSQL_PASSWORD='' -MYSQL_ROOT_PASSWORD='' diff --git a/debian/service/20-cron/run b/debian/service/20-cron/run deleted file mode 100755 index 2c89471..0000000 --- a/debian/service/20-cron/run +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -. /etc/service/template - -msglog green "Starting Cron..." -# Touch cron files to fix 'NUMBER OF HARD LINKS > 1' issue. See https://github.com/phusion/baseimage-docker/issues/198 -touch -c /etc/crontab /etc/cron.*/* /var/spool/cron/crontabs/* -exec /usr/sbin/cron -f diff --git a/debian/service/30-apache2/run b/debian/service/30-apache2/run deleted file mode 100755 index bb78cc5..0000000 --- a/debian/service/30-apache2/run +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -. /etc/service/template - -msglog green "Starting Apache..." -exec apache2-foreground diff --git a/debian/service/90-glpi_init/run b/debian/service/90-glpi_init/run deleted file mode 100755 index 767ea4b..0000000 --- a/debian/service/90-glpi_init/run +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -. /etc/service/template - -msglog green "Starting glpi_init.sh..." -/root/glpi_init.sh -sleep infinity diff --git a/debian/service/template b/debian/service/template deleted file mode 100644 index 70543c1..0000000 --- a/debian/service/template +++ /dev/null @@ -1,19 +0,0 @@ -NORMAL='\e[39m' -RED='\e[31m' -GREEN='\e[32m' - -msglog() { - case "${1}" in - green) - TEXT_COLOR="${GREEN}" - ;; - red) - TEXT_COLOR="${RED}" - ;; - normal) - TEXT_COLOR="${NORMAL}" - ;; - esac - DATE=$(date '+%Y %b %d %H:%M:%S') - echo ${DATE} ${TEXT_COLOR}${2}${NORMAL} -} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..4d01be7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,64 @@ +version: '3.5' +services: + web: + container_name: glpi-web + build: web-builder + restart: always + volumes: + - ./etc/:/etc/glpi/ + - ./files/:/var/lib/glpi/ + - ./log/:/var/log/glpi/ + - /etc/localtime:/etc/localtime:ro + env_file: + - ./mysql_settings.ini + environment: + - PHP_MEMORY_LIMIT=256M + - PHP_UPLOAD_MAX_FILESIZE=20M + - PHP_POST_MAX_SIZE=40M + - PHP_SESSION_GC_MAXLIFETIME=14400 + - PHP_DATE_TIMEZONE=Europe/Paris + - PHP_MAX_INPUT_VARS=100000 + depends_on: + - db + - redis + + cron: + container_name: glpi-cron + image : glpi-web:latest + restart: always + volumes: + - ./etc/:/etc/glpi/ + - ./files/:/var/lib/glpi/ + - ./log/:/var/log/glpi/ + - /etc/localtime:/etc/localtime:ro + env_file: + - ./mysql_settings.ini + environment: + - PHP_MEMORY_LIMIT=256M + - PHP_UPLOAD_MAX_FILESIZE=20M + - PHP_POST_MAX_SIZE=40M + - PHP_SESSION_GC_MAXLIFETIME=14400 + - PHP_DATE_TIMEZONE=Europe/Paris + entrypoint: /etc/service/cron + depends_on: + - db + - web + + db: + image: mariadb + container_name: glpi-db + command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci + restart: always + env_file: + - ./mysql_settings.ini + volumes: + - ./db/:/var/lib/mysql/ + - /etc/localtime:/etc/localtime:ro + + redis: + container_name: glpi-redis + image: redis:latest + volumes: + - ./cache:/data + restart: "always" + diff --git a/alpine/web-builder/CAS-1.3.8.tgz b/web-builder/CAS-1.3.8.tgz similarity index 100% rename from alpine/web-builder/CAS-1.3.8.tgz rename to web-builder/CAS-1.3.8.tgz diff --git a/web-builder/Dockerfile b/web-builder/Dockerfile new file mode 100644 index 0000000..aff2ad9 --- /dev/null +++ b/web-builder/Dockerfile @@ -0,0 +1,81 @@ +FROM alpine +MAINTAINER Benoit LORAND + +WORKDIR /root +ENV GLPI_CONFIG_DIR=/etc/glpi +ENV GLPI_VAR_DIR=/var/lib/glpi +ENV GLPI_LOG_DIR=/var/log/glpi +ENV GLPI_VERSION=10.0.14 +ENV FIELDS_VERSION=1.21.8 +ENV DATAINJECTION_VERSION=2.13.5 +ENV GLPIINVENTORY_VERSION=1.3.5 + + +RUN \ +apk add --no-cache \ + php82-apache2 \ + php82 \ + mariadb-client \ + php82-pecl-apcu \ + php82-pecl-redis \ + php82-mysqli \ + php82-gd \ + php82-intl \ + php82-ldap \ + php82-xml \ + php82-xmlreader \ + php82-xmlwriter \ + php82-exif \ + php82-zip \ + php82-bz2 \ + php82-opcache \ + php82-pear \ + php82-curl \ + php82-dom \ + php82-pdo \ + php82-json \ + php82-session \ + php82-ctype \ + php82-fileinfo \ + php82-mbstring \ + php82-simplexml \ + php82-iconv \ + php82-sodium \ + php82-imap \ + php82-pdo \ + php82-pdo_mysql \ + php82-pspell \ + php82-phar \ + patch + +COPY CAS-1.3.8.tgz /root/ +RUN pear82 install /root/CAS-1.3.8.tgz && \ +pear82 install Archive_Tar +COPY httpd.conf /etc/apache2 +COPY remoteip.conf /etc/apache2/conf.d +COPY service/ /etc/service/ +COPY glpi.cron /var/spool/cron/crontabs/apache +ADD https://github.com/glpi-project/glpi/releases/download/${GLPI_VERSION}/glpi-${GLPI_VERSION}.tgz /root/glpi-${GLPI_VERSION}.tgz +ADD https://github.com/pluginsGLPI/fields/releases/download/${FIELDS_VERSION}/glpi-fields-${FIELDS_VERSION}.tar.bz2 /root/glpi-fields-${FIELDS_VERSION}.tar.bz2 +ADD https://github.com/pluginsGLPI/datainjection/releases/download/${DATAINJECTION_VERSION}/glpi-datainjection-${DATAINJECTION_VERSION}.tar.bz2 /root/glpi-datainjection-${DATAINJECTION_VERSION}.tar.bz2 +ADD https://github.com/glpi-project/glpi-inventory-plugin/releases/download/${GLPIINVENTORY_VERSION}/glpi-glpiinventory-${GLPIINVENTORY_VERSION}.tar.bz2 /root/glpi-glpiinventory-${GLPIINVENTORY_VERSION}.tar.bz2 + +RUN \ +mkdir -p /root/glpi_template/etc /root/glpi_template/files && \ +tar -x -f /root/glpi-${GLPI_VERSION}.tgz && \ +cp -r /root/glpi/config/. /root/glpi_template/etc/. && \ +cp -r /root/glpi/files/. /root/glpi_template/files/. && \ +rm -r /root/glpi/config /root/glpi/files && \ +mv /root/glpi /var/www/glpi && \ +cd /var/www/glpi/marketplace && \ +tar x -f /root/glpi-fields-${FIELDS_VERSION}.tar.bz2 && \ +tar x -f /root/glpi-datainjection-${DATAINJECTION_VERSION}.tar.bz2 && \ +tar x -f /root/glpi-glpiinventory-${GLPIINVENTORY_VERSION}.tar.bz2 && \ +chmod 600 /etc/crontabs/apache && \ +rm -f /var/www/html/* /root/CAS-1.3.8.tgz /root/glpi-${GLPI_VERSION}.tgz /root/glpi-fields-${FIELDS_VERSION}.tar.bz2 /root/glpi-datainjection-${DATAINJECTION_VERSION}.tar.bz2 /root/glpi-glpiinventory-${GLPIINVENTORY_VERSION}.tar.bz2 && \ +rm -rf /tmp/* /var/tmp/* + +COPY logo.png /var/www/glpi/pics/logo.png + +WORKDIR /var/www/glpi +ENTRYPOINT ["/etc/service/glpi"] diff --git a/web-builder/glpi.cron b/web-builder/glpi.cron new file mode 100644 index 0000000..2bf32a4 --- /dev/null +++ b/web-builder/glpi.cron @@ -0,0 +1,6 @@ +GLPI_CONFIG_DIR=/etc/glpi +GLPI_VAR_DIR=/var/lib/glpi +GLPI_LOG_DIR=/var/log/glpi + +*/1 * * * * /usr/bin/php82 /var/www/glpi/front/cron.php +0 * * * * cd /var/www/glpi && /usr/bin/php82 bin/console glpi:ldap:synchronize_users -n diff --git a/web-builder/glpi_ticket.class.php.patch b/web-builder/glpi_ticket.class.php.patch new file mode 100644 index 0000000..49298db --- /dev/null +++ b/web-builder/glpi_ticket.class.php.patch @@ -0,0 +1,27 @@ +--- ticket.class.php.orig 2022-04-12 12:24:25.634142162 +0200 ++++ ticket.class.php 2022-04-12 12:21:31.000000000 +0200 +@@ -3740,6 +3740,7 @@ + + Plugin::doHook("pre_item_form", ['item' => $this, 'options' => &$options]); + ++ echo "
"; + echo ""; + echo ""; +@@ -3804,6 +3805,7 @@ + + echo ""; + } ++*/ + if (($_SESSION["glpiactiveprofile"]["helpdesk_hardware"] != 0) + && (count($_SESSION["glpiactiveprofile"]["helpdesk_item_type"]))) { + if (!$tt->isHiddenField('items_id')) { diff --git a/alpine/web-builder/httpd.conf b/web-builder/httpd.conf similarity index 98% rename from alpine/web-builder/httpd.conf rename to web-builder/httpd.conf index eb9d6df..06886a5 100644 --- a/alpine/web-builder/httpd.conf +++ b/web-builder/httpd.conf @@ -26,7 +26,7 @@ # Set to one of: Full | OS | Minor | Minimal | Major | Prod # where Full conveys the most information, and Prod the least. # -ServerTokens OS +ServerTokens Prod # # ServerRoot: The top of the directory tree under which the server's @@ -133,7 +133,7 @@ LoadModule headers_module modules/mod_headers.so #LoadModule unique_id_module modules/mod_unique_id.so LoadModule setenvif_module modules/mod_setenvif.so LoadModule version_module modules/mod_version.so -#LoadModule remoteip_module modules/mod_remoteip.so +LoadModule remoteip_module modules/mod_remoteip.so #LoadModule session_module modules/mod_session.so #LoadModule session_cookie_module modules/mod_session_cookie.so #LoadModule session_crypto_module modules/mod_session_crypto.so @@ -163,7 +163,7 @@ LoadModule dir_module modules/mod_dir.so #LoadModule speling_module modules/mod_speling.so #LoadModule userdir_module modules/mod_userdir.so LoadModule alias_module modules/mod_alias.so -#LoadModule rewrite_module modules/mod_rewrite.so +LoadModule rewrite_module modules/mod_rewrite.so LoadModule negotiation_module modules/mod_negotiation.so @@ -241,8 +241,8 @@ ServerSignature On # documents. By default, all requests are taken from this directory, but # symbolic links and aliases may be used to point to other locations. # -DocumentRoot "/var/www/glpi" - +DocumentRoot "/var/www/glpi/public" + # # Possible values for the Options directive are "None", "All", # or any combination of: @@ -268,6 +268,11 @@ DocumentRoot "/var/www/glpi" # Controls who can get stuff from this server. # Require all granted + RewriteEngine On + + # Redirect all requests to GLPI router, unless file exists. + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^(.*)$ index.php [QSA,L] # diff --git a/web-builder/remoteip.conf b/web-builder/remoteip.conf new file mode 100644 index 0000000..c38373e --- /dev/null +++ b/web-builder/remoteip.conf @@ -0,0 +1,10 @@ + + RemoteIPHeader X-Forwarded-For + RemoteIPProxiesHeader X-Forwarded-By + RemoteIPInternalProxy 172.23.0.0/24 + + + + LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"X-Forwarded-For: %{X-Forwarded-For}i\" \"X-Forwarded-By: %{X-Forwarded-By}i\"" combined_fwd + CustomLog /proc/self/fd/1 combined_fwd + diff --git a/alpine/web-builder/service/20-cron/run b/web-builder/service/cron similarity index 75% rename from alpine/web-builder/service/20-cron/run rename to web-builder/service/cron index 2fa1207..069b36e 100644 --- a/alpine/web-builder/service/20-cron/run +++ b/web-builder/service/cron @@ -2,6 +2,9 @@ . /etc/service/template msglog green "Starting Cron..." +/etc/service/php + # Touch cron files to fix 'NUMBER OF HARD LINKS > 1' issue. See https://github.com/phusion/baseimage-docker/issues/198 +chown -R apache:apache /var/www/glpi /etc/glpi /var/lib/glpi /var/log/glpi touch -c /etc/crontab /etc/cron.*/* /var/spool/cron/crontabs/* exec /usr/sbin/crond -f -L /dev/stdout diff --git a/alpine/web-builder/glpi_init.sh b/web-builder/service/glpi similarity index 50% rename from alpine/web-builder/glpi_init.sh rename to web-builder/service/glpi index 1a7fe5c..310d8bb 100644 --- a/alpine/web-builder/glpi_init.sh +++ b/web-builder/service/glpi @@ -26,25 +26,15 @@ while ! mysqlshow -h db -uroot -p${MYSQL_ROOT_PASSWORD} 2>&1 | grep "^| ${MYSQL_ done } -updatephpini() { - variable=$1 - value=$2 - file="/etc/php7/php.ini" +start_apache() { + rm -r /run/* + mkdir -p /run/apache2 - if [ ! -z "${value}" ] ; then - msglog green "Updating $variable to $value in $file" - if grep "^${variable}" "${file}" > /dev/null 2<&1 ; then - sed -i "s@^\(${variable}\s*=\).*@\1 ${value}@g" "${file}" - else - echo ${variable} = ${value} >> ${file} - fi - fi + msglog green "Starting Apache..." + exec /usr/sbin/httpd -D FOREGROUND } -updatephpini memory_limit ${PHP_MEMORY_LIMIT} -updatephpini upload_max_filesize ${PHP_UPLOAD_MAX_FILESIZE} -updatephpini post_max_size ${PHP_POST_MAX_SIZE} -updatephpini date.timezone ${PHP_DATE_TIMEZONE} +/etc/service/php mkdir -p /var/www/glpi if [ ! -e "/etc/glpi/config_db.php" ] ; then @@ -58,38 +48,38 @@ use mysql; GRANT SELECT ON time_zone_name TO '${MYSQL_USER}'@'%'; EOF cd /var/www/glpi - php bin/console db:install --config-dir=${GLPI_CONFIG_DIR} -L fr_FR -H db -d ${MYSQL_DATABASE} -u ${MYSQL_USER} -p ${MYSQL_PASSWORD} -n - php bin/console glpi:plugin:install -u glpi fusioninventory -n - php bin/console glpi:plugin:activate fusioninventory -n + php82 bin/console db:install --config-dir=${GLPI_CONFIG_DIR} -L fr_FR -H db -d ${MYSQL_DATABASE} -u ${MYSQL_USER} -p ${MYSQL_PASSWORD} -n rm install/install.php chown -R apache:apache /var/www/glpi /etc/glpi /var/lib/glpi /var/log/glpi - patch -Np0 -i /root/glpi_ticket.class.php.patch echo "${GLPI_VERSION}" > /etc/glpi/glpi_actual_version - echo "${FUSIONINVENTORY_VERSION}" > /etc/glpi/fusioninventory_actual_version echo "${FIELDS_VERSION}" > /etc/glpi/fields_actual_version - echo "${DATAINJECTION_VERSION}" > /etc/glpi/datainjection_version + echo "${DATAINJECTION_VERSION}" > /etc/glpi/datainjection_actual_version + echo "${GLPIINVENTORY_VERSION}" > /etc/glpi/glpiinventory_actual_version msglog green "Initialazing complete..." else msglog green "GLPI is already initialized" - GLPI_ACTUAL_VERSION=$(cat /etc/glpi/glpi_actual_version) - FUSIONINVENTORY_ACTUAL_VERSION=$(cat /etc/glpi/fusioninventory_actual_version) - FIELDS_ACTUAL_VERSION=$(cat /etc/glpi/fields_actual_version) - DATAINJECTION_ACTUAL_VERSION=$(cat /etc/glpi/datainjection_version) - if [ "${GLPI_ACTUAL_VERSION}" = "${GLPI_VERSION}" -a "${FUSIONINVENTORY_ACTUAL_VERSION}" = "${FUSIONINVENTORY_VERSION}" -a "${FIELDS_ACTUAL_VERSION}" = "${FIELDS_VERSION}" -a "${DATAINJECTION_ACTUAL_VERSION}" = "${DATAINJECTION_VERSION}" ] ; then + GLPI_ACTUAL_VERSION=$(test -e /etc/glpi/glpi_actual_version && cat /etc/glpi/glpi_actual_version) + FIELDS_ACTUAL_VERSION=$(test -e /etc/glpi/fields_actual_version && cat /etc/glpi/fields_actual_version) + DATAINJECTION_ACTUAL_VERSION=$(test -e /etc/glpi/datainjection_actual_version && cat /etc/glpi/datainjection_actual_version) + GLPIINVENTORY_ACTUAL_VERSION=$(test -e /etc/glpi/glpiinventory_actual_version && cat /etc/glpi/glpiinventory_actual_version) + if [ "${GLPI_ACTUAL_VERSION}" = "${GLPI_VERSION}" -a "${FIELDS_ACTUAL_VERSION}" = "${FIELDS_VERSION}" -a "${DATAINJECTION_ACTUAL_VERSION}" = "${DATAINJECTION_VERSION}" -a "${GLPIINVENTORY_ACTUAL_VERSION}" = "${GLPIINVENTORY_VERSION}" ] ; then + chown -R apache:apache /var/www/glpi /etc/glpi /var/lib/glpi /var/log/glpi + [ -e "/var/www/glpi/install/install.php" ] && rm /var/www/glpi/install/install.php msglog green "GLPI already up2date" - exit + start_apache fi msglog red "Updating GLPI from ${GLPI_ACTUAL_VERSION} to ${GLPI_VERSION}" waiting_for_db cd /var/www/glpi - php bin/console glpi:maintenance:enable -n - php bin/console glpi:plugin:deactivate --all -n + php82 bin/console glpi:maintenance:enable -n + php82 bin/console glpi:plugin:deactivate --all # -n rm /var/www/glpi/install/install.php - php bin/console db:update --config-dir=${GLPI_CONFIG_DIR} -n && \ + php82 bin/console db:update --config-dir=${GLPI_CONFIG_DIR} -n && \ ( echo "${GLPI_VERSION}" > /etc/glpi/glpi_actual_version ; \ - echo "${FUSIONINVENTORY_VERSION}" > /etc/glpi/fusioninventory_actual_version ; \ echo "${FIELDS_VERSION}" > /etc/glpi/fields_actual_version ; \ - echo "${DATAINJECTION_VERSION}" > /etc/glpi/datainjection_actual_version ) - php bin/console glpi:maintenance:disable -n + echo "${DATAINJECTION_VERSION}" > /etc/glpi/datainjection_actual_version ; \ + echo "${GLPIINVENTORY_VERSION}" > /etc/glpi/glpiinventory_actual_version ) + php82 bin/console glpi:maintenance:disable -n chown -R apache:apache /var/www/glpi /etc/glpi /var/lib/glpi /var/log/glpi fi +start_apache diff --git a/web-builder/service/php b/web-builder/service/php new file mode 100644 index 0000000..1e069e0 --- /dev/null +++ b/web-builder/service/php @@ -0,0 +1,43 @@ +#!/bin/sh +NORMAL='' +RED='' +GREEN='' + +msglog() { + case "${1}" in + green) + TEXT_COLOR="${GREEN}" + ;; + red) + TEXT_COLOR="${RED}" + ;; + normal) + TEXT_COLOR="${NORMAL}" + ;; + esac + DATE=$(date '+%Y %b %d %H:%M:%S') + echo ${DATE} ${TEXT_COLOR}${2}${NORMAL} +} + +updatephpini() { + variable=$1 + value=$2 + file="/etc/php82/php.ini" + + if [ ! -z "${value}" ] ; then + msglog green "Updating $variable to $value in $file" + if grep "^${variable}" "${file}" > /dev/null 2<&1 ; then + sed -i "s@^\(${variable}\s*=\).*@\1 ${value}@g" "${file}" + else + echo ${variable} = ${value} >> ${file} + fi + fi +} + +updatephpini memory_limit ${PHP_MEMORY_LIMIT} +updatephpini upload_max_filesize ${PHP_UPLOAD_MAX_FILESIZE} +updatephpini post_max_size ${PHP_POST_MAX_SIZE} +updatephpini date.timezone ${PHP_DATE_TIMEZONE} +updatephpini max_input_vars ${PHP_MAX_INPUT_VARS} +updatephpini session.cookie_httponly 1 +updatephpini session.gc_maxlifetime ${PHP_SESSION_GC_MAXLIFETIME} diff --git a/alpine/web-builder/service/template b/web-builder/service/template similarity index 100% rename from alpine/web-builder/service/template rename to web-builder/service/template
-
-  $name -
-
"; - - if (isset($job->users[CommonITILActor::REQUESTER]) - && count($job->users[CommonITILActor::REQUESTER])) { - foreach ($job->users[CommonITILActor::REQUESTER] as $d) { - if ($d["users_id"] > 0) { - $userdata = getUserName($d["users_id"], 2); - $name = "".$userdata['name'].""; - $name = sprintf(__('%1$s %2$s'), $name, - Html::showToolTip($userdata["comment"], - ['link' => $userdata["link"], - 'display' => false])); - echo $name; - } else { - echo $d['alternative_email']." "; - } - echo "
"; - } - } - - if (isset($job->groups[CommonITILActor::REQUESTER]) - && count($job->groups[CommonITILActor::REQUESTER])) { - foreach ($job->groups[CommonITILActor::REQUESTER] as $d) { - echo Dropdown::getDropdownName("glpi_groups", $d["groups_id"]); - echo "
"; - } - } - - echo "
"; - if (!empty($job->hardwaredatas)) { - foreach ($job->hardwaredatas as $hardwaredatas) { - if ($hardwaredatas->canView()) { - echo $hardwaredatas->getTypeName()." - "; - echo "".$hardwaredatas->getLink()."
"; - } else if ($hardwaredatas) { - echo $hardwaredatas->getTypeName()." - "; - echo "".$hardwaredatas->getNameID()."
"; - } - } - } else { - echo __('General'); - } - echo "
"; - - $link = "getNameID().""; - $link = sprintf(__('%1$s (%2$s)'), $link, - sprintf(__('%1$s - %2$s'), $job->numberOfFollowups($showprivate), - $job->numberOfTasks($showprivate))); - $content = Toolbox::unclean_cross_side_scripting_deep(html_entity_decode($job->fields['content'], - ENT_QUOTES, - "UTF-8")); - $link = printf(__('%1$s %2$s'), $link, - Html::showToolTip(nl2br(Html::Clean($content)), - ['applyto' => 'ticket'.$job->fields["id"].$rand, - 'display' => false])); - echo "
".__('No ticket in progress.')."
".__('Assign equipment')."".$item->getLink(['comments' => true])."

".__('Support Informatique')."

".__('Describe the incident or request').""; + if (Session::isMultiEntitiesMode()) { + echo "(".Dropdown::getDropdownName("glpi_entities", $_SESSION["glpiactive_entity"]).")"; +@@ -3789,7 +3790,7 @@ + } + } + +- if (empty($delegating) ++/** if (empty($delegating) + && NotificationTargetTicket::isAuthorMailingActivatedForHelpdesk()) { + echo "
".__('Inform me about the actions taken')."