Вопрос от Поддержки

This commit is contained in:
n1rwana 2023-08-03 18:56:19 +03:00
parent a2384cc231
commit ccbf892e79
11 changed files with 112 additions and 9 deletions

View file

@ -32,8 +32,13 @@ class SupportAgent extends RowModel
return $this->getRecord()->numerate; return $this->getRecord()->numerate;
} }
function getUser(): User
{
return (new Users)->get((int) $this->getAgentId());
}
function getRealName(): string function getRealName(): string
{ {
return (new Users)->get($this->getAgentId())->getCanonicalName(); return $this->getUser()->getCanonicalName();
} }
} }

View file

@ -1,5 +1,6 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
namespace openvk\Web\Models\Entities; namespace openvk\Web\Models\Entities;
use openvk\Web\Models\Repositories\SupportAgents;
use openvk\Web\Util\DateTime; use openvk\Web\Util\DateTime;
use openvk\Web\Models\RowModel; use openvk\Web\Models\RowModel;
use openvk\Web\Models\Repositories\Users; use openvk\Web\Models\Repositories\Users;
@ -64,5 +65,15 @@ class Ticket extends RowModel
return false; return false;
} }
function getSupportSender(): ?SupportAgent
{
return (new SupportAgents)->get((int) $this->getRecord()->support_sender);
}
function isFromSupport(): bool
{
return $this->getSupportSender() !== NULL;
}
use Traits\TRichText; use Traits\TRichText;
} }

View file

@ -1031,7 +1031,7 @@ class User extends RowModel
function adminNotify(string $message): bool function adminNotify(string $message): bool
{ {
$admId = OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"]; $admId = (int) OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"];
if(!$admId) if(!$admId)
return false; return false;
else if(is_null($admin = (new Users)->get($admId))) else if(is_null($admin = (new Users)->get($admId)))

View file

@ -152,7 +152,7 @@ final class SupportPresenter extends OpenVKPresenter
if(!empty($id)) { if(!empty($id)) {
$ticket = $this->tickets->get($id); $ticket = $this->tickets->get($id);
if(!$ticket || $ticket->isDeleted() != 0 || $ticket->getUserId() !== $this->user->id && !$this->hasPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0)) { if(!$ticket || $ticket->isDeleted() != 0 || (($ticket->getUserId() !== $this->user->id || $ticket->isFromSupport()) && !$this->hasPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0))) {
$this->notFound(); $this->notFound();
} else { } else {
if($ticket->getUserId() !== $this->user->id && $this->hasPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0)) if($ticket->getUserId() !== $this->user->id && $this->hasPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0))
@ -396,4 +396,37 @@ final class SupportPresenter extends OpenVKPresenter
$this->flashFail("succ", "Успех", "Профиль создан. Теперь пользователи видят Ваши псевдоним и аватарку вместо стандартных аватарки и номера."); $this->flashFail("succ", "Успех", "Профиль создан. Теперь пользователи видят Ваши псевдоним и аватарку вместо стандартных аватарки и номера.");
} }
} }
function renderSendUserTicket(): void
{
$this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
$this->assertNoCSRF();
if (!$this->postParam("uid") || !$this->postParam("text"))
$this->returnJson(["success" => false, "error" => "Один или несколько обязательных параметров не были переданы"]);
$user = (new Users)->get((int) $this->postParam("uid"));
if (!$user) $this->returnJson(["success" => false, "error" => "Пользователь не найден"]);
$ticket = new Ticket;
$ticket->setType(1);
$ticket->setUser_Id($user->getId());
$ticket->setName("[Вопрос от Поддержки]" . ($this->postParam("title") ? " " . $this->postParam("title") : ""));
$ticket->setText($this->postParam("text"));
$ticket->setCreated(time());
$ticket->setSupport_Sender($this->user->id);
$ticket->save();
$comment = new TicketComment;
$comment->setUser_Id($this->user->id);
$comment->setUser_Type(1);
$comment->setText($this->postParam("text"));
$comment->setCreated(time());
$comment->setTicket_Id($ticket->getId());
$comment->save();
$user->adminNotify(($user->isFemale() ? "Дорогая " : "Дорогой ") . $user->getFirstName() . "!\n\nВы получили новый вопрос (https://$_SERVER[SERVER_NAME]/support/view/{$ticket->getId()}) от Команды Поддержки " . OPENVK_ROOT_CONF["openvk"]["appearance"]["name"]);
$this->returnJson(["success" => true, "payload" => $ticket->getId()]);
}
} }

