Фитчи

This commit is contained in:
n1rwana 2022-08-22 02:11:48 +03:00
parent 5b46485a73
commit 3dcfc5dd50
13 changed files with 114 additions and 54 deletions

View file

@ -92,7 +92,7 @@ class BugReport extends RowModel
return $this->getRecord()->reproduced;
}
function getCreationDate(): DateTime
function getCreationTime(): DateTime
{
return new DateTime($this->getRecord()->created);
}

View file

@ -1,5 +1,6 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Entities;
use openvk\Web\Util\DateTime;
use openvk\Web\Models\{RowModel};
use openvk\Web\Models\Entities\{User, BugtrackerProduct};
use openvk\Web\Models\Repositories\{Users, BugtrackerProducts};
@ -43,4 +44,9 @@ class BugReportComment extends RowModel
{
return $this->getRecord()->point_actions;
}
function getCreationTime(): DateTime
{
return new DateTime($this->getRecord()->created);
}
}

View file

@ -1,5 +1,6 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Entities;
use openvk\Web\Util\DateTime;
use openvk\Web\Models\{RowModel};
use openvk\Web\Models\Entities\{User};
use openvk\Web\Models\Repositories\{Users};
@ -37,4 +38,9 @@ class BugtrackerProduct extends RowModel
{
return (bool) $this->getRecord()->closed;
}
function getCreationTime(): DateTime
{
return new DateTime($this->getRecord()->created);
}
}

View file

@ -1018,5 +1018,10 @@ class User extends RowModel
return (bool) $this->getRecord()->activated;
}
function isBtModerator(): bool
{
return $this->getChandlerUser()->can("admin")->model('openvk\Web\Models\Repositories\BugtrackerReports')->whichBelongsTo(NULL);
}
use Traits\TSubscribable;
}

View file

@ -25,15 +25,20 @@ class BugtrackerProducts
return $this->toProduct($this->products->get($id));
}
function getAll(): \Traversable
function getAll(int $page = 1): \Traversable
{
foreach($this->products->order("id ASC") as $product)
foreach($this->products->order("id ASC")->page($page, 5) as $product)
yield new BugtrackerProduct($product);
}
function getOpen(): \Traversable
function getOpen(int $page = 1): \Traversable
{
foreach($this->products->where(["closed" => 0])->order("id ASC") as $product)
foreach($this->products->where(["closed" => 0])->order("id ASC")->page($page, 5) as $product)
yield new BugtrackerProduct($product);
}
function getCount(): ?int
{
return sizeof($this->products->where(["closed" => 0]));
}
}

View file

@ -51,12 +51,12 @@ class BugtrackerReports
yield new BugReport($report);
}
function getCountByReporter(int $reporter_id)
function getCountByReporter(int $reporter_id): ?int
{
return sizeof($this->reports->where(["deleted" => NULL, "reporter" => $reporter_id]));
}
function getSuccCountByReporter(int $reporter_id)
function getSuccCountByReporter(int $reporter_id): ?int
{
return sizeof($this->reports->where(["deleted" => NULL, "reporter" => $reporter_id, "status" => "<= 4"]));
}

View file

