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
@@ -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++;
}
}
}