View file

@ -8,9 +8,16 @@
{block content} {block content}
<div class="post-author"> <div class="post-author">
<a href="#" style="font-size: 13px;"><b>{$ticket->getName()}</b></a><br /> <a href="#" style="font-size: 13px;"><b>{$ticket->getName()}</b></a><br />
{_author}: <a href="/id{$ticket->getUser()->getId()}">{$ticket->getUser()->getFullName()}</a> | {$ticket->getUser()->getRegistrationIP()} | {_status}: {$ticket->getStatus()}. {$ticket->isFromSupport() ? tr("user") : tr("author")}: <a href="/id{$ticket->getUser()->getId()}">{$ticket->getUser()->getFullName()}</a>
{if $ticket->isFromSupport()}
| {_author}:
<a href="{$ticket->getSupportSender()->getUser()->getURL()}">
{$ticket->getSupportSender()->getUser()->getCanonicalName()}
</a>
{/if}
| {$ticket->getUser()->getRegistrationIP()} | {_status}: {$ticket->getStatus()}.
</div> </div>
<div class="text" style="padding-top: 10px; border-bottom: #ECECEC solid 1px;"> <div class="text" style="padding-top: 10px; border-bottom: #ECECEC solid 1px;" n:if="!$ticket->isFromSupport()">
{$ticket->getText()|noescape} {$ticket->getText()|noescape}
<br /><br /> <br /><br />
</div> </div>

View file

@ -34,13 +34,16 @@
<a href="#" style="font-size:13px;"><b>{$ticket->getName()}</b></a> <a href="#" style="font-size:13px;"><b>{$ticket->getName()}</b></a>
<br />{_status}: {$ticket->getStatus()} <br />{_status}: {$ticket->getStatus()}
</div> </div>
<div class="text" style="padding-top: 10px; border-bottom: #ECECEC solid 1px;"> <div class="text" style="padding-top: 10px; border-bottom: #ECECEC solid 1px;" n:if="!$ticket->isFromSupport()">
{$ticket->getText()|noescape} {$ticket->getText()|noescape}
<br /></br> <br /><br />
</div> </div>
<div style="padding-top: 5px;"> <div style="padding-top: 5px;">
{$ticket->getTime()}&nbsp;|&nbsp; {$ticket->getTime()}
<span n:if="!$ticket->isFromSupport()">
&nbsp;|&nbsp;
<a href="/support/delete/{$id}?hash={$csrfToken}">{_delete}</a> <a href="/support/delete/{$id}?hash={$csrfToken}">{_delete}</a>
</span>
</div> </div>
{if $ticket->getType() !== 2} {if $ticket->getType() !== 2}
<br /> <br />

View file

