diff --git a/Web/Models/Entities/BugReport.php b/Web/Models/Entities/BugReport.php index 65976261..563b9baa 100644 --- a/Web/Models/Entities/BugReport.php +++ b/Web/Models/Entities/BugReport.php @@ -92,7 +92,7 @@ class BugReport extends RowModel return $this->getRecord()->reproduced; } - function getCreationDate(): DateTime + function getCreationTime(): DateTime { return new DateTime($this->getRecord()->created); } diff --git a/Web/Models/Entities/BugReportComment.php b/Web/Models/Entities/BugReportComment.php index 281cfcfc..da69a9eb 100644 --- a/Web/Models/Entities/BugReportComment.php +++ b/Web/Models/Entities/BugReportComment.php @@ -1,5 +1,6 @@ getRecord()->point_actions; } + + function getCreationTime(): DateTime + { + return new DateTime($this->getRecord()->created); + } } \ No newline at end of file diff --git a/Web/Models/Entities/BugtrackerProduct.php b/Web/Models/Entities/BugtrackerProduct.php index a89c8596..264b7f22 100644 --- a/Web/Models/Entities/BugtrackerProduct.php +++ b/Web/Models/Entities/BugtrackerProduct.php @@ -1,5 +1,6 @@ getRecord()->closed; } + + function getCreationTime(): DateTime + { + return new DateTime($this->getRecord()->created); + } } \ No newline at end of file diff --git a/Web/Models/Entities/User.php b/Web/Models/Entities/User.php index 44db0cd9..2fcc3c64 100644 --- a/Web/Models/Entities/User.php +++ b/Web/Models/Entities/User.php @@ -1017,6 +1017,11 @@ 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; } diff --git a/Web/Models/Repositories/BugtrackerProducts.php b/Web/Models/Repositories/BugtrackerProducts.php index 1803880a..0bcebd5a 100644 --- a/Web/Models/Repositories/BugtrackerProducts.php +++ b/Web/Models/Repositories/BugtrackerProducts.php @@ -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])); + } } \ No newline at end of file diff --git a/Web/Models/Repositories/BugtrackerReports.php b/Web/Models/Repositories/BugtrackerReports.php index d5465a38..0eae1a4d 100644 --- a/Web/Models/Repositories/BugtrackerReports.php +++ b/Web/Models/Repositories/BugtrackerReports.php @@ -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"])); } diff --git a/Web/Presenters/BugtrackerPresenter.php b/Web/Presenters/BugtrackerPresenter.php index 3f7501ba..627a9095 100644 --- a/Web/Presenters/BugtrackerPresenter.php +++ b/Web/Presenters/BugtrackerPresenter.php @@ -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->all_products = $this->products->getAll(); + $this->template->page = (int) ($this->queryParam("p") ?? 1); + $this->template->open_products = $this->products->getOpen(); - if($this->template->mode === "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"))]; + 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->count = $this->reports->getCountByReporter((int) $this->queryParam("id")); - } else { - $this->template->page = (int) ($this->queryParam("p") ?? 1); - $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); + $this->template->iterator = $this->reports->getByReporter((int) $this->queryParam("id"), $this->template->page); + $this->template->count = $this->reports->getCountByReporter((int) $this->queryParam("id")); + 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")); diff --git a/Web/Presenters/templates/Bugtracker/Index.xml b/Web/Presenters/templates/Bugtracker/Index.xml index e58ad6b8..9d15cb79 100644 --- a/Web/Presenters/templates/Bugtracker/Index.xml +++ b/Web/Presenters/templates/Bugtracker/Index.xml @@ -60,7 +60,7 @@ {_bug_tracker_product}: - {$bug->getProduct()->getCanonicalName()} + {$bug->getProduct()->getCanonicalName()} {_bug_tracker_sent_by}: @@ -77,9 +77,13 @@ {$bug->getStatus()} - {_priority}: + {_bug_tracker_priority}: {$bug->getPriority()} + + {_created}: + {$bug->getCreationTime()} + @@ -149,7 +153,7 @@ {elseif $mode === "products"} - +
@@ -157,7 +161,7 @@
+
+ {include "../components/paginator.xml", conf => (object) [ + "page" => $page, + "count" => $count, + "amount" => sizeof($iterator), + "perPage" => 5, + "atBottom" => true, + ]} +
{elseif $mode === "new_product"}
@@ -212,7 +225,8 @@
{$reporter->getCanonicalName()} -
tr("bug_tracker_reporter_card_text", $reporter_stats[0], $reporter_stats[1])
+ [Модератор] +
{tr("bug_tracker_reporter_card_text", $reporter_stats[0], $reporter_stats[1])}
diff --git a/Web/Presenters/templates/Bugtracker/View.xml b/Web/Presenters/templates/Bugtracker/View.xml index 6581cba2..d97dae63 100644 --- a/Web/Presenters/templates/Bugtracker/View.xml +++ b/Web/Presenters/templates/Bugtracker/View.xml @@ -10,6 +10,12 @@ {block content} {if $bug AND !$bug->isDeleted()} +
+ Этот отчёт закрыт, и пользователь не может оставлять к нему комментарии. При необходимости Вы можете изменить его статус. +
+
+ Этот отчёт закрыт, и Вы больше не можете оставлять к нему комментарии. +

{$bug->getCanonicalName()}

@@ -20,7 +26,7 @@
{$reporter->getCanonicalName()} -
{_created}: {$bug->getCreationDate()}
+
{_created}: {$bug->getCreationTime()}

@@ -44,11 +50,11 @@ - + - + @@ -57,8 +63,8 @@
{_status}:{$bug->getStatus()}{$bug->getStatus()}
{_bug_tracker_priority}:{$bug->getPriority()}{$bug->getPriority()}
{_bug_tracker_device}:

- - + + {_bug_tracker_reproduced} ({$bug->getReproducedCount()}) @@ -66,7 +72,7 @@ {if sizeof($comments) > 0}
-
+
- {$comment->isModer() ? "{_bug_tracker_moderator}" : $comment->getAuthor()->getCanonicalName()} - + {$comment->isModer() ? tr("bug_tracker_moderator") : $comment->getAuthor()->getCanonicalName()} + ({$comment->getAuthor()->getCanonicalName()}) - ({_bug_tracker_hidden_comment_span}) + ({_bug_tracker_hidden_comment_span})
{$comment->getText()}
- (действия с балансом: {$comment->getBalanceChanges() > 0 ? "+" : false}{$comment->getBalanceChanges()}) +
+ (действия с балансом: {$comment->getBalanceChanges() > 0 ? "+" : false}{$comment->getBalanceChanges()}) +
+ + {$comment->getCreationTime()}

{/if} - -
+ +
-
+
diff --git a/Web/routes.yml b/Web/routes.yml index d7c654ed..c8814ea3 100755 --- a/Web/routes.yml +++ b/Web/routes.yml @@ -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" diff --git a/install/sqls/00030-bug-tracker.sql b/install/sqls/00030-bug-tracker.sql index 3c466ff9..dbdc854f 100644 --- a/install/sqls/00030-bug-tracker.sql +++ b/install/sqls/00030-bug-tracker.sql @@ -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` diff --git a/locales/en.strings b/locales/en.strings index c0e768ea..9e7478e0 100644 --- a/locales/en.strings +++ b/locales/en.strings @@ -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"; diff --git a/locales/ru.strings b/locales/ru.strings index d377bdd6..c6ec5911 100644 --- a/locales/ru.strings +++ b/locales/ru.strings @@ -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" = "Закрыт";