Initial xentral_oss_20.3.c9ffacf
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ticket;
|
||||
|
||||
use Ticket;
|
||||
use Xentral\Core\DependencyInjection\ContainerInterface;
|
||||
use Xentral\Modules\Api\LegacyBridge\LegacyApplication;
|
||||
use Xentral\Modules\Ticket\Importer\TicketFormatter;
|
||||
use Xentral\Modules\Ticket\Task\TicketImportHelperFactory;
|
||||
|
||||
final class Bootstrap
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function registerServices(): array
|
||||
{
|
||||
return [
|
||||
'TicketFormatter' => 'onInitTicketFormatter',
|
||||
'TicketImportHelperFactory' => 'onInitTicketImportHelperFactory',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return TicketFormatter
|
||||
*/
|
||||
public static function onInitTicketFormatter(ContainerInterface $container): TicketFormatter
|
||||
{
|
||||
return new TicketFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return TicketImportHelperFactory
|
||||
*/
|
||||
public static function onInitTicketImportHelperFactory(ContainerInterface $container): TicketImportHelperFactory
|
||||
{
|
||||
/** @var LegacyApplication $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
/** @var Ticket $ticketModule */
|
||||
$ticketModule = $ticketModule = $app->erp->LoadModul('ticket');
|
||||
|
||||
return new TicketImportHelperFactory(
|
||||
$app->DB,
|
||||
$app->erp,
|
||||
$app->Conf,
|
||||
$ticketModule,
|
||||
$container->get('TicketFormatter'),
|
||||
$container->get('Logger')
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ticket\Exception;
|
||||
|
||||
use \InvalidArgumentException as SplInvalidArgumentException;
|
||||
|
||||
class InvalidArgumentException extends SplInvalidArgumentException implements TicketExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ticket\Exception;
|
||||
|
||||
use \RuntimeException as SplRuntimeException;
|
||||
|
||||
class NumberGeneratorException extends SplRuntimeException implements TicketExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ticket\Exception;
|
||||
|
||||
use Xentral\Core\Exception\ModuleExceptionInterface;
|
||||
|
||||
interface TicketExceptionInterface extends ModuleExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ticket\Importer;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Xentral\Components\MailClient\Client\MailClientInterface;
|
||||
use Xentral\Modules\SystemMailer\Data\EmailBackupAccount;
|
||||
use Xentral\Modules\Ticket\Service\TicketGateway;
|
||||
use Xentral\Modules\Ticket\Service\TicketService;
|
||||
use Xentral\Modules\Ticket\Wrapper\EmailBackupWrapper;
|
||||
|
||||
class InboxTicketImporter
|
||||
{
|
||||
/** @var TicketGateway $gateway */
|
||||
private $gateway;
|
||||
|
||||
/** @var TicketService $service */
|
||||
private $service;
|
||||
|
||||
/** @var TicketFormatter $formatter */
|
||||
private $formatter;
|
||||
|
||||
/** @var EmailBackupWrapper $emailBackupService */
|
||||
private $emailBackupService;
|
||||
|
||||
/**
|
||||
* @param TicketGateway $gateway
|
||||
* @param TicketService $service
|
||||
* @param TicketFormatter $formatter
|
||||
* @param EmailBackupWrapper $emailBackupService
|
||||
*/
|
||||
public function __construct(
|
||||
TicketGateway $gateway,
|
||||
TicketService $service,
|
||||
TicketFormatter $formatter,
|
||||
EmailBackupWrapper $emailBackupService
|
||||
) {
|
||||
$this->gateway = $gateway;
|
||||
$this->service = $service;
|
||||
$this->formatter = $formatter;
|
||||
$this->emailBackupService = $emailBackupService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MailClientInterface $client
|
||||
* @param DateTimeInterface|null $fromDate
|
||||
*
|
||||
* @return string[]|array
|
||||
*/
|
||||
public function searchImportableEmails(MailClientInterface $client, DateTimeInterface $fromDate = null): array
|
||||
{
|
||||
if ($fromDate !== null) {
|
||||
$criteria = sprintf('UNSEEN SINCE %s', $fromDate->format('d-M-Y'));
|
||||
} else {
|
||||
$criteria = 'UNSEEN';
|
||||
}
|
||||
|
||||
return $client->searchMessages($criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EmailBackupAccount $mailAccount
|
||||
* @param MailClientInterface $client
|
||||
* @param int $messageId
|
||||
* @param int $userId
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function importTicket(
|
||||
EmailBackupAccount $mailAccount,
|
||||
MailClientInterface $client,
|
||||
int $messageId,
|
||||
int $userId
|
||||
): void {
|
||||
//fetch message
|
||||
$message = $client->fetchMessage($messageId);
|
||||
|
||||
//format several values
|
||||
$sender = $message->getSender()->getEmail();
|
||||
$subject = $message->getSubject();
|
||||
$timestamp = $message->getDate()->getTimestamp();
|
||||
$attachments = $message->getAttachments();
|
||||
$plainText = $message->getPlainTextBody();
|
||||
if ($plainText === null) {
|
||||
$plainText = '';
|
||||
}
|
||||
$htmlText = $message->getHtmlBody();
|
||||
if (empty($htmlText)) {
|
||||
$htmlText = nl2br($plainText);
|
||||
}
|
||||
|
||||
if (
|
||||
$this->emailBackupService->existsEmailBackup(
|
||||
$mailAccount->getId(),
|
||||
$sender,
|
||||
$subject,
|
||||
$timestamp
|
||||
)
|
||||
) {
|
||||
$emailBackupId = $this->emailBackupService->createEmailBackup(
|
||||
$mailAccount->getId(),
|
||||
$subject,
|
||||
$sender,
|
||||
$plainText,
|
||||
$htmlText,
|
||||
$timestamp,
|
||||
count($attachments) > 0
|
||||
);
|
||||
//TODO: store attachment files (filesystem)
|
||||
}
|
||||
|
||||
//extract ticket number from email subject
|
||||
$ticketNumber = $this->tryGetTicketNumberFromSubject($subject);
|
||||
|
||||
if ($ticketNumber !== null && !$this->gateway->existsTicketNumber($ticketNumber)) {
|
||||
$projectId = $mailAccount->getProjectId() !== 0
|
||||
? $mailAccount->getProjectId()
|
||||
: 1;
|
||||
$ticketId = $this->service->createTicket();
|
||||
}
|
||||
if ($ticketNumber !== null) {
|
||||
$this->service->addTicketMessage(
|
||||
$ticketNumber,
|
||||
$timestamp,
|
||||
$htmlText,
|
||||
$subject,
|
||||
$message->getSender()->getName(),
|
||||
$message->getSender()->getEmail(),
|
||||
TicketGateway::STATUS_NEW,
|
||||
$message->getSender()->getName(),
|
||||
$message->getReplyToAddress()
|
||||
);
|
||||
}
|
||||
|
||||
//if the email was a ticket related mark the emailbackup as ticket related
|
||||
if ($ticketNumber !== null) {
|
||||
//mark emailbackup as ticketmessage
|
||||
//save ticket headers
|
||||
}
|
||||
|
||||
if (/* autoresponder is active */true) {
|
||||
//send autoresponse
|
||||
}
|
||||
|
||||
if (/* email delete is active */true) {
|
||||
//delete email
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $subject
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private function tryGetTicketNumberFromSubject(string $subject): ?string
|
||||
{
|
||||
if (!preg_match("/Ticket #(\d{12})/i", $subject, $matches)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $matches[1];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ticket\Importer;
|
||||
|
||||
class TicketFormatter
|
||||
{
|
||||
/**
|
||||
* @param string $rawEmail
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function formatEmail(string $rawEmail): string
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encodeToUtf8(string $string): string
|
||||
{
|
||||
$encoding = mb_detect_encoding($string, 'UTF-8, ISO-8859-1, ISO-8859-15', true);
|
||||
|
||||
return mb_convert_encoding(
|
||||
$string,
|
||||
'UTF-8',
|
||||
$encoding
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ticket\Service;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Components\Database\SqlQuery\SelectQuery;
|
||||
|
||||
class TicketGateway
|
||||
{
|
||||
/** @var string STATUS_NEW */
|
||||
public const STATUS_NEW = 'neu';
|
||||
|
||||
/** @var string STATUS_COMPLETED */
|
||||
public const STATUS_COMPLETED = 'abgeschlossen';
|
||||
|
||||
/** @var string STATUS_SPAM */
|
||||
public const STATUS_SPAM = 'spam';
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* TicketGateway constructor.
|
||||
*
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ticketNumber
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function existsTicketNumber(string $ticketNumber): bool
|
||||
{
|
||||
return $this->tryGetTicketDataByTicketNumber($ticketNumber) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return ?array
|
||||
*/
|
||||
public function tryGetTicketDataByTicketNumber(string $key): ?array
|
||||
{
|
||||
$sql = $this->createTicketQuery()
|
||||
->where('t.schluessel like :ticket_number')
|
||||
->where("t.schluessel <> ''")
|
||||
->getStatement();
|
||||
$row = $this->db->fetchRow($sql, ['ticket_number' => $key]);
|
||||
if (empty($row)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SelectQuery
|
||||
*/
|
||||
private function createTicketQuery(): SelectQuery
|
||||
{
|
||||
return $this->db->select()
|
||||
->cols(
|
||||
[
|
||||
't.id',
|
||||
't.schluessel as ticket_number',
|
||||
't.zeit as timestamp',
|
||||
't.projekt as project',
|
||||
't.bearbeiter as editor',
|
||||
't.quelle as source_email',
|
||||
't.status',
|
||||
't.adresse as address_id',
|
||||
't.kunde as customer',
|
||||
't.warteschlange as queue_name',
|
||||
't.mailadresse as sender_email',
|
||||
't.prio as priority',
|
||||
't.betreff as subject',
|
||||
't.zugewiesen as is_assigned',
|
||||
't.inbearbeitung as is_editor_locked',
|
||||
't.inbearbeitung_user as editor_user',
|
||||
't.firma as company_id',
|
||||
't.notiz as note',
|
||||
't.bitteantworten as is_response_required',
|
||||
't.service',
|
||||
't.kommentar as comment',
|
||||
't.privat as is_private',
|
||||
't.dsgvo as is_gdpr_relevant',
|
||||
't.tags',
|
||||
't.nachrichten_anz as count_messages',
|
||||
]
|
||||
)
|
||||
->from('ticket as t');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $recipientMail
|
||||
* @param string $senderMail
|
||||
* @param string $senderName
|
||||
* @param string $subject
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTicketRules(
|
||||
string $recipientMail,
|
||||
string $senderMail,
|
||||
string $senderName,
|
||||
string $subject
|
||||
): array {
|
||||
$sql = "SELECT
|
||||
tr.spam AS `is_spam`,
|
||||
tr.dsgvo AS `is_gdpr_relevant`,
|
||||
tr.prio AS `priority`,
|
||||
tr.persoenlich AS `is_private`,
|
||||
tr.warteschlange AS `queue_id`
|
||||
FROM `ticket_regeln` AS `tr`
|
||||
WHERE
|
||||
tr.aktiv = 1
|
||||
AND (tr.empfaenger_email LIKE :source_email OR empfaenger_email = '')
|
||||
AND (
|
||||
tr.sender_email LIKE :sender_email
|
||||
OR (tr.sender_email LIKE '@%' AND :sender_email LIKE CONCAT('%', tr.sender_email))
|
||||
OR tr.sender_email = ''
|
||||
)
|
||||
AND (tr.name LIKE :sender_name OR tr.name = '')
|
||||
AND (tr.betreff LIKE :subject OR tr.betreff = '')";
|
||||
$values = [
|
||||
'source_email' => $recipientMail,
|
||||
'sender_email' => $senderMail,
|
||||
'sender_name' => $senderName,
|
||||
'subject' => $subject,
|
||||
];
|
||||
|
||||
return $this->db->fetchAll($sql, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function existsTicketId(int $id): bool
|
||||
{
|
||||
return $this->tryGetTicketById($id) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function tryGetTicketById(int $id): ?array
|
||||
{
|
||||
if ($id < 1) {
|
||||
return null;
|
||||
}
|
||||
$sql = $this->createTicketQuery()
|
||||
->where('t.id like :id')
|
||||
->getStatement();
|
||||
$row = $this->db->fetchRow($sql, ['id' => $id]);
|
||||
if (empty($row)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $messageId
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function tryGetTicketDataByByMessage(int $messageId): ?array
|
||||
{
|
||||
if ($messageId < 1) {
|
||||
return null;
|
||||
}
|
||||
$sql = $this->createTicketQuery()
|
||||
->join('', 'ticket_nachricht AS tm', 'tm.ticket = t.id')
|
||||
->where('tm.id = :id')
|
||||
->getStatement();
|
||||
$row = $this->db->fetchRow($sql, ['id' => $messageId]);
|
||||
if (empty($row)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ticketNumber
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getMessageCountByTicketNumber(string $ticketNumber): int
|
||||
{
|
||||
$sql = 'SELECT COUNT(tm.id) FROM `ticket_nachricht` AS `tm` WHERE tm.ticket = :ticket_number';
|
||||
$count = $this->db->fetchValue($sql, ['ticket_number' => $ticketNumber]);
|
||||
if ($count === null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ticket\Service;
|
||||
|
||||
use Throwable;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\SystemMailer\Data\EmailBackupAccount;
|
||||
use Xentral\Modules\Ticket\Exception\InvalidArgumentException;
|
||||
use Xentral\Modules\Ticket\Exception\NumberGeneratorException;
|
||||
use Xentral\Modules\Ticket\Wrapper\AddressWrapper;
|
||||
|
||||
class TicketService
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/** @var TicketGateway $gateway */
|
||||
private $gateway;
|
||||
|
||||
/** @var AddressWrapper $addressService */
|
||||
private $addressService;
|
||||
|
||||
/**
|
||||
* TicketService constructor.
|
||||
*
|
||||
* @param Database $db
|
||||
* @param TicketGateway $gateway
|
||||
* @param AddressWrapper $addressService
|
||||
*/
|
||||
public function __construct(Database $db, TicketGateway $gateway, AddressWrapper $addressService)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->gateway = $gateway;
|
||||
$this->addressService = $addressService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $projectId
|
||||
* @param EmailBackupAccount $mailAccount
|
||||
* @param string $senderName
|
||||
* @param string $senderAddress
|
||||
* @param string $subject
|
||||
* @param int $timestamp
|
||||
* @param string $replyToName
|
||||
* @param string $replyToAddress
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function createTicket(
|
||||
int $projectId,
|
||||
EmailBackupAccount $mailAccount,
|
||||
string $senderName,
|
||||
string $senderAddress,
|
||||
string $subject,
|
||||
int $timestamp,
|
||||
string $replyToName,
|
||||
string $replyToAddress
|
||||
): int
|
||||
{
|
||||
$assigneeAddressId = $mailAccount->getAddressId();
|
||||
if ($assigneeAddressId < 1) {
|
||||
$assigneeAddressId = $this->addressService->tryGetAddressIdByEmailAddress(
|
||||
$mailAccount->getEmailAddress()
|
||||
);
|
||||
}
|
||||
$ticketNumber = $this->generateRandomTicketNumber();
|
||||
if($projectId < 1) {
|
||||
$projectId = $mailAccount->getProjectId();
|
||||
}
|
||||
if ($mailAccount->isTicketMarkAsFinishedEnabled()) {
|
||||
$status = TicketGateway::STATUS_COMPLETED;
|
||||
} else {
|
||||
$status = TicketGateway::STATUS_NEW;
|
||||
}
|
||||
|
||||
$insertTicket = "INSERT INTO `ticket` (
|
||||
`schluessel`, `zeit`, `projekt`, `quelle`, `status`, `kunde`,
|
||||
`mailadresse`, `prio`, `betreff`,`warteschlange`,`adresse`
|
||||
) VALUES (
|
||||
:ticket_number, :date_received, :project_id, :source, :status, :sender_name,
|
||||
:sender_email, :priority, :subject, :queue_id, :address_id);";
|
||||
$values = [
|
||||
'ticket_number' => $ticketNumber,
|
||||
'date_received' => date('Y-m-d H:i:s', $timestamp),
|
||||
'project_id' => $projectId,
|
||||
'source' => $mailAccount->getEmailAddress(),
|
||||
'status' => $status,
|
||||
'sender_name' => $senderName,
|
||||
'sender_email' => $senderAddress,
|
||||
'priority' => 3,
|
||||
'subject' => $subject,
|
||||
'queue_id' => $mailAccount->getTicketQueueId(),
|
||||
'address_id' => $assigneeAddressId,
|
||||
];
|
||||
$this->db->perform($insertTicket, $values);
|
||||
$ticketId = $this->db->lastInsertId();
|
||||
|
||||
/* todo This should not be included at this point
|
||||
|
||||
$sql = "INSERT INTO `ticket_nachricht` (`id`, `ticket`, `zeit`,`text`,`betreff`,`medium`,`verfasser`, `mail`,`status`,`verfasser_replyto`, `mail_replyto`)
|
||||
VALUES (NULL, '$testschluessel', FROM_UNIXTIME($timestamp), '$text','$betreff','$medium','$kunde', '$mailadresse','neu','".$this->app->DB->real_escape_string($verfasser_replyto)."', '".$this->app->DB->real_escape_string($mail_replyto)."');";
|
||||
|
||||
$this->app->DB->InsertWithoutLog($sql);
|
||||
$ticket_nachricht_id = $this->app->DB->GetInsertID();
|
||||
|
||||
$this->app->DB->Update("UPDATE ticket AS t
|
||||
INNER JOIN (
|
||||
SELECT count(id) as co, ticket
|
||||
FROM ticket_nachricht
|
||||
GROUP BY ticket
|
||||
) AS tn ON t.schluessel = tn.ticket
|
||||
SET t.nachrichten_anz = tn.co
|
||||
WHERE t.schluessel = '$testschluessel'");
|
||||
*/
|
||||
|
||||
// todo als rueckgabe ticketnachricht
|
||||
return $ticket_nachricht_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $ticketMessageId
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function applyTicketRules(int $ticketMessageId): void
|
||||
{
|
||||
$ticketData = $this->gateway->tryGetTicketDataByByMessage($ticketMessageId);
|
||||
if ($ticketData === null) {
|
||||
throw new InvalidArgumentException('cannot find ticket by message id');
|
||||
}
|
||||
$ticketId = $ticketData['id'];
|
||||
$senderMail = $ticketData['sender_email'];
|
||||
$senderName = $ticketData['sender_name'];
|
||||
$subject = $ticketData['subject'];
|
||||
$source = $ticketData['source_email'];
|
||||
|
||||
//TODO: richtig loggen: $this->app->erp->LogFile("Empfaengermail: $quelle Sendermail: $mailadresse Kunde: $kunde Betreff: $betreff");
|
||||
$ruleArray = $this->gateway->getTicketRules($source, $senderMail, $senderName, $subject);
|
||||
if (empty($ruleArray)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($ruleArray as $rule) {
|
||||
$update = $this->db->update();
|
||||
$update->table('ticket');
|
||||
if ($rule['is_spam'] === 1) {
|
||||
$update->set('inbearbeitung', 0);
|
||||
$update->set('zugewiesen', 1);
|
||||
$this->db->perform(
|
||||
'UPDATE `ticket_nachricht` SET `status` = :status WHERE `ticket` = :ticket_id',
|
||||
['status' => TicketGateway::STATUS_SPAM, 'ticket_id' => $ticketId]
|
||||
);
|
||||
}
|
||||
$update->set('dsgvo', $rule['is_gdpr_relevant']);
|
||||
$update->set('privat', $rule['is_private'] );
|
||||
$update->set('prio', $rule['priority'] );
|
||||
$update->where('id = :ticket_id');
|
||||
$sql = $update->getStatement();
|
||||
$this->db->perform($sql, ['ticket_id' => $ticketId]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ticketNumber
|
||||
* @param int $timestamp
|
||||
* @param string $message
|
||||
* @param string $subject
|
||||
* @param string $senderName
|
||||
* @param string $senderAddress
|
||||
* @param string $status
|
||||
* @param string $replyToName
|
||||
* @param string $replyToAddress
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function addTicketMessage(
|
||||
string $ticketNumber,
|
||||
int $timestamp,
|
||||
string $message,
|
||||
string $subject,
|
||||
string $senderName,
|
||||
string $senderAddress,
|
||||
string $status,
|
||||
string $replyToName,
|
||||
string $replyToAddress
|
||||
): int
|
||||
{
|
||||
$this->db->beginTransaction();
|
||||
try {
|
||||
$this->markTicketMessagesCompleted($ticketNumber);
|
||||
$sql = 'INSERT INTO `ticket_nachricht` (
|
||||
`ticket`, `zeit`, `text`, `betreff`, `medium`,
|
||||
`verfasser`, `mail`,`status`, `verfasser_replyto`, `mail_replyto`
|
||||
) VALUES (
|
||||
:ticket_number, :date_received, :message, :subject, :medium,
|
||||
:sender_name, :sender_address, :status, :replyto_name, :replyto_address
|
||||
)';
|
||||
$dateString = date('Y-m-d H:i:s', $timestamp);
|
||||
$values = [
|
||||
'ticket_number' => $ticketNumber,
|
||||
'date_received' => $dateString,
|
||||
'message' => $message,
|
||||
'subject' => $subject,
|
||||
'medium' => 'email',
|
||||
'sender_name' => $senderName,
|
||||
'sender_address' => $senderAddress,
|
||||
'status' => $status,
|
||||
'replyto_name' => $replyToName,
|
||||
'replyto_address' => $replyToAddress,
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
$messageId = $this->db->lastInsertId();
|
||||
$this->updateTicketMessagesCount($ticketNumber);
|
||||
$this->resetTicketStatus($ticketNumber);
|
||||
$this->db->commit();
|
||||
|
||||
return $messageId;
|
||||
} catch (Throwable $e) {
|
||||
$this->db->rollBack();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ticketNumber
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function markTicketMessagesCompleted(string $ticketNumber): void
|
||||
{
|
||||
$this->setTicketMessagesStatus($ticketNumber, TicketGateway::STATUS_COMPLETED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ticketNumber
|
||||
* @param string $status
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function setTicketMessagesStatus(string $ticketNumber, string $status): void
|
||||
{
|
||||
$sql = 'UPDATE `ticket_nachricht` SET `status` = :status WHERE `ticket` = :ticket_number';
|
||||
$this->db->perform($sql, ['ticket_number' => $ticketNumber, 'status' => $status]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ticketNumber
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function resetTicketStatus(string $ticketNumber): void
|
||||
{
|
||||
$this->ensureTicketNumberExists($ticketNumber);
|
||||
$sql = 'UPDATE `ticket` SET
|
||||
`status` = :status,
|
||||
`zugewiesen` = :is_assigned,
|
||||
`inbearbeitung` = :is_editor_locked
|
||||
WHERE `schluessel` = :ticket_number';
|
||||
$values = [
|
||||
'status' => TicketGateway::STATUS_NEW,
|
||||
'is_assigned' => 0,
|
||||
'is_editor_locked' => 0
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ticketNumber
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateTicketMessagesCount(string $ticketNumber): void
|
||||
{
|
||||
$this->ensureTicketNumberExists($ticketNumber);
|
||||
$count = $this->gateway->getMessageCountByTicketNumber($ticketNumber);
|
||||
$count++;
|
||||
$sql = 'UPDATE `ticket` SET `nachrichten_anz` = :message_amount WHERE schluessel = :ticket_number';
|
||||
$this->db->perform($sql, ['message_amount' => $count, 'ticket_number' => $ticketNumber]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ticketNumber
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function ensureTicketNumberExists(string $ticketNumber): void
|
||||
{
|
||||
if (!$this->gateway->existsTicketNumber($ticketNumber)) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf('ticket number "%s" does not exist', $ticketNumber)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NumberGeneratorException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function generateRandomTicketNumber(): string
|
||||
{
|
||||
$random = rand(300,700);
|
||||
$loopCounter = 0;
|
||||
while(true) {
|
||||
$candidate = sprintf('%s%04d', date('Ymd'), $random++);
|
||||
if (!$this->gateway->existsTicketNumber($candidate)) {
|
||||
return $candidate;
|
||||
}
|
||||
if ($loopCounter > 99) {
|
||||
throw new NumberGeneratorException('ticket number generation failed');
|
||||
}
|
||||
$loopCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ticket\Task;
|
||||
|
||||
use Config as LegacyConfig;
|
||||
use DB as LegacyDataBase;
|
||||
use erpAPI;
|
||||
use Throwable;
|
||||
use Ticket as TicketModule;
|
||||
use Xentral\Components\Logger\LoggerAwareTrait;
|
||||
use Xentral\Components\MailClient\Client\MailClientInterface;
|
||||
use Xentral\Components\MailClient\Data\MailMessageInterface;
|
||||
use Xentral\Modules\SystemMailer\Data\EmailBackupAccount;
|
||||
use Xentral\Modules\Ticket\Importer\TicketFormatter;
|
||||
|
||||
/**
|
||||
* Utility functions for tickets_google cronjob for improved testability
|
||||
*/
|
||||
class TicketImportHelper
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
|
||||
/** @var LegacyDataBase $db */
|
||||
private $db;
|
||||
|
||||
/** @var erpAPI $erpApi */
|
||||
private $erpApi;
|
||||
|
||||
/** @var LegacyConfig $config */
|
||||
private $config;
|
||||
|
||||
/** @var TicketModule $ticketModule */
|
||||
private $ticketModule;
|
||||
|
||||
/** @var TicketFormatter $formatter */
|
||||
private $formatter;
|
||||
|
||||
/** @var MailClientInterface $mailClient */
|
||||
private $mailClient;
|
||||
|
||||
/** @var EmailBackupAccount $mailAccount */
|
||||
private $mailAccount;
|
||||
|
||||
/** @var int $projectId */
|
||||
private $projectId;
|
||||
|
||||
/**
|
||||
* @param LegacyDataBase $db
|
||||
* @param erpAPI $erpApi
|
||||
* @param TicketModule $ticketModule
|
||||
* @param LegacyConfig $config
|
||||
* @param TicketFormatter $formatter
|
||||
* @param MailClientInterface $mailClient
|
||||
* @param EmailBackupAccount $mailAccount
|
||||
* @param int $projectId
|
||||
*/
|
||||
public function __construct(
|
||||
LegacyDataBase $db,
|
||||
erpAPI $erpApi,
|
||||
TicketModule $ticketModule,
|
||||
LegacyConfig $config,
|
||||
TicketFormatter $formatter,
|
||||
MailClientInterface $mailClient,
|
||||
EmailBackupAccount $mailAccount,
|
||||
int $projectId
|
||||
) {
|
||||
$this->db = $db;
|
||||
$this->erpApi = $erpApi;
|
||||
$this->ticketModule = $ticketModule;
|
||||
$this->formatter = $formatter;
|
||||
$this->mailClient = $mailClient;
|
||||
$this->mailAccount = $mailAccount;
|
||||
$this->projectId = $projectId;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $inboxMessageIds
|
||||
*
|
||||
* @return int amount of imported tickets
|
||||
*/
|
||||
public function importMessages(array $inboxMessageIds): int
|
||||
{
|
||||
$insertedMailsCount = 0;
|
||||
foreach ($inboxMessageIds as $messageNumber) {
|
||||
try {
|
||||
$message = $this->mailClient->fetchMessage((int)$messageNumber);
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->error('Failed to fetch email from server', ['exception' => $e]);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$this->importMessage($message);
|
||||
$insertedMailsCount++;
|
||||
if ($this->mailAccount->isDeleteAfterImportEnabled()) {
|
||||
$this->mailClient->deleteMessage((int)$messageNumber);
|
||||
} else {
|
||||
$this->mailClient->setFlags((int)$messageNumber, ['\\Seen']);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$this->logger->error('Error during email import', ['exception' => $e]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$this->logger->debug(
|
||||
'{imported_count} of {total} emails imported successfully',
|
||||
['imported_count' => $insertedMailsCount, 'total' => count($inboxMessageIds)]
|
||||
);
|
||||
|
||||
return $insertedMailsCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MailMessageInterface $message
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function importMessage(MailMessageInterface $message): void
|
||||
{
|
||||
$DEBUG = 0;
|
||||
|
||||
// extract email data
|
||||
$subject = $this->formatter->encodeToUtf8($message->getSubject());
|
||||
$from = $this->formatter->encodeToUtf8($message->getSender()->getEmail());
|
||||
$ccs = $message->getCcRecipients();
|
||||
$cc_recv = [];
|
||||
foreach ($ccs as $cc) {
|
||||
$cc_recv[] = [
|
||||
'email' => $this->formatter->encodeToUtf8($cc->getEmail()),
|
||||
'name' => $this->formatter->encodeToUtf8($cc->getName()),
|
||||
];
|
||||
}
|
||||
$plainTextBody = $message->getPlainTextBody();
|
||||
if ($plainTextBody === null) {
|
||||
$plainTextBody = '';
|
||||
}
|
||||
$htmlBody = $message->getHtmlBody();
|
||||
if ($htmlBody === null) {
|
||||
$htmlBody = '';
|
||||
}
|
||||
$action = $this->formatter->encodeToUtf8($plainTextBody);
|
||||
$action_html = $this->formatter->encodeToUtf8($htmlBody);
|
||||
if (strlen($action_html) < strlen($action)) {
|
||||
$action_html = nl2br($action);
|
||||
}
|
||||
$name_sender = $this->formatter->encodeToUtf8($message->getSender()->getName());
|
||||
$mail_replyto = $this->formatter->encodeToUtf8($message->getReplyToAddress());
|
||||
$verfasser_replyto = $this->formatter->encodeToUtf8($message->getSender()->getName());
|
||||
|
||||
//check if email exists in database
|
||||
$date = $message->getDate();
|
||||
$timestamp = $date->getTimestamp();
|
||||
$frommd5 = md5($from . $subject . $timestamp);
|
||||
$empfang = $date->format('Y-m-d H:i:s');
|
||||
$sql = "SELECT COUNT(id)
|
||||
FROM `emailbackup_mails`
|
||||
WHERE `checksum`='$frommd5'
|
||||
AND `empfang`='$empfang'
|
||||
AND `webmail`='" . $this->mailAccount->getId() . "'";
|
||||
|
||||
if ($this->db->Select($sql) == 0) {
|
||||
$attachments = $message->getAttachments();
|
||||
$anhang = count($attachments) > 0 ? 1 : 0;
|
||||
$mailacc = $this->mailAccount->getEmailAddress();
|
||||
if (empty($mailacc) && count($message->getRecipients()) > 0) {
|
||||
$mailacc = array_values($message->getRecipients())[0]->getEmail();
|
||||
}
|
||||
$mailaccid = $this->mailAccount->getId();
|
||||
|
||||
if (!$this->erpApi->isMailAdr($from)) {
|
||||
$from = $this->erpApi->filterMailAdr($from);
|
||||
}
|
||||
|
||||
//fuege gegenenfalls ein
|
||||
$sql = "INSERT INTO `emailbackup_mails`
|
||||
(
|
||||
`webmail`,
|
||||
`subject`,
|
||||
`sender`,
|
||||
`action`,
|
||||
`action_html`,
|
||||
`empfang`,
|
||||
`anhang`,
|
||||
`checksum`
|
||||
) VALUES (
|
||||
'$mailaccid',
|
||||
'" . $this->db->real_escape_string($subject) . "',
|
||||
'" . $this->db->real_escape_string($from) . "',
|
||||
'" . $this->db->real_escape_string($action) . "',
|
||||
'" . $this->db->real_escape_string($action_html) . "',
|
||||
'$empfang','$anhang','$frommd5'
|
||||
)";
|
||||
|
||||
$id = null;
|
||||
if ($DEBUG) {
|
||||
echo $sql;
|
||||
} else {
|
||||
$this->db->InsertWithoutLog($sql);
|
||||
$id = $this->db->GetInsertID();
|
||||
}
|
||||
|
||||
if ($DEBUG) {
|
||||
echo "ticket suchen oder anlegen\n";
|
||||
}
|
||||
|
||||
$_schluessel = null;
|
||||
$schluessel = null;
|
||||
$ticketexits = null;
|
||||
if (preg_match("/Ticket #[0-9]{12}/i", $subject, $matches)) {
|
||||
$schluessel = str_replace('Ticket #', '', $matches[0]);
|
||||
$ticketexits = $this->db->Select(
|
||||
"SELECT schluessel
|
||||
FROM ticket
|
||||
WHERE schluessel LIKE '" . $schluessel . "'
|
||||
AND schluessel!='' LIMIT 1"
|
||||
);
|
||||
}
|
||||
$ticketnachricht = null;
|
||||
if ($ticketexits) {
|
||||
if ($DEBUG) {
|
||||
echo "ticket nummer in betreff gefunden\n";
|
||||
}
|
||||
|
||||
$schluessel = str_replace('Ticket #', '', $matches[0]);
|
||||
|
||||
if ($action_html != '') {
|
||||
$sql = "INSERT INTO `ticket_nachricht`
|
||||
(
|
||||
`id`,
|
||||
`ticket`,
|
||||
`zeit`,
|
||||
`text`,
|
||||
`betreff`,
|
||||
`medium`,
|
||||
`verfasser`,
|
||||
`mail`,
|
||||
`status`,
|
||||
`verfasser_replyto`,
|
||||
`mail_replyto`
|
||||
) VALUES (
|
||||
NULL,
|
||||
'$schluessel',
|
||||
FROM_UNIXTIME($timestamp),
|
||||
'" . $this->db->real_escape_string($action_html) . "',
|
||||
'" . $this->db->real_escape_string($subject) . "',
|
||||
'email',
|
||||
'" . $this->db->real_escape_string($name_sender) . "',
|
||||
'" . $this->db->real_escape_string($from) . "',
|
||||
'neu',
|
||||
'" . $this->db->real_escape_string($verfasser_replyto) . "',
|
||||
'" . $this->db->real_escape_string($mail_replyto) . "'
|
||||
);";
|
||||
} else {
|
||||
$sql = "INSERT INTO `ticket_nachricht`
|
||||
(
|
||||
`id`,
|
||||
`ticket`,
|
||||
`zeit`,
|
||||
`text`,
|
||||
`betreff`,
|
||||
`medium`,
|
||||
`verfasser`,
|
||||
`mail`,
|
||||
`status`,
|
||||
`verfasser_replyto`,
|
||||
`mail_replyto`
|
||||
) VALUES (
|
||||
NULL,
|
||||
'$schluessel',
|
||||
FROM_UNIXTIME($timestamp),
|
||||
'" . $this->db->real_escape_string($action) . "',
|
||||
'" . $this->db->real_escape_string($subject) . "',
|
||||
'email',
|
||||
'" . $this->db->real_escape_string($name_sender) . "',
|
||||
'" . $this->db->real_escape_string($from) . "',
|
||||
'neu',
|
||||
'" . $this->db->real_escape_string($verfasser_replyto) . "',
|
||||
'" . $this->db->real_escape_string($mail_replyto) . "'
|
||||
);";
|
||||
}
|
||||
|
||||
|
||||
if (!$DEBUG) {
|
||||
$this->db->InsertWithoutLog(
|
||||
"UPDATE ticket_nachricht
|
||||
SET status = 'abgeschlossen'
|
||||
WHERE ticket LIKE '$schluessel'"
|
||||
);
|
||||
$this->db->InsertWithoutLog($sql);
|
||||
$ticketnachricht = $this->db->GetInsertID();
|
||||
$this->db->InsertWithoutLog(
|
||||
"UPDATE ticket
|
||||
SET status='neu', zugewiesen = 0, inbearbeitung=0
|
||||
WHERE schluessel LIKE '$schluessel'"
|
||||
);
|
||||
$this->db->Update(
|
||||
"UPDATE `ticket` AS `t`
|
||||
INNER JOIN (
|
||||
SELECT COUNT(`id`) AS `co`, `ticket`
|
||||
FROM `ticket_nachricht`
|
||||
GROUP BY `ticket`
|
||||
) AS `tn` ON t.schluessel = tn.ticket
|
||||
SET t.nachrichten_anz = tn.co
|
||||
WHERE t.schluessel = '$schluessel'"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (!$DEBUG) {
|
||||
if ($action_html != '') {
|
||||
$ticketnachricht = $this->ticketModule->CreateTicket(
|
||||
$this->projectId,
|
||||
$mailacc,
|
||||
$name_sender,
|
||||
$from,
|
||||
$subject,
|
||||
$action_html,
|
||||
$timestamp,
|
||||
"email",
|
||||
null,
|
||||
$verfasser_replyto,
|
||||
$mail_replyto
|
||||
); // ACHTUNG immer Projekt eprooshop
|
||||
} else {
|
||||
$ticketnachricht = $this->ticketModule->CreateTicket(
|
||||
$this->projectId,
|
||||
$mailacc,
|
||||
$name_sender,
|
||||
$from,
|
||||
$subject,
|
||||
$action,
|
||||
$timestamp,
|
||||
"email",
|
||||
null,
|
||||
$verfasser_replyto,
|
||||
$mail_replyto
|
||||
); // ACHTUNG immer Projekt eprooshop
|
||||
}
|
||||
$schluessel = $this->db->Select(
|
||||
"SELECT `ticket`
|
||||
FROM `ticket_nachricht`
|
||||
WHERE `id`='$ticketnachricht' LIMIT 1"
|
||||
);
|
||||
} else {
|
||||
echo "Lege neues Ticket an\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($ticketnachricht > 0 && $id > 0) {
|
||||
$this->db->Update(
|
||||
"UPDATE `emailbackup_mails`
|
||||
SET ticketnachricht='$ticketnachricht'
|
||||
WHERE id='$id' LIMIT 1"
|
||||
);
|
||||
if (is_array($cc_recv)) {
|
||||
foreach ($cc_recv as $mail) {
|
||||
if ($mail['name'] != '') {
|
||||
$cc_value =
|
||||
$this->db->real_escape_string($mail['name'])
|
||||
. ' <'
|
||||
. $this->db->real_escape_string($mail['email'])
|
||||
. ">";
|
||||
} else {
|
||||
$cc_value = $this->db->real_escape_string($mail['email']);
|
||||
}
|
||||
if ($cc_value != '') {
|
||||
$sql = "INSERT INTO ticket_header
|
||||
(`id`,`ticket_nachricht`,`type`,`value`)
|
||||
VALUES
|
||||
('', '$ticketnachricht', 'cc', '" . $cc_value . "')";
|
||||
$this->db->InsertWithoutLog($sql);
|
||||
}
|
||||
}
|
||||
$cc_recv = [];
|
||||
}
|
||||
}
|
||||
|
||||
// Prüfen ob Ordner vorhanden ansonsten anlegen
|
||||
$ordner = $this->config->WFuserdata . '/emailbackup/' . $this->config->WFdbname . "/$id";
|
||||
if (!is_dir($ordner) && $id > 0) {
|
||||
if (!mkdir($ordner, 0777, true) && !is_dir($ordner)) {
|
||||
}
|
||||
$raw_full_email = $message->getRawContent();
|
||||
file_put_contents($ordner . '/mail.txt', $raw_full_email);
|
||||
}
|
||||
|
||||
//speichere anhang als datei
|
||||
if ($anhang == 1 && $id > 0) {
|
||||
$ordner = $this->config->WFuserdata . '/emailbackup/' . $this->config->WFdbname;
|
||||
if (!is_dir($ordner)) {
|
||||
if (!mkdir($ordner, 0777, true) && !is_dir($ordner)) {
|
||||
$this->logger->error("Folder \"{folder}\" was not created", ['folder' => $ordner]);
|
||||
}
|
||||
}
|
||||
// Prüfen ob Ordner vorhanden ansonsten anlegen
|
||||
$ordner = $this->config->WFuserdata . '/emailbackup/' . $this->config->WFdbname . "/$id";
|
||||
if (!is_dir($ordner)) {
|
||||
if ($DEBUG) {
|
||||
echo "mkdir $ordner\n";
|
||||
} else {
|
||||
if (!mkdir($ordner, 0777, true) && !is_dir($ordner)) {
|
||||
$this->logger->error("Folder \"{folder}\" was not created", ['folder' => $ordner]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($attachments as $attachment) {
|
||||
if ($attachment->getFileName() !== '') {
|
||||
if ($DEBUG) {
|
||||
} else {
|
||||
$handle = fopen($ordner . '/' . $attachment->getFileName(), 'wb');
|
||||
if ($handle) {
|
||||
fwrite($handle, $attachment->getContent());
|
||||
fclose($handle);
|
||||
}
|
||||
}
|
||||
//Schreibe Anhänge in Datei-Tabelle
|
||||
$datei = $ordner . '/' . $attachment->getFileName();
|
||||
$dateiname = $attachment->getFileName();
|
||||
if (stripos($dateiname, '=?utf-8') !== false) {
|
||||
$dateiname = $this->formatter->encodeToUtf8($dateiname);
|
||||
$dateiname = htmlspecialchars_decode($dateiname);
|
||||
}
|
||||
if (stripos($dateiname, '=?iso-8859') !== false) {
|
||||
$dateiname = $this->formatter->encodeToUtf8($dateiname);
|
||||
$dateiname = htmlspecialchars_decode($dateiname);
|
||||
}
|
||||
|
||||
if ($DEBUG) {
|
||||
echo "CreateDatei($dateiname,{$dateiname},\"\",\"\",\"datei\",\"Support Mail\",true,"
|
||||
. $this->config->WFuserdata . "/dms/" . $this->config->WFdbname . ")\n";
|
||||
} else {
|
||||
$tmpid = $this->erpApi->CreateDatei(
|
||||
$dateiname,
|
||||
$dateiname,
|
||||
'',
|
||||
'',
|
||||
$datei,
|
||||
'Support Mail',
|
||||
true,
|
||||
$this->config->WFuserdata . '/dms/' . $this->config->WFdbname
|
||||
);
|
||||
}
|
||||
|
||||
if ($DEBUG) {
|
||||
echo "AddDateiStichwort $tmpid,'Anhang','Ticket',$ticketnachricht,true)\n";
|
||||
} else {
|
||||
$this->erpApi->AddDateiStichwort(
|
||||
$tmpid,
|
||||
'Anhang',
|
||||
'Ticket',
|
||||
$ticketnachricht,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$text = $this->mailAccount->getAutoresponseText();
|
||||
$betreff = $this->mailAccount->getAutoresponseSubject();
|
||||
$text = str_replace('{TICKET}', $schluessel, $text);
|
||||
$text = str_replace('{BETREFF}', $subject, $text);
|
||||
$betreff = str_replace('{TICKET}', $schluessel, $betreff);
|
||||
$betreff = str_replace('{BETREFF}', $subject, $betreff);
|
||||
|
||||
if (
|
||||
$this->mailAccount->isAutoresponseEnabled()
|
||||
&& $this->mailAccount->getAutoresponseText() !== ''
|
||||
&& (
|
||||
$this->erpApi->AutoresponderBlacklist($from) !== 1
|
||||
|| $this->mailAccount->isAutoresponseLimitEnabled() === false
|
||||
)
|
||||
) {
|
||||
if (!$this->erpApi->isHTML($text)) {
|
||||
$text = str_replace("\r\n", '<br>', $text);
|
||||
}
|
||||
$this->erpApi->MailSend(
|
||||
$this->mailAccount->getSenderEmailAddress(),
|
||||
'',
|
||||
$from,
|
||||
$name_sender,
|
||||
$betreff,
|
||||
$text
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ticket\Task;
|
||||
|
||||
use DB as LegacyDataBase;
|
||||
use Ticket as TicketModule;
|
||||
use erpAPI;
|
||||
use Config as LegacyConfig;
|
||||
|
||||
use Xentral\Components\Logger\Logger;
|
||||
use Xentral\Components\MailClient\Client\MailClientInterface;
|
||||
use Xentral\Modules\SystemMailer\Data\EmailBackupAccount;
|
||||
use Xentral\Modules\Ticket\Importer\TicketFormatter;
|
||||
|
||||
class TicketImportHelperFactory
|
||||
{
|
||||
/** @var LegacyDataBase $db */
|
||||
private $db;
|
||||
|
||||
/** @var erpAPI $erpApi */
|
||||
private $erpApi;
|
||||
|
||||
/** @var LegacyConfig $config */
|
||||
private $config;
|
||||
|
||||
/** @var TicketModule $ticketModule */
|
||||
private $ticketModule;
|
||||
|
||||
/** @var TicketFormatter $formatter */
|
||||
private $formatter;
|
||||
|
||||
/** @var Logger $logger */
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* TicketImportHelperFactory constructor.
|
||||
*
|
||||
* @param LegacyDataBase $db
|
||||
* @param erpAPI $erpApi
|
||||
* @param LegacyConfig $config
|
||||
* @param TicketModule $ticketModule
|
||||
* @param TicketFormatter $formatter
|
||||
* @param Logger $logger
|
||||
*/
|
||||
public function __construct(
|
||||
LegacyDataBase $db,
|
||||
erpAPI $erpApi,
|
||||
LegacyConfig $config,
|
||||
TicketModule $ticketModule,
|
||||
TicketFormatter $formatter,
|
||||
Logger $logger
|
||||
) {
|
||||
$this->db = $db;
|
||||
$this->erpApi = $erpApi;
|
||||
$this->ticketModule = $ticketModule;
|
||||
$this->config = $config;
|
||||
$this->formatter = $formatter;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MailClientInterface $mailClient
|
||||
* @param EmailBackupAccount $mailAccount
|
||||
* @param int $projectId
|
||||
*
|
||||
* @return TicketImportHelper
|
||||
*/
|
||||
public function create(
|
||||
MailClientInterface $mailClient,
|
||||
EmailBackupAccount $mailAccount,
|
||||
int $projectId
|
||||
): TicketImportHelper
|
||||
{
|
||||
$helper = new TicketImportHelper(
|
||||
$this->db,
|
||||
$this->erpApi,
|
||||
$this->ticketModule,
|
||||
$this->config,
|
||||
$this->formatter,
|
||||
$mailClient,
|
||||
$mailAccount,
|
||||
$projectId
|
||||
);
|
||||
$helper->setLogger($this->logger);
|
||||
|
||||
return $helper;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ticket\Wrapper;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
|
||||
class AddressWrapper
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* AddressWrapper constructor.
|
||||
*
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $emailAddress
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function tryGetAddressIdByEmailAddress(string $emailAddress): ?int
|
||||
{
|
||||
$values = ['email_address' => $emailAddress];
|
||||
$searchByEmail = 'SELECT a.id FROM `adresse` AS `a`
|
||||
WHERE a.email LIKE :email_address AND a.geloescht = 0
|
||||
ORDER BY a.id DESC';
|
||||
$id = $this->db->fetchValue($searchByEmail, $values);
|
||||
if ($id !== null && $id > 0) {
|
||||
return $id;
|
||||
}
|
||||
|
||||
$searchByResponsePerson = 'SELECT ap.adresse FROM `ansprechpartner` AS `ap`
|
||||
WHERE ap.email LIKE :email_address
|
||||
ORDER BY ap.id DESC';
|
||||
$id = $this->db->fetchValue($searchByResponsePerson, $values);
|
||||
if ($id !== null && $id > 0) {
|
||||
return $id;
|
||||
}
|
||||
|
||||
$searchByContactInfo = 'SELECT ak.adresse FROM `adresse_kontakte` AS `ak`
|
||||
WHERE ak.kontakt LIKE :email_address ORDER BY ak.id DESC';
|
||||
$id = $this->db->fetchValue($searchByContactInfo, $values);
|
||||
|
||||
return $id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Ticket\Wrapper;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\Ticket\Exception\InvalidArgumentException;
|
||||
|
||||
class EmailBackupWrapper
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $emailAccountId
|
||||
* @param string $subject
|
||||
* @param string $sender
|
||||
* @param string $plainTextBody
|
||||
* @param string $htmlBody
|
||||
* @param int $timestamp
|
||||
* @param bool $hasAttachment
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function createEmailBackup(
|
||||
int $emailAccountId,
|
||||
string $subject,
|
||||
string $sender,
|
||||
string $plainTextBody,
|
||||
string $htmlBody,
|
||||
int $timestamp,
|
||||
bool $hasAttachment
|
||||
): int {
|
||||
$sql = 'INSERT INTO `emailbackup_mails` (
|
||||
`webmail`, `subject`, `sender`, `action`, `action_html`,
|
||||
`empfang`, `anhang`, `checksum`
|
||||
) VALUES (
|
||||
:mail_account_id, :subject, :sender, :action, :action_html,
|
||||
:date_received, :has_attachment, :checksum
|
||||
)';
|
||||
$date = date('Y-m-d H:i:s', $timestamp);
|
||||
$checksum = md5($sender . $subject . $timestamp);
|
||||
$values = [
|
||||
'mail_account_id' => $emailAccountId,
|
||||
'subject' => $subject,
|
||||
'sender' => $sender,
|
||||
'action' => $plainTextBody,
|
||||
'action_html' => $htmlBody,
|
||||
'date_received' => $date,
|
||||
'has_attachment' => (int)$hasAttachment,
|
||||
'checksum' => $checksum,
|
||||
];
|
||||
$this->db->perform($sql, $values);
|
||||
|
||||
return $this->db->lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $emailAccountId
|
||||
* @param string $sender
|
||||
* @param string $subject
|
||||
* @param int $timestamp
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function existsEmailBackup(int $emailAccountId, string $sender, string $subject, int $timestamp): bool
|
||||
{
|
||||
$date = date('Y-m-d H:i:s', $timestamp);
|
||||
$checksum = md5($sender . $subject . $timestamp);
|
||||
$sql = 'SELECT COUNT(eb.id)
|
||||
FROM `emailbackup_mails` AS `eb`
|
||||
WHERE eb.checksum = :checksum AND eb.empfang = :date_received AND eb.webmail = :email_account_id';
|
||||
$values = [
|
||||
'checksum' => $checksum,
|
||||
'date_received' => $date,
|
||||
'email_account_id' => $emailAccountId,
|
||||
];
|
||||
$entriesCount = $this->db->fetchValue($sql, $values);
|
||||
|
||||
return $entriesCount !== null && $entriesCount > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $emailBackupId
|
||||
* @param string $message
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addTicketMessageToEmailBackup(int $emailBackupId, string $message): void
|
||||
{
|
||||
if (!$this->existsEmailBackupId($emailBackupId)) {
|
||||
throw new InvalidArgumentException('email backup does not exits');
|
||||
}
|
||||
$sql = 'UPDATE `emailbackup_mails` SET `ticketnachricht` = :message WHERE `id` = :id';
|
||||
$this->db->perform($sql, ['message' => $message, 'id' => $emailBackupId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $emailBackupId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function existsEmailBackupId(int $emailBackupId): bool
|
||||
{
|
||||
$sql = 'SELECT COUNT(eb.id)
|
||||
FROM `emailbackup_mails` AS `eb` WHERE eb.id = :id';
|
||||
$id = $this->db->fetchValue($sql, ['id' => $emailBackupId]);
|
||||
|
||||
return $id === $emailBackupId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
/**
|
||||
ANHÄNGE
|
||||
*/
|
||||
ul.file-attachments {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 5px 0;
|
||||
}
|
||||
ul.file-attachments li {
|
||||
display: flex;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 2px 0;
|
||||
}
|
||||
ul.file-attachments li * {
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
ul.file-attachments li a {
|
||||
padding-left: 5px;
|
||||
}
|
||||
@@ -0,0 +1,434 @@
|
||||
var TicketFiles = function ($) {
|
||||
"use strict";
|
||||
|
||||
var me = {
|
||||
elem: {},
|
||||
|
||||
selector: {
|
||||
dialog: '#attachment-assign-dialog',
|
||||
dialogTabs: '#filetabs',
|
||||
dialogContent: '#assign-dialog-content',
|
||||
documentTableContainer: '.document-table-container',
|
||||
documentFilterCheckbox: '.document-filter-checkbox',
|
||||
documentAssignButton: '.document-assign-action',
|
||||
createLiabilityButton: '.create-liability-button'
|
||||
},
|
||||
|
||||
storage: {
|
||||
fileId: null,
|
||||
previewFileId: null,
|
||||
documentType: 'verbindlichkeit',
|
||||
dataTableSettings: {}
|
||||
},
|
||||
|
||||
init: function () {
|
||||
me.elem.$assignDialog = $(me.selector.dialog);
|
||||
me.attachEvents();
|
||||
me.initDialog();
|
||||
},
|
||||
|
||||
/**
|
||||
* Benötigte Events attachen
|
||||
*/
|
||||
attachEvents: function () {
|
||||
// Hinzufügen-Button wird angeklickt
|
||||
$(document).on('click', '.attachment-assign-button', function (e) {
|
||||
e.preventDefault();
|
||||
me.onClickAddButton(this);
|
||||
});
|
||||
|
||||
// Im Dialog-Modal wird der Tab gewechselt
|
||||
$(document).on('tabsactivate', me.selector.dialogTabs, function(event, ui) {
|
||||
me.onChangeFileTab(ui.newTab, ui.oldTab);
|
||||
});
|
||||
|
||||
// DataTable-Filter wird geändert
|
||||
$(document).on('change', me.selector.documentFilterCheckbox, function () {
|
||||
me.onChangeTableFilter(this);
|
||||
});
|
||||
|
||||
// "Datei zuweisen"-Button wurde in UI-Dialog-Table angeklickt
|
||||
$(document).on('click', me.selector.documentAssignButton, function (e) {
|
||||
e.preventDefault();
|
||||
me.onClickDocumentAssignButton(this);
|
||||
});
|
||||
|
||||
// Neue Verbindlichkeit anlegen
|
||||
$(document).on('click', me.selector.createLiabilityButton, function () {
|
||||
me.createNewLiability();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} element
|
||||
*/
|
||||
onClickAddButton: function (element) {
|
||||
var fileId = parseInt($(element).data('file'));
|
||||
if (isNaN(fileId) || fileId === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// UI-Dialog anzeigen
|
||||
me.storage.fileId = fileId;
|
||||
me.displayDialog();
|
||||
},
|
||||
|
||||
/**
|
||||
* Im UI-Dialog wird der Tab gewechselt
|
||||
*
|
||||
* @param {HTMLElement} newTab Tab-Element das aktiviert wird
|
||||
* @param {HTMLElement} oldTab Tab-Element das vorher aktiv war
|
||||
*/
|
||||
onChangeFileTab: function (newTab, oldTab) {
|
||||
var docTypeBefore = $(oldTab).data('type');
|
||||
me.destroyDataTable(docTypeBefore);
|
||||
|
||||
me.storage.documentType = $(newTab).data('type');
|
||||
me.loadDataTable();
|
||||
},
|
||||
|
||||
/**
|
||||
* "Datei zuweisen"-Button wurde angeklickt
|
||||
*
|
||||
* @param {HTMLElement} element Angeklickter Button
|
||||
*/
|
||||
onClickDocumentAssignButton: function (element) {
|
||||
var $tableRow = $(element).parents('tr');
|
||||
if (!$.fn.DataTable.isDataTable(me.elem.$currentDataTable)) {
|
||||
alert('Unbekannter Fehler #1: DataTable konnte nicht gefunden werden.');
|
||||
return;
|
||||
}
|
||||
var $dataTable = me.elem.$currentDataTable.DataTable();
|
||||
var data = $dataTable.row($tableRow).data();
|
||||
|
||||
// ID aus DataTable-Datensatz holen
|
||||
var objectId = parseInt(data.id);
|
||||
if (isNaN(objectId)) {
|
||||
alert('Unbekannter Fehler #2: ID für Zuweisung konnte nicht gefunden werden.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Datei-Stichwort zuweisen
|
||||
me.assignDocumentKeyword(me.storage.documentType, objectId);
|
||||
},
|
||||
|
||||
/**
|
||||
* Datei-Stichwort zuweisen
|
||||
*
|
||||
* @param {string} documentType
|
||||
* @param {number} objectId
|
||||
*/
|
||||
assignDocumentKeyword: function (documentType, objectId) {
|
||||
$.ajax({
|
||||
url: 'index.php?module=ticket&action=assistent&cmd=assign-file',
|
||||
data: {keyword: documentType, file: me.storage.fileId, object: objectId},
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function(result) {
|
||||
if (result.success === false) {
|
||||
alert('Unbekannter Fehler #3. Datei konnte nicht zugewiesen werden.');
|
||||
}
|
||||
me.closeDialog();
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* DataTable-Filter wurde geändert
|
||||
*
|
||||
* @param {HTMLElement} element
|
||||
*/
|
||||
onChangeTableFilter: function (element) {
|
||||
var isActive = $(element).prop('checked');
|
||||
var filterColumn = $(element).data('filter-column');
|
||||
if (typeof isActive === 'undefined' || typeof filterColumn === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prüfen ob DataTable vorhanden
|
||||
if (!$.fn.DataTable.isDataTable(me.elem.$currentDataTable)) {
|
||||
return;
|
||||
}
|
||||
var dataTable = me.elem.$currentDataTable.DataTable();
|
||||
|
||||
// Filter anwenden
|
||||
if (isActive) {
|
||||
dataTable.column(filterColumn).search('true', false, false, false).draw();
|
||||
} else {
|
||||
dataTable.column(filterColumn).search('', false, false, false).draw();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* UI-Dialog initialisieren
|
||||
*/
|
||||
initDialog: function () {
|
||||
me.elem.$assignDialog.dialog({
|
||||
title: 'Datei-Zuordnung',
|
||||
modal: true,
|
||||
minWidth: 900,
|
||||
closeOnEscape: false,
|
||||
autoOpen: false,
|
||||
resizable: false
|
||||
});
|
||||
|
||||
// Tabs initialisieren
|
||||
$(me.selector.dialogTabs).tabs();
|
||||
},
|
||||
|
||||
/**
|
||||
* UI-Dialog anzeigen (vorher DataTable laden)
|
||||
*/
|
||||
displayDialog: function () {
|
||||
me.loadDataTable().then(me.openDialog);
|
||||
},
|
||||
|
||||
/**
|
||||
* HTML-Template und DataTable-Einstellungen laden
|
||||
*
|
||||
* @return {Deferred} jQuery Promise Object
|
||||
*/
|
||||
loadDataTable: function () {
|
||||
return me.fetchDataTableHtmlTemplate()
|
||||
.then(me.fetchDataTableSettings)
|
||||
.then(me.initDataTable);
|
||||
},
|
||||
|
||||
/**
|
||||
* UI-Dialog öffnen
|
||||
*/
|
||||
openDialog: function () {
|
||||
window.setTimeout(function () {
|
||||
// Kurz warten bis DataTable aufgebaut ist, damit Höhe berechnet werden kann
|
||||
me.elem.$assignDialog.dialog('open');
|
||||
me.elem.$assignDialog.dialog('option', 'height', 'auto');
|
||||
}, 150);
|
||||
},
|
||||
|
||||
/**
|
||||
* UI-Dialog schließen
|
||||
*/
|
||||
closeDialog: function () {
|
||||
me.elem.$assignDialog.dialog('close');
|
||||
},
|
||||
|
||||
/**
|
||||
* DataTable initialisieren
|
||||
*/
|
||||
initDataTable: function () {
|
||||
var $tabContent = me.elem.$assignDialog.find('#' + me.storage.documentType + '-tab');
|
||||
me.elem.$currentDataTable = $tabContent.find('table.display');
|
||||
me.elem.$currentDataTable.css('width', '100%');
|
||||
|
||||
// DataTable ist bereist initialisiert > Instanz zerstören
|
||||
if ($.fn.DataTable.isDataTable(me.elem.$currentDataTable)) {
|
||||
me.elem.$currentDataTable.DataTable().destroy();
|
||||
}
|
||||
|
||||
// DataTable initialisieren
|
||||
var table = me.elem.$currentDataTable.DataTable(me.storage.dataTableSettings);
|
||||
table.on('init.dt', function () { $(me.selector.documentTableContainer).show(); })
|
||||
},
|
||||
|
||||
/**
|
||||
* Zerstört eine DataTable-Instanz
|
||||
*
|
||||
* @param {string} docType
|
||||
*/
|
||||
destroyDataTable: function (docType) {
|
||||
var $tabContent = me.elem.$assignDialog.find('#' + docType + '-tab');
|
||||
var $table = $tabContent.find('table.display');
|
||||
|
||||
if ($.fn.DataTable.isDataTable($table)) {
|
||||
$table.DataTable().destroy();
|
||||
me.elem.$currentDataTable = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* DataTable-HTML-Tabelle laden
|
||||
*
|
||||
* @return {jqXHR} jQuery jqXHR-Objekt
|
||||
*/
|
||||
fetchDataTableHtmlTemplate: function () {
|
||||
return $.ajax({
|
||||
url: 'index.php?module=ticket&action=assistent&cmd=table-html',
|
||||
data: { 'type': me.storage.documentType, 'id': me.storage.fileId },
|
||||
type: 'GET',
|
||||
dataType: 'html',
|
||||
success: function(data) {
|
||||
me.elem.$assignDialog.find('#' + me.storage.documentType + '-tab').html(data);
|
||||
me.elem.$assignDialog.find(me.selector.documentTableContainer).hide();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* DataTable-Einstellungen laden
|
||||
*
|
||||
* @return {jqXHR} jQuery jqXHR-Objekt
|
||||
*/
|
||||
fetchDataTableSettings: function () {
|
||||
return $.ajax({
|
||||
url: 'index.php?module=ticket&action=assistent&cmd=table-settings',
|
||||
data: { 'type': me.storage.documentType, 'id': me.storage.fileId },
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
me.storage.dataTableSettings = data;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Neue Verbindlichkeit anlegen + Datei zuweisen
|
||||
*
|
||||
* Bei Erfolg wird die Verbindlichkeit geöffnet.
|
||||
*/
|
||||
createNewLiability: function () {
|
||||
$.ajax({
|
||||
url: 'index.php?module=ticket&action=assistent&cmd=create-liability',
|
||||
data: { 'id': me.storage.fileId },
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
if (typeof data.success === 'undefined' || data.success === false) {
|
||||
alert('Unbekannter Fehler #5. Verbindlichkeit konnte nicht angelegt werden.');
|
||||
return;
|
||||
}
|
||||
/** @namespace data.liability */
|
||||
if (typeof data.liability === 'undefined') {
|
||||
alert('Unbekannter Fehler #6. Verbindlichkeit konnte nicht angelegt werden.');
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = './index.php?module=verbindlichkeit&action=edit&id=' + data.liability;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
init: me.init
|
||||
};
|
||||
|
||||
}(jQuery);
|
||||
|
||||
var TicketTree = function($) {
|
||||
"use strict";
|
||||
|
||||
var me = {
|
||||
elem: {},
|
||||
storage: {
|
||||
api:null,
|
||||
},
|
||||
selector: {
|
||||
|
||||
},
|
||||
initTree: function() {
|
||||
$('#mlmTree').aciTree({
|
||||
autoInit: false,
|
||||
checkboxChain: false,
|
||||
ajax: {
|
||||
url: 'index.php?module=ticket&action=antwort&cmd=gettree&id='+$('.mlmTreeContainerLeft').data('id')
|
||||
},
|
||||
checkbox: true,
|
||||
itemHook: function(parent, item, itemData, level) {
|
||||
},
|
||||
filterHook: function(item, search, regexp) {
|
||||
|
||||
if (search.length) {
|
||||
var parent = this.parent(item);
|
||||
|
||||
if (parent.length) {
|
||||
var label = this.getLabel(parent);
|
||||
if (regexp.test(String(label))) {
|
||||
this.setVisible(item);
|
||||
return true;
|
||||
}
|
||||
this.setVisible(item);
|
||||
}
|
||||
|
||||
if (regexp.test(String(this.getLabel(item)))) {
|
||||
item.addClass('searched');
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
init: function () {
|
||||
me.initTree();
|
||||
|
||||
me.storage.api = $('#mlmTree').aciTree('api');
|
||||
$('#search').val('');
|
||||
var last = '';
|
||||
|
||||
$('#search').on('keyup', function() {
|
||||
if ($(this).val() === last) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('.aciTreeLi').removeClass('searched');
|
||||
|
||||
last = $(this).val();
|
||||
me.storage.api.filter(null, {
|
||||
search: $(this).val(),
|
||||
callback: function() {
|
||||
|
||||
},
|
||||
success: function(item, options) {
|
||||
|
||||
if (!options.first) {
|
||||
//alert('No results found!');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#mlmTree').on('acitree', function(event, api, item, eventName, options){
|
||||
switch (eventName){
|
||||
case 'checked':
|
||||
break;
|
||||
case 'unchecked':
|
||||
break;
|
||||
case 'selected':
|
||||
var itemData = api.itemData(item);
|
||||
if(typeof itemData.vorlage != 'undefined') {
|
||||
einfuegenticket(itemData.vorlage);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (api.isItem(item)){
|
||||
//console.log('the event is: ' + eventName + ' for the item ID: ' + api.getId(item));
|
||||
} else {
|
||||
//console.log('the event is: ' + eventName + ' for the tree ROOT');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#mlmTree').aciTree('init');
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: me.init
|
||||
};
|
||||
|
||||
}(jQuery);
|
||||
|
||||
$(document).ready(function () {
|
||||
if ($('div.mlmTreeContainerLeft').length > 0) {
|
||||
TicketTree.init();
|
||||
}
|
||||
if ($('#ticketassistent').length === 0) {
|
||||
return;
|
||||
}
|
||||
TicketFiles.init();
|
||||
});
|
||||
@@ -0,0 +1,306 @@
|
||||
var TicketTemplate = function ($) {
|
||||
"use strict";
|
||||
|
||||
var me = {
|
||||
storage: {
|
||||
api : null,
|
||||
},
|
||||
selector: {
|
||||
overviewTable: '#ticket_vorlagenlist',
|
||||
itemPopup: '#tickettemplatepopup',
|
||||
newButton: 'input#newtemplate',
|
||||
},
|
||||
updateOverviewTable: function() {
|
||||
$(me.selector.overviewTable).DataTable().ajax.reload();
|
||||
},
|
||||
saveItem: function()
|
||||
{
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: 'index.php?module=ticket_vorlage&action=list&cmd=saveitem',
|
||||
data: {
|
||||
itemId: $('#itemid').val(),
|
||||
name:$('#itemname').val(),
|
||||
text:$('#itemtext').val(),
|
||||
project:$('#itemproject').val(),
|
||||
category:$('#itemcategory').val(),
|
||||
sort:$('#itemsort').val(),
|
||||
visible:$('#itemvisible').prop('checked')?1:0,
|
||||
},
|
||||
success: function () {
|
||||
$(me.selector.itemPopup).dialog('close');
|
||||
me.updateOverviewTable();
|
||||
}
|
||||
});
|
||||
},
|
||||
resetItem: function()
|
||||
{
|
||||
$('#itemid').val('');
|
||||
$('#itemname').val('');
|
||||
$('#itemtext').val('');
|
||||
$('#itemsort').val('');
|
||||
$('#itemcategory').val('');
|
||||
$('#itemvisible').prop('checked', false);
|
||||
},
|
||||
|
||||
getItem: function(itemId)
|
||||
{
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: 'index.php?module=ticket_vorlage&action=list&cmd=getitem',
|
||||
data: {
|
||||
itemId: itemId,
|
||||
categoryId: $('#categoryid').val(),
|
||||
name:$('#newtemplatename').val()
|
||||
},
|
||||
success: function (data) {
|
||||
if(typeof data.id == 'undefined') {
|
||||
me.resetItem();
|
||||
$(me.selector.itemPopup).dialog('open');
|
||||
return;
|
||||
}
|
||||
$('#itemid').val(data.id);
|
||||
$('#itemname').val(data.name);
|
||||
$('#itemtext').val(data.text);
|
||||
$('#itemsort').val(data.sort);
|
||||
$('#itemcategory').val(data.category);
|
||||
$('#itemvisible').prop('checked', data.visible == '1');
|
||||
$(me.selector.itemPopup).dialog('open');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
initTree: function() {
|
||||
$('#mlmTree').aciTree({
|
||||
autoInit: false,
|
||||
checkboxChain: false,
|
||||
ajax: {
|
||||
url: 'index.php?module=ticket_vorlage&action=list&cmd=gettree'
|
||||
},
|
||||
checkbox: true,
|
||||
itemHook: function(parent, item, itemData, level) {
|
||||
//console.log(itemData);
|
||||
},
|
||||
filterHook: function(item, search, regexp) {
|
||||
|
||||
if (search.length) {
|
||||
var parent = this.parent(item);
|
||||
|
||||
if (parent.length) {
|
||||
var label = this.getLabel(parent);
|
||||
if (regexp.test(String(label))) {
|
||||
this.setVisible(item);
|
||||
return true;
|
||||
}
|
||||
this.setVisible(item);
|
||||
}
|
||||
|
||||
if (regexp.test(String(this.getLabel(item)))) {
|
||||
item.addClass('searched');
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
//return regexp.test(String(this.getLabel(item)));
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
initOverview: function() {
|
||||
$(me.selector.newButton).on('click',function () {
|
||||
me.getItem(0);
|
||||
});
|
||||
$(me.selector.overviewTable).on('afterreload',function() {
|
||||
$(this).find('img.deleteitem').on('click', function() {
|
||||
if(confirm('Wirklich löschen?')) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: 'index.php?module=ticket_vorlage&action=list&cmd=deleteitem',
|
||||
data: {
|
||||
itemId: $(this).data('id')
|
||||
},
|
||||
success: function () {
|
||||
me.updateOverviewTable();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
$(this).find('img.edititem').on('click', function() {
|
||||
me.getItem($(this).data('id'));
|
||||
});
|
||||
});
|
||||
|
||||
$(me.selector.itemPopup).toggleClass('hidden', false);
|
||||
$(me.selector.itemPopup).dialog(
|
||||
{
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
minWidth: 940,
|
||||
title:'',
|
||||
buttons: {
|
||||
'ABBRECHEN': function() {
|
||||
$(this).dialog('close');
|
||||
},
|
||||
'SPEICHERN': function()
|
||||
{
|
||||
me.saveItem();
|
||||
},
|
||||
},
|
||||
close: function(event, ui){
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
$('#savesubcategory').on('click',function(){
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: 'index.php?module=ticket_vorlage&action=list&cmd=savenewsubcategory',
|
||||
data: {
|
||||
categoryId: $('#categoryid').val(),
|
||||
name: $('#subcategoriename').val(),
|
||||
},
|
||||
success: function () {
|
||||
$('#mlmTree').aciTree('api').unload(null, {
|
||||
success: function() {
|
||||
this.ajaxLoad(null);
|
||||
}
|
||||
});
|
||||
me.updateOverviewTable();
|
||||
$('#subcategoriename').val('');
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#savecategory').on('click',function(){
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: 'index.php?module=ticket_vorlage&action=list&cmd=savecategory',
|
||||
data: {
|
||||
categoryId: $('#categoryid').val(),
|
||||
name: $('#categoriename').val(),
|
||||
},
|
||||
success: function () {
|
||||
$('#mlmTree').aciTree('api').unload(null, {
|
||||
success: function() {
|
||||
this.ajaxLoad(null);
|
||||
}
|
||||
});
|
||||
me.updateOverviewTable();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#deletecategory').on('click',function(){
|
||||
if(!confirm('Wirklich löschen?')) {
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: 'index.php?module=ticket_vorlage&action=list&cmd=deletecategory',
|
||||
data: {
|
||||
categoryId: $('#categoryid').val()
|
||||
},
|
||||
success: function () {
|
||||
$('#categoryid').val('');
|
||||
$('#categoriename').val('');
|
||||
$('#mlmTree').aciTree('api').unload(null, {
|
||||
success: function() {
|
||||
this.ajaxLoad(null);
|
||||
}
|
||||
});
|
||||
|
||||
me.updateOverviewTable();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
me.initTree();
|
||||
|
||||
|
||||
me.storage.api = $('#mlmTree').aciTree('api');
|
||||
|
||||
|
||||
$('#search').val('');
|
||||
var last = '';
|
||||
|
||||
$('#search').on('keyup', function() {
|
||||
if ($(this).val() === last) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('.aciTreeLi').removeClass('searched');
|
||||
|
||||
last = $(this).val();
|
||||
me.storage.api.filter(null, {
|
||||
search: $(this).val(),
|
||||
callback: function() {
|
||||
|
||||
},
|
||||
success: function(item, options) {
|
||||
|
||||
if (!options.first) {
|
||||
//alert('No results found!');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#mlmTree').on('acitree', function(event, api, item, eventName, options){
|
||||
switch (eventName){
|
||||
case 'checked':
|
||||
break;
|
||||
case 'unchecked':
|
||||
break;
|
||||
case 'selected':
|
||||
|
||||
var ajaxData = {
|
||||
id: api.getId(item),
|
||||
name: api.getLabel(item)
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: 'index.php?module=ticket_vorlage&action=list&cmd=gettreedetail',
|
||||
data: ajaxData,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
$('#categoryid').val(data.id);
|
||||
$('#categoriename').val(data.name);
|
||||
me.updateOverviewTable();
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
default:
|
||||
if (api.isItem(item)){
|
||||
//console.log('the event is: ' + eventName + ' for the item ID: ' + api.getId(item));
|
||||
} else {
|
||||
//console.log('the event is: ' + eventName + ' for the tree ROOT');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#mlmTree').aciTree('init');
|
||||
},
|
||||
|
||||
init: function () {
|
||||
if($(me.selector.overviewTable).length) {
|
||||
me.initOverview();
|
||||
}
|
||||
}
|
||||
};
|
||||
return {
|
||||
init: me.init,
|
||||
|
||||
};
|
||||
|
||||
}(jQuery);
|
||||
|
||||
$(document).ready(function () {
|
||||
TicketTemplate.init();
|
||||
});
|
||||
Reference in New Issue
Block a user