@ -128,6 +128,9 @@
{_ban_in_support_user_action} {_ban_in_support_user_action}
{/if} {/if}
</a> </a>
<a href="javascript:newSupportTicketToUser()" class="profile_link" style="width: 194px;">
Вопрос от Поддержки
</a>
{/if} {/if}
<a style="width: 194px;" n:if="OPENVK_ROOT_CONF['openvk']['preferences']['commerce'] && $user->getGiftCount() == 0" href="/gifts?act=pick&user={$user->getId()}" class="profile_link">{_send_gift}</a> <a style="width: 194px;" n:if="OPENVK_ROOT_CONF['openvk']['preferences']['commerce'] && $user->getGiftCount() == 0" href="/gifts?act=pick&user={$user->getId()}" class="profile_link">{_send_gift}</a>
@ -688,6 +691,40 @@
]); ]);
} }
{/if} {/if}
function newSupportTicketToUser() {
uTicketMsgTxt = "Вы собираетесь связаться с пользователем <b>" + {$user->getCanonicalName()} + "</b> от имени Поддержки. Он получит об этом оповещение от имени служебного аккаунта.";
uTicketMsgTxt += "<br/><br/><b>Название</b>: <input type='text' id='uTicketTitle' placeholder='В начале будет добавлено \"[Вопрос от Поддержки]\"' />";
uTicketMsgTxt += "<br/><br/><b>Текст</b>: <textarea type='text' id='uTicketText' placeholder='Текст без приветствия и завершения' style='resize: vertical; height: 185px;'></textarea>";
MessageBox("Отправить вопрос", uTicketMsgTxt, ["Отправить", "Отмена"], [
(function () {
title = $("#uTicketTitle").val();
text = $("#uTicketText").val()
$.ajax({
type: "POST",
url: "/al_helpdesk/sendTicket",
data: {
uid: {$user->getId()},
title: title,
text: text,
hash: {=$csrfToken}
},
success: (response) => {
if (response.success) {
MessageBox("Успех", "Пользователь получил вопрос и оповещения<br/><br/><a href='/support/reply/" + response.payload + "' target='_blank'>Перейти к вопросу</a>", ["OK"], [Function.noop]);
} else {
MessageBox("Ошибка", "При отправке запроса произошла ошибка: " + (response?.error ?? "Неизвестная ошибка"), ["OK"], [Function.noop]);
}
}
})
}),
Function.noop
])
$(".ovk-diag-cont").width("650px");
}
</script> </script>
<script n:if="isset($thisUser) && $user->getId() == $thisUser->getId()" n:syntax="off"> <script n:if="isset($thisUser) && $user->getId() == $thisUser->getId()" n:syntax="off">

View file

@ -35,6 +35,8 @@ routes:
handler: "Support->agent" handler: "Support->agent"
- url: "/support/agent{num}/edit" - url: "/support/agent{num}/edit"
handler: "Support->editAgent" handler: "Support->editAgent"
- url: "/al_helpdesk/sendTicket"
handler: "Support->sendUserTicket"
- url: "/language" - url: "/language"
handler: "About->language" handler: "About->language"
- url: "/language/{text}.js" - url: "/language/{text}.js"

View file

@ -0,0 +1,2 @@
ALTER TABLE `tickets`
ADD `support_sender` BIGINT UNSIGNED NULL DEFAULT NULL AFTER `created`;

View file

@ -913,6 +913,8 @@
"banned_in_support_1" = "Sorry, <b>$1</b>, but now you can't create tickets."; "banned_in_support_1" = "Sorry, <b>$1</b>, but now you can't create tickets.";
"banned_in_support_2" = "And the reason for this is simple: <b>$1</b>. Unfortunately, this time we had to take away this opportunity from you forever."; "banned_in_support_2" = "And the reason for this is simple: <b>$1</b>. Unfortunately, this time we had to take away this opportunity from you forever.";
"user" = "User";
/* Invite */ /* Invite */
"invite" = "Invite"; "invite" = "Invite";

View file

@ -841,6 +841,7 @@
"ticket_changed_comment" = "Изменения вступят силу через несколько секунд."; "ticket_changed_comment" = "Изменения вступят силу через несколько секунд.";
"banned_in_support_1" = "Извините, <b>$1</b>, но теперь вам нельзя создавать обращения."; "banned_in_support_1" = "Извините, <b>$1</b>, но теперь вам нельзя создавать обращения.";
"banned_in_support_2" = "А причина этому проста: <b>$1</b>. К сожалению, на этот раз нам пришлось отобрать у вас эту возможность навсегда."; "banned_in_support_2" = "А причина этому проста: <b>$1</b>. К сожалению, на этот раз нам пришлось отобрать у вас эту возможность навсегда.";
"user" = "Пользователь";
/* Invite */ /* Invite */