Initial xentral_oss_20.3.c9ffacf

This commit is contained in:
Alex
2021-05-21 08:49:41 +02:00
parent 5406e4a551
commit 34e5ac43d9
18884 changed files with 2109867 additions and 0 deletions
+57
View File
@@ -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;
}
}
+22
View File
@@ -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;
}
+434
View File
@@ -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();
});