@ -23,29 +23,39 @@ final class BugtrackerPresenter extends OpenVKPresenter
function renderIndex(): void
{
$this->assertUserLoggedIn();
$this->template->mode = in_array($this->queryParam("act"), ["list", "show", "products", "new_product", "reporter", "new"]) ? $this->queryParam("act") : "list";
$this->template->mode = in_array($this->queryParam("act"), ["list", "products", "new_product", "reporter", "new"]) ? $this->queryParam("act") : "list";
if($this->queryParam("act") === "show")
$this->redirect("/bug" . $this->queryParam("id"));
$this->template->user = $this->user;
$this->template->page = (int) ($this->queryParam("p") ?? 1);
$this->template->all_products = $this->products->getAll();
$this->template->open_products = $this->products->getOpen();
if($this->template->mode === "reporter") {
switch ($this->template->mode) {
case 'reporter':
$this->template->reporter = (new Users)->get((int) $this->queryParam("id"));
$this->template->reporter_stats = [$this->reports->getCountByReporter((int) $this->queryParam("id")), $this->reports->getSuccCountByReporter((int) $this->queryParam("id"))];
$this->template->page = (int) ($this->queryParam("p") ?? 1);
$this->template->iterator = $this->reports->getByReporter((int) $this->queryParam("id"));
$this->template->iterator = $this->reports->getByReporter((int) $this->queryParam("id"), $this->template->page);
$this->template->count = $this->reports->getCountByReporter((int) $this->queryParam("id"));
} else {
$this->template->page = (int) ($this->queryParam("p") ?? 1);
break;
case 'products':
$this->template->count = $this->products->getCount();
$this->template->iterator = $this->products->getAll($this->template->page);
break;
default:
$this->template->count = $this->reports->getReportsCount((int) $this->queryParam("product"));
$this->template->iterator = $this->queryParam("product")
? $this->reports->getReports((int) $this->queryParam("product"), $this->template->page)
: $this->reports->getAllReports($this->template->page);
break;
}
$this->template->canAdminBugTracker = $this->user->identity->getChandlerUser()->can("admin")->model('openvk\Web\Models\Repositories\BugtrackerReports')->whichBelongsTo(NULL);
$this->template->isModerator = $this->user->identity->isBtModerator();
}
function renderView(int $id): void
@ -59,7 +69,7 @@ final class BugtrackerPresenter extends OpenVKPresenter
$this->template->reporter = $this->template->bug->getReporter();
$this->template->comments = $this->comments->getByReport($this->template->bug);
$this->template->canAdminBugTracker = $this->user->identity->getChandlerUser()->can("admin")->model('openvk\Web\Models\Repositories\BugtrackerReports')->whichBelongsTo(NULL);
$this->template->isModerator = $this->user->identity->isBtModerator();
} else {
$this->flashFail("err", tr("bug_tracker_report_not_found"));
}
@ -127,12 +137,12 @@ final class BugtrackerPresenter extends OpenVKPresenter
function createComment(?BugReport $report, string $text, string $label = "", bool $is_moder = FALSE, bool $is_hidden = FALSE, string $point_actions = NULL)
{
$moder = $this->user->identity->getChandlerUser()->can("admin")->model('openvk\Web\Models\Repositories\BugtrackerReports')->whichBelongsTo(NULL);
$moder = $this->user->identity->isBtModerator();
if (!$text && !$label)
$this->flashFail("err", tr("error"), tr("bug_tracker_empty_comment"));
if ($report->getRawStatus() == 6 && !$moder)
if (in_array($report->getRawStatus(), [5, 6]) && !$moder)
$this->flashFail("err", tr("forbidden"));
DB::i()->getContext()->table("bt_comments")->insert([
@ -142,7 +152,8 @@ final class BugtrackerPresenter extends OpenVKPresenter
"is_hidden" => $moder === $is_hidden,
"point_actions" => $point_actions,
"text" => $text,
"label" => $label
"label" => $label,
"created" => time()
]);
$this->flashFail("succ", tr("bug_tracker_success"), tr("bug_tracker_comment_sent"));
@ -192,7 +203,7 @@ final class BugtrackerPresenter extends OpenVKPresenter
$this->assertUserLoggedIn();
$this->willExecuteWriteAction();
$moder = $this->user->identity->getChandlerUser()->can("admin")->model('openvk\Web\Models\Repositories\BugtrackerReports')->whichBelongsTo(NULL);
$moder = $this->user->identity->isBtModerator();
if (!$moder)
$this->flashFail("err", tr("forbidden"));

View file

@ -60,7 +60,7 @@
<tbody>
<tr>
<td class="label"><span class="nobold">{_bug_tracker_product}:</span></td>
<td class="data"><a href="#">{$bug->getProduct()->getCanonicalName()}</a></td>
<td class="data"><a href="/bugtracker?act=products">{$bug->getProduct()->getCanonicalName()}</a></td>
</tr>
<tr>
<td class="label"><span class="nobold">{_bug_tracker_sent_by}: </span></td>
@ -77,9 +77,13 @@
<td class="data"><a href="#">{$bug->getStatus()}</a></td>
</tr>
<tr>
<td class="label"><span class="nobold">{_priority}:</span></td>
<td class="label"><span class="nobold">{_bug_tracker_priority}:</span></td>
<td class="data"><a href="#">{$bug->getPriority()}</a></td>
</tr>
<tr>
<td class="label"><span class="nobold">{_created}:</span></td>
<td class="data"><a href="#">{$bug->getCreationTime()}</a></td>
</tr>
</tbody>
</table>
</div>
@ -149,7 +153,7 @@
{elseif $mode === "products"}
<table border="0" style="font-size: 11px; width: 100%;" class="post">
<tbody>
<tr n:foreach="$all_products as $product">
<tr n:foreach="$iterator as $product">
<td width="54" >
<center>
<img src="/assets/packages/static/openvk/img/note_icon.png">
@ -157,7 +161,7 @@
</td>
<td width="92%" valign="top">
<div class="post-author" href="#">
<a href="#">
<a href="/bugtracker?product={$product->getId()}">
<b>{$product->getCanonicalName()}</b>
<span>#{$product->getId()}</span>
</a>
@ -166,13 +170,13 @@
<table id="basicInfo" class="ugc-table group_info" cellspacing="0" cellpadding="0" border="0">
<tbody>
<tr>
<td class="label"><span class="nobold">{_bug_tracker_name}:</span></td>
<td class="label"><span class="nobold">{_bug_tracker_product}:</span></td>
<td class="data">
<a href="#">{$product->getCanonicalName()}</a>
<a href="/bugtracker?product={$product->getId()}">{$product->getCanonicalName()}</a>
<b n:if="$product->isClosed()">({_bug_tracker_product_is_closed})</b>
</td>
</tr>
<tr n:if="$canAdminBugTracker">
<tr n:if="$isModerator">
<td class="label"><span class="nobold">{_bug_tracker_product_created_by}: </span></td>
<td class="data">
<a href="/bugtracker?act=reporter&id={$product->getCreator()->getId()}">{$product->getCreator()->getCanonicalName()}</a>
@ -180,7 +184,7 @@
</tr>
<tr>
<td class="label"><span class="nobold">{_bug_tracker_product_creation_date}:</span></td>
<td class="data"><a href="#">123</a></td>
<td class="data"><a href="#">{$product->getCreationTime()}</a></td>
</tr>
</tbody>
</table>
@ -189,6 +193,15 @@
</tr>
</tbody>
</table>
<div style="padding: 8px;">
{include "../components/paginator.xml", conf => (object) [
"page" => $page,
"count" => $count,
"amount" => sizeof($iterator),
"perPage" => 5,
"atBottom" => true,
]}
</div>
{elseif $mode === "new_product"}
<form method="post" action="/bugtracker/createProduct">
@ -212,7 +225,8 @@
</div>
<div class="info" style="width: 92%">
<a href="{$reporter->getURL()}" class="title">{$reporter->getCanonicalName()}</a>
<div>tr("bug_tracker_reporter_card_text", $reporter_stats[0], $reporter_stats[1])</div>
<b n:if="$reporter->isBtModerator() AND $isModerator">[Модератор]</b>
<div>{tr("bug_tracker_reporter_card_text", $reporter_stats[0], $reporter_stats[1])}</div>
</div>
</div>
<table border="0" style="font-size: 11px; width: 100%;" class="post">

View file

@ -10,6 +10,12 @@
{block content}
{if $bug AND !$bug->isDeleted()}
<div n:if="in_array($bug->getRawStatus(), [4, 6]) AND $isModerator" class="user-alert">
Этот отчёт закрыт, и пользователь не может оставлять к нему комментарии. При необходимости Вы можете изменить его статус.
</div>
<div n:if="in_array($bug->getRawStatus(), [4, 6]) AND !$isModerator" class="user-alert">
Этот отчёт закрыт, и Вы больше не можете оставлять к нему комментарии.
</div>
<h4>{$bug->getCanonicalName()}</h4>
<div class="avatar-list-item" style="padding: 8px;">
@ -20,7 +26,7 @@
</div>
<div class="info" style="width: 92%">
<a href="/bugtracker?act=reporter&id={$reporter->getId()}" class="title">{$reporter->getCanonicalName()}</a>
<div class="subtitle">{_created}: {$bug->getCreationDate()}</div>
<div class="subtitle">{_created}: {$bug->getCreationTime()}</div>
</div>
</div>
<hr color="#DAE1E8" size="1">
@ -44,11 +50,11 @@
</tr>
<tr>
<td class="label"><span class="nobold">{_status}:</span></td>
<td class="data"><a href="#" n:attr='onClick => $canAdminBugTracker ? "showBtStatusChangeDialog({$bug->getId()}, {$reporter->getCoins()}, \"{$csrfToken}\");" : false'>{$bug->getStatus()}</a></td>
<td class="data"><a href="#" n:attr='onClick => $isModerator ? "showBtStatusChangeDialog({$bug->getId()}, {$reporter->getCoins()}, \"{$csrfToken}\");" : false'>{$bug->getStatus()}</a></td>
</tr>
<tr>
<td class="label"><span class="nobold">{_bug_tracker_priority}:</span></td>
<td class="data"><a href="#" n:attr='onClick => $canAdminBugTracker ? "showBtPriorityChangeDialog({$bug->getId()}, {$reporter->getCoins()}, \"{$csrfToken}\");" : false'>{$bug->getPriority()}</a></td>
<td class="data"><a href="#" n:attr='onClick => $isModerator ? "showBtPriorityChangeDialog({$bug->getId()}, {$reporter->getCoins()}, \"{$csrfToken}\");" : false'>{$bug->getPriority()}</a></td>
</tr>
<tr>
<td class="label"><span class="nobold">{_bug_tracker_device}:</span></td>
@ -57,8 +63,8 @@
</tbody>
</table>
<hr color="#DAE1E8" size="1">
<button n:if="$canAdminBugTracker" class="button" onClick="showBtStatusChangeDialog({$bug->getId()}, {$reporter->getCoins()}, {$csrfToken})">{_bug_tracker_change_status}</button>
<button n:if="$canAdminBugTracker" class="button" onClick="showBtPriorityChangeDialog({$bug->getId()}, {$reporter->getCoins()}, {$csrfToken})">{_bug_tracker_change_priority}</button>
<button n:if="$isModerator" class="button" onClick="showBtStatusChangeDialog({$bug->getId()}, {$reporter->getCoins()}, {$csrfToken})">{_bug_tracker_change_status}</button>
<button n:if="$isModerator" class="button" onClick="showBtPriorityChangeDialog({$bug->getId()}, {$reporter->getCoins()}, {$csrfToken})">{_bug_tracker_change_priority}</button>
<a n:if="$bug->getReporter()->getId() !== $user->identity->getId()" class="button" href="/bug{$bug->getId()}/reproduce">
{_bug_tracker_reproduced}
<span n:if="$bug->getReproducedCount() > 0">({$bug->getReproducedCount()})</span>
@ -66,7 +72,7 @@
{if sizeof($comments) > 0}
<hr color="#DAE1E8" size="1">
<div n:foreach="$comments as $comment">
<div n:if="!$comment->isHidden() OR $comment->isHidden() AND $canAdminBugTracker" class="avatar-list-item" style="padding: 8px;">
<div n:if="!$comment->isHidden() OR $comment->isHidden() AND $isModerator" class="avatar-list-item" style="padding: 8px;">
<div class="avatar">
<a href="/bugtracker?act=reporter&id={$comment->getAuthor()->getId()}">
<img class="ava" src="{$comment->isModer() ? 'https://vk.com/images/support15_specagent.png' : $comment->getAuthor()->getAvatarURL()}">
@ -74,27 +80,31 @@
</div>
<div class="info" style="width: 90%;">
<a n:attr='href => $comment->isModer() ? false : "/bugtracker?act=reporter&id={$comment->getAuthor()->getId()}"' class="title">
{$comment->isModer() ? "{_bug_tracker_moderator}" : $comment->getAuthor()->getCanonicalName()}
<a n:if="$comment->isModer() AND $canAdminBugTracker" href="{$comment->getAuthor()->getURL()}">
{$comment->isModer() ? tr("bug_tracker_moderator") : $comment->getAuthor()->getCanonicalName()}
<a n:if="$comment->isModer() AND $isModerator" href="{$comment->getAuthor()->getURL()}">
(<b>{$comment->getAuthor()->getCanonicalName()}</b>)
</a>
</a>
<b n:if="$comment->isHidden() AND $canAdminBugTracker">({_bug_tracker_hidden_comment_span})</b>
<b n:if="$comment->isHidden() AND $isModerator">({_bug_tracker_hidden_comment_span})</b>
<br>
<b n:if="$comment->getLabel()" class="post-author" style="display: inline-block; border-top: 0;">{$comment->getLabel()}</b>
<div>
{$comment->getText()}
</div>
<b n:if="$canAdminBugTracker AND $comment->getBalanceChanges()">(действия с балансом: {$comment->getBalanceChanges() > 0 ? "+" : false}{$comment->getBalanceChanges()})</b>
<div n:if="$isModerator AND $comment->getBalanceChanges()">
<b>(действия с балансом: {$comment->getBalanceChanges() > 0 ? "+" : false}{$comment->getBalanceChanges()})</b>
</div>
<span class="nobold">{$comment->getCreationTime()}</span>
</div>
</div>
<hr color="#DAE1E8" size="1">
</div>
{/if}
<form n:if="$bug->getRawStatus() != 6 OR $bug->getRawStatus() == 6 AND $canAdminBugTracker" method="post" action="/bug{$bug->getId()}/addComment">
<form n:if="!in_array($bug->getRawStatus(), [4, 6]) OR in_array($bug->getRawStatus(), [4, 6]) AND $isModerator" method="post" action="/bug{$bug->getId()}/addComment">
<textarea name="text" style="width: 100%; resize: vertical;"></textarea><br />
<div style="float: right;">
<div n:if="$canAdminBugTracker" style="display: inline;">
<div n:if="$isModerator" style="display: inline;">
<input id="is_moder" type="checkbox" name="is_moder">
<label for="is_moder">{_bug_tracker_comment_as_moderator}</label>

View file

@ -33,6 +33,8 @@ routes:
handler: "Support->delete"
- url: "/bugtracker"
handler: "Bugtracker->index"
- url: "/bugs"
handler: "Bugtracker->index"
- url: "/bug{num}"
handler: "Bugtracker->view"
- url: "/bug{num}/setStatus"

View file

@ -49,7 +49,8 @@ CREATE TABLE `bt_comments` (
`is_hidden` tinyint(1) DEFAULT NULL,
`text` longtext NOT NULL,
`label` varchar(50) NOT NULL,
`point_actions` bigint(20) DEFAULT NULL
`point_actions` bigint(20) DEFAULT NULL,
`created` bigint(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE `bt_comments`

View file

@ -381,7 +381,7 @@
"my_feed" = "My Feed";
"my_feedback" = "My Feedback";
"my_settings" = "My Settings";
"bug_tracker" = "Bug-tracker";
"bug_tracker" = "Bug tracker";
"menu_login" = "Login";
"menu_registration" = "Registration";
@ -1078,7 +1078,7 @@
"bug_tracker_hidden_comment" = "Hidden comment";
"bug_tracker_report_not_found" = "The report was not found. It may have been deleted.";
"bug_tracker_status_open" = "Open";
"bug_tracker_status_under_review" = "Under review":
"bug_tracker_status_under_review" = "Under review";
"bug_tracker_status_in_progress" = "In progress";
"bug_tracker_status_fixed" = "Fixed";
"bug_tracker_status_closed" = "Closed";

View file

@ -1137,7 +1137,7 @@
"bug_tracker_hidden_comment" = "Скрытый комментарий";
"bug_tracker_report_not_found" = "Отчёт не найден. Возможно, он был удалён.";
"bug_tracker_status_open" = "Открыт";
"bug_tracker_status_under_review" = "На рассмотрении":
"bug_tracker_status_under_review" = "На рассмотрении";
"bug_tracker_status_in_progress" = "В работе";
"bug_tracker_status_fixed" = "Исправлен";
"bug_tracker_status_closed" = "Закрыт";