OneBot: Leantime 改造版源码(BOM/Univer 表格/AI 接管/品牌替换等)
This commit is contained in:
211
app/Domain/Canvas/Controllers/BoardDialog.php
Normal file
211
app/Domain/Canvas/Controllers/BoardDialog.php
Normal file
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
namespace Leantime\Domain\Canvas\Controllers;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Leantime\Core\Auth\Permissions\RequiresPermission;
|
||||
use Leantime\Core\Controller\Controller;
|
||||
use Leantime\Core\Controller\Frontcontroller;
|
||||
use Leantime\Core\Mailer as MailerCore;
|
||||
use Leantime\Domain\Blueprints\Permissions\BlueprintsPermissions;
|
||||
use Leantime\Domain\Blueprints\Services\Blueprints as BlueprintsService;
|
||||
use Leantime\Domain\Projects\Services\Projects as ProjectService;
|
||||
use Leantime\Domain\Queue\Repositories\Queue as QueueRepository;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Handles canvas board create/edit dialog.
|
||||
*/
|
||||
class BoardDialog extends Controller
|
||||
{
|
||||
/**
|
||||
* Constant that must be redefined by subclasses.
|
||||
*/
|
||||
protected const CANVAS_NAME = '??';
|
||||
|
||||
private ProjectService $projectService;
|
||||
|
||||
private BlueprintsService $blueprintsService;
|
||||
|
||||
private object $canvasRepo;
|
||||
|
||||
/**
|
||||
* Initializes dependencies.
|
||||
*/
|
||||
public function init(ProjectService $projectService): void
|
||||
{
|
||||
$this->projectService = $projectService;
|
||||
$this->blueprintsService = app()->make(BlueprintsService::class);
|
||||
$canvasName = Str::studly(static::CANVAS_NAME).'canvas';
|
||||
$repoName = app()->getNamespace()."Domain\\$canvasName\\Repositories\\$canvasName";
|
||||
$this->canvasRepo = app()->make($repoName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the board dialog form.
|
||||
*
|
||||
* @param array $params Request parameters
|
||||
*/
|
||||
#[RequiresPermission(BlueprintsPermissions::VIEW, entityScoped: true)]
|
||||
public function get(array $params): Response
|
||||
{
|
||||
$currentCanvasId = '';
|
||||
$canvasTitle = '';
|
||||
|
||||
if (isset($params['id'])) {
|
||||
// getBoard authorizes VIEW against the board's real project; false = missing/foreign/
|
||||
// unauthorized — don't expose the title or switch the active board (no session poison).
|
||||
$singleCanvas = $this->blueprintsService->getBoard((int) $params['id'], static::CANVAS_NAME.'canvas');
|
||||
if ($singleCanvas !== false) {
|
||||
$currentCanvasId = (int) $params['id'];
|
||||
$canvasTitle = $singleCanvas[0]['title'] ?? '';
|
||||
session(['current'.strtoupper(static::CANVAS_NAME).'Canvas' => $currentCanvasId]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->assignTemplateVars($currentCanvasId, $canvasTitle);
|
||||
|
||||
if (! isset($_GET['raw'])) {
|
||||
return $this->tpl->displayPartial('canvas.boardDialog');
|
||||
}
|
||||
|
||||
return new Response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles board creation and editing.
|
||||
*
|
||||
* @param array $params Request parameters
|
||||
*/
|
||||
#[RequiresPermission(BlueprintsPermissions::EDIT, entityScoped: true)]
|
||||
public function post(array $params): Response
|
||||
{
|
||||
$currentCanvasId = '';
|
||||
$canvasTitle = '';
|
||||
|
||||
if (isset($params['id'])) {
|
||||
$singleCanvas = $this->blueprintsService->getBoard((int) $params['id'], static::CANVAS_NAME.'canvas');
|
||||
if ($singleCanvas !== false) {
|
||||
$currentCanvasId = (int) $params['id'];
|
||||
$canvasTitle = $singleCanvas[0]['title'] ?? '';
|
||||
session(['current'.strtoupper(static::CANVAS_NAME).'Canvas' => $currentCanvasId]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['newCanvas'])) {
|
||||
$result = $this->handleNewCanvas($currentCanvasId);
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['editCanvas']) && $currentCanvasId > 0) {
|
||||
$result = $this->handleEditCanvas($currentCanvasId);
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assignTemplateVars($currentCanvasId, $canvasTitle);
|
||||
|
||||
if (! isset($_GET['raw'])) {
|
||||
return $this->tpl->displayPartial('canvas.boardDialog');
|
||||
}
|
||||
|
||||
return new Response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles creating a new canvas board.
|
||||
*/
|
||||
private function handleNewCanvas(int|string &$currentCanvasId): ?Response
|
||||
{
|
||||
if (! isset($_POST['canvastitle']) || empty($_POST['canvastitle'])) {
|
||||
$this->tpl->setNotification($this->language->__('notification.please_enter_title'), 'error');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->canvasRepo->existCanvas(session('currentProject'), $_POST['canvastitle'])) {
|
||||
$this->tpl->setNotification($this->language->__('notification.board_exists'), 'error');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$values = [
|
||||
'title' => $_POST['canvastitle'],
|
||||
'author' => session('userdata.id'),
|
||||
'projectId' => session('currentProject'),
|
||||
];
|
||||
// createBoard authorizes CREATE against the target (current) project.
|
||||
$currentCanvasId = $this->blueprintsService->createBoard($values, static::CANVAS_NAME.'canvas');
|
||||
|
||||
$this->notifyBoardCreated($values['title']);
|
||||
|
||||
$this->tpl->setNotification($this->language->__('notification.board_created'), 'success', static::CANVAS_NAME.'board_created');
|
||||
session(['current'.strtoupper(static::CANVAS_NAME).'Canvas' => $currentCanvasId]);
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas/boardDialog/'.$currentCanvasId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles editing a canvas board title.
|
||||
*/
|
||||
private function handleEditCanvas(int $currentCanvasId): ?Response
|
||||
{
|
||||
if (! isset($_POST['canvastitle']) || empty($_POST['canvastitle'])) {
|
||||
$this->tpl->setNotification($this->language->__('notification.please_enter_title'), 'error');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->canvasRepo->existCanvas(session('currentProject'), $_POST['canvastitle'])) {
|
||||
$this->tpl->setNotification($this->language->__('notification.board_exists'), 'error');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// renameBoard authorizes EDIT against the board's real project.
|
||||
$this->blueprintsService->renameBoard($currentCanvasId, $_POST['canvastitle'], static::CANVAS_NAME.'canvas');
|
||||
|
||||
$this->tpl->setNotification($this->language->__('notification.board_edited'), 'success');
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas/boardDialog/'.$currentCanvasId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends board creation notifications to project users.
|
||||
*/
|
||||
private function notifyBoardCreated(string $title): void
|
||||
{
|
||||
$mailer = app()->make(MailerCore::class);
|
||||
$users = $this->projectService->getUsersToNotify(session('currentProject'));
|
||||
|
||||
$mailer->setSubject($this->language->__('notification.board_created'));
|
||||
$message = sprintf(
|
||||
$this->language->__('email_notifications.canvas_created_message'),
|
||||
session('userdata.name'),
|
||||
"<a href='".CURRENT_URL."'>".strip_tags($title).'</a>'
|
||||
);
|
||||
$mailer->setHtml($message);
|
||||
|
||||
$queue = app()->make(QueueRepository::class);
|
||||
$queue->queueMessageToUsers(
|
||||
$users,
|
||||
$message,
|
||||
$this->language->__('notification.board_created'),
|
||||
session('currentProject')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns common template variables.
|
||||
*/
|
||||
private function assignTemplateVars(int|string $currentCanvasId, string $canvasTitle): void
|
||||
{
|
||||
$this->tpl->assign('currentCanvas', $currentCanvasId);
|
||||
$this->tpl->assign('canvasName', static::CANVAS_NAME);
|
||||
$this->tpl->assign('canvasTitle', $canvasTitle);
|
||||
$this->tpl->assign('users', $this->projectService->getUsersAssignedToProject(session('currentProject')));
|
||||
}
|
||||
}
|
||||
83
app/Domain/Canvas/Controllers/DelCanvas.php
Normal file
83
app/Domain/Canvas/Controllers/DelCanvas.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Leantime\Domain\Canvas\Controllers;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Leantime\Core\Auth\Permissions\RequiresPermission;
|
||||
use Leantime\Core\Controller\Controller;
|
||||
use Leantime\Core\Controller\Frontcontroller;
|
||||
use Leantime\Domain\Blueprints\Permissions\BlueprintsPermissions;
|
||||
use Leantime\Domain\Blueprints\Services\Blueprints as BlueprintsService;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Handles deletion of a canvas board.
|
||||
*/
|
||||
class DelCanvas extends Controller
|
||||
{
|
||||
/**
|
||||
* Constant that must be redefined by subclasses.
|
||||
*/
|
||||
protected const CANVAS_NAME = '??';
|
||||
|
||||
private mixed $canvasRepo;
|
||||
|
||||
private BlueprintsService $blueprintsService;
|
||||
|
||||
/**
|
||||
* Initializes dependencies.
|
||||
*
|
||||
* Note: no `void` return type so plugin subclasses that override init()
|
||||
* without a return type (this class is the deprecated plugin shim) stay
|
||||
* signature-compatible.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->blueprintsService = app()->make(BlueprintsService::class);
|
||||
$canvasName = Str::studly(static::CANVAS_NAME).'canvas';
|
||||
$repoName = app()->getNamespace()."Domain\\$canvasName\\Repositories\\$canvasName";
|
||||
$this->canvasRepo = app()->make($repoName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the delete canvas confirmation.
|
||||
*
|
||||
* @param array $params Request parameters
|
||||
*/
|
||||
#[RequiresPermission(BlueprintsPermissions::DELETE)]
|
||||
public function get(array $params): Response
|
||||
{
|
||||
return $this->tpl->displayPartial(static::CANVAS_NAME.'canvas.delCanvas');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles canvas board deletion.
|
||||
*
|
||||
* @param array $params Request parameters
|
||||
*/
|
||||
#[RequiresPermission(BlueprintsPermissions::DELETE, entityScoped: true)]
|
||||
public function post(array $params): Response
|
||||
{
|
||||
$id = (int) ($params['id'] ?? $_GET['id'] ?? 0);
|
||||
|
||||
if (isset($_POST['del']) && $id > 0) {
|
||||
// The service resolves the board's REAL project and authorizes DELETE against it
|
||||
// (throwing for a missing/foreign board) — closing the by-id board-delete IDOR the
|
||||
// previous role-only Auth::authOrRedirect left open.
|
||||
$this->blueprintsService->deleteBoard($id, static::CANVAS_NAME.'canvas');
|
||||
|
||||
$allCanvas = $this->canvasRepo->getAllCanvas(session('currentProject'));
|
||||
session(['current'.strtoupper(static::CANVAS_NAME).'Canvas' => $allCanvas[0]['id'] ?? -1]);
|
||||
|
||||
$this->tpl->setNotification($this->language->__('notification.board_deleted'), 'success', strtoupper(static::CANVAS_NAME).'canvas_deleted');
|
||||
|
||||
if (! $allCanvas || count($allCanvas) == 0) {
|
||||
return Frontcontroller::redirect(BASE_URL.'/blueprints/showBoards');
|
||||
}
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas/showCanvas');
|
||||
}
|
||||
|
||||
return $this->tpl->displayPartial(static::CANVAS_NAME.'canvas.delCanvas');
|
||||
}
|
||||
}
|
||||
65
app/Domain/Canvas/Controllers/DelCanvasItem.php
Normal file
65
app/Domain/Canvas/Controllers/DelCanvasItem.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Leantime\Domain\Canvas\Controllers;
|
||||
|
||||
use Leantime\Core\Auth\Permissions\RequiresPermission;
|
||||
use Leantime\Core\Controller\Controller;
|
||||
use Leantime\Core\Controller\Frontcontroller;
|
||||
use Leantime\Domain\Blueprints\Permissions\BlueprintsPermissions;
|
||||
use Leantime\Domain\Blueprints\Services\Blueprints as BlueprintsService;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Handles deletion of a canvas item.
|
||||
*/
|
||||
class DelCanvasItem extends Controller
|
||||
{
|
||||
/**
|
||||
* Constant that must be redefined by subclasses.
|
||||
*/
|
||||
protected const CANVAS_NAME = '??';
|
||||
|
||||
private BlueprintsService $blueprintsService;
|
||||
|
||||
/**
|
||||
* Initializes dependencies.
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
$this->blueprintsService = app()->make(BlueprintsService::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the delete canvas item confirmation.
|
||||
*
|
||||
* @param array $params Request parameters
|
||||
*/
|
||||
#[RequiresPermission(BlueprintsPermissions::DELETE)]
|
||||
public function get(array $params): Response
|
||||
{
|
||||
return $this->tpl->displayPartial(static::CANVAS_NAME.'canvas.delCanvasItem');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles canvas item deletion.
|
||||
*
|
||||
* @param array $params Request parameters
|
||||
*/
|
||||
#[RequiresPermission(BlueprintsPermissions::DELETE, entityScoped: true)]
|
||||
public function post(array $params): Response
|
||||
{
|
||||
$id = (int) ($params['id'] ?? $_GET['id'] ?? 0);
|
||||
|
||||
if (isset($_POST['del']) && $id > 0) {
|
||||
// The service resolves the item's REAL project and authorizes DELETE against it
|
||||
// (throwing for a missing/foreign item) — closing the by-id item-delete IDOR.
|
||||
$this->blueprintsService->deleteCanvasItem($id, static::CANVAS_NAME.'canvas');
|
||||
|
||||
$this->tpl->setNotification($this->language->__('notification.element_deleted'), 'success', strtoupper(static::CANVAS_NAME).'canvasitem_deleted');
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas/showCanvas');
|
||||
}
|
||||
|
||||
return $this->tpl->displayPartial(static::CANVAS_NAME.'canvas.delCanvasItem');
|
||||
}
|
||||
}
|
||||
291
app/Domain/Canvas/Controllers/EditCanvasComment.php
Normal file
291
app/Domain/Canvas/Controllers/EditCanvasComment.php
Normal file
@@ -0,0 +1,291 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* editCanvasComment class - Generic canvas controller / Edit Comments
|
||||
*/
|
||||
|
||||
namespace Leantime\Domain\Canvas\Controllers;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Leantime\Core\Auth\Permissions\RequiresPermission;
|
||||
use Leantime\Core\Controller\Controller;
|
||||
use Leantime\Core\Controller\Frontcontroller;
|
||||
use Leantime\Domain\Blueprints\Permissions\BlueprintsPermissions;
|
||||
use Leantime\Domain\Blueprints\Services\Blueprints as BlueprintsService;
|
||||
use Leantime\Domain\Comments\Repositories\Comments as CommentRepository;
|
||||
use Leantime\Domain\Notifications\Models\Notification as NotificationModel;
|
||||
use Leantime\Domain\Projects\Services\Projects as ProjectService;
|
||||
|
||||
class EditCanvasComment extends Controller
|
||||
{
|
||||
/**
|
||||
* Constant that must be redefined
|
||||
*/
|
||||
protected const CANVAS_NAME = '??';
|
||||
|
||||
private CommentRepository $commentsRepo;
|
||||
|
||||
private ProjectService $projectService;
|
||||
|
||||
private BlueprintsService $blueprintsService;
|
||||
|
||||
private object $canvasRepo;
|
||||
|
||||
/**
|
||||
* init - initialize private variables
|
||||
*/
|
||||
public function init(
|
||||
CommentRepository $commentsRepo,
|
||||
ProjectService $projectService
|
||||
) {
|
||||
$this->commentsRepo = $commentsRepo;
|
||||
$this->projectService = $projectService;
|
||||
$this->blueprintsService = app()->make(BlueprintsService::class);
|
||||
|
||||
$canvasName = Str::studly(static::CANVAS_NAME).'canvas';
|
||||
$repoName = app()->getNamespace()."Domain\\$canvasName\\Repositories\\$canvasName";
|
||||
$this->canvasRepo = app()->make($repoName);
|
||||
}
|
||||
|
||||
/**
|
||||
* get - handle get requests
|
||||
*/
|
||||
#[RequiresPermission(BlueprintsPermissions::VIEW, entityScoped: true)]
|
||||
public function get($params)
|
||||
{
|
||||
$canvasType = static::CANVAS_NAME.'canvas';
|
||||
|
||||
$canvasTypes = $this->canvasRepo->getCanvasTypes();
|
||||
if (isset($params['id'])) {
|
||||
// Resolve + VIEW-authorize the item against its real project first.
|
||||
$canvasItem = $this->blueprintsService->getCanvasItem((int) $params['id'], $canvasType);
|
||||
if (! $canvasItem) {
|
||||
return $this->tpl->displayPartial('errors.error404');
|
||||
}
|
||||
|
||||
// Delete comment — only when it belongs to THIS gated item (module + moduleId).
|
||||
if (isset($params['delComment']) === true) {
|
||||
$commentId = (int) ($params['delComment']);
|
||||
$comment = $this->commentsRepo->getComment($commentId);
|
||||
if ($comment !== false
|
||||
&& (string) $comment['module'] === static::CANVAS_NAME.'canvasitem'
|
||||
&& (int) $comment['moduleId'] === (int) $canvasItem['id']) {
|
||||
$this->commentsRepo->deleteComment($commentId);
|
||||
$this->tpl->setNotification($this->language->__('notifications.comment_deleted'), 'success', strtoupper(static::CANVAS_NAME).'canvascomment_deleted');
|
||||
}
|
||||
}
|
||||
|
||||
$comments = $this->commentsRepo->getComments(static::CANVAS_NAME.'canvasitem', $canvasItem['id']);
|
||||
$this->tpl->assign('numComments', $this->commentsRepo->countComments(static::CANVAS_NAME.'canvasitem', $canvasItem['id']));
|
||||
} else {
|
||||
if (isset($params['type'])) {
|
||||
$type = strip_tags($params['type']);
|
||||
} else {
|
||||
$type = array_key_first($canvasTypes);
|
||||
}
|
||||
|
||||
$canvasItem = [
|
||||
'id' => '',
|
||||
'box' => $type,
|
||||
'description' => '',
|
||||
'status' => array_key_first($this->canvasRepo->getStatusLabels()),
|
||||
'relates' => array_key_first($this->canvasRepo->getRelatesLabels()),
|
||||
'assumptions' => '',
|
||||
'data' => '',
|
||||
'conclusion' => '',
|
||||
'milestoneHeadline' => '',
|
||||
'milestoneId' => '',
|
||||
];
|
||||
|
||||
$comments = [];
|
||||
}
|
||||
|
||||
$this->tpl->assign('comments', $comments);
|
||||
|
||||
$this->tpl->assign('canvasTypes', $canvasTypes);
|
||||
$this->tpl->assign('canvasItem', $canvasItem);
|
||||
|
||||
return $this->tpl->displayPartial(static::CANVAS_NAME.'canvas.canvasComment');
|
||||
}
|
||||
|
||||
/**
|
||||
* post - handle post requests
|
||||
*/
|
||||
#[RequiresPermission(BlueprintsPermissions::EDIT, entityScoped: true)]
|
||||
public function post($params)
|
||||
{
|
||||
$canvasType = static::CANVAS_NAME.'canvas';
|
||||
|
||||
if (isset($params['changeItem'])) {
|
||||
if (isset($params['itemId']) && $params['itemId'] != '') {
|
||||
if (isset($params['description']) && ! empty($params['description'])) {
|
||||
$currentCanvasId = (int) session('current'.strtoupper(static::CANVAS_NAME).'Canvas');
|
||||
|
||||
$canvasItem = [
|
||||
'box' => $params['box'],
|
||||
'author' => session('userdata.id'),
|
||||
'description' => $params['description'],
|
||||
'status' => $params['status'],
|
||||
'relates' => $params['relates'],
|
||||
'assumptions' => $params['assumptions'],
|
||||
'data' => $params['data'],
|
||||
'conclusion' => $params['conclusion'],
|
||||
'itemId' => $params['itemId'],
|
||||
'id' => $params['itemId'],
|
||||
'canvasId' => $currentCanvasId,
|
||||
'milestoneId' => $params['milestoneId'],
|
||||
'dependentMilstone' => '',
|
||||
];
|
||||
|
||||
// Resolves the item's real project from itemId and authorizes EDIT there.
|
||||
$this->blueprintsService->updateCanvasItem($canvasItem, $canvasType);
|
||||
|
||||
$comments = $this->commentsRepo->getComments(static::CANVAS_NAME.'canvasitem', $params['itemId']);
|
||||
$this->tpl->assign('numComments', $this->commentsRepo->countComments(
|
||||
static::CANVAS_NAME.'canvasitem',
|
||||
$params['itemId']
|
||||
));
|
||||
$this->tpl->assign('comments', $comments);
|
||||
|
||||
$this->tpl->setNotification($this->language->__('notifications.canvas_item_updates'), 'success', strtoupper(static::CANVAS_NAME).'canvasitem_updated');
|
||||
|
||||
$notification = app()->make(NotificationModel::class);
|
||||
$notification->url = [
|
||||
'url' => BASE_URL.'/'.static::CANVAS_NAME.'canvas'.'/editCanvasComment/'.(int) $params['itemId'],
|
||||
'text' => $this->language->__('email_notifications.canvas_item_update_cta'),
|
||||
];
|
||||
$notification->entity = $canvasItem;
|
||||
$notification->module = static::CANVAS_NAME.'canvas';
|
||||
$notification->action = 'updated';
|
||||
$notification->projectId = session('currentProject');
|
||||
$notification->subject = $this->language->__('email_notifications.canvas_board_edited');
|
||||
$notification->authorId = session('userdata.id');
|
||||
$notification->message = sprintf(
|
||||
$this->language->__('email_notifications.canvas_item_update_message'),
|
||||
session('userdata.name'),
|
||||
$canvasItem['description']
|
||||
);
|
||||
|
||||
$this->projectService->notifyProjectUsers($notification);
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas'.'/editCanvasComment/'.$params['itemId']);
|
||||
} else {
|
||||
$this->tpl->setNotification($this->language->__('notification.please_enter_element_title'), 'error');
|
||||
}
|
||||
} else {
|
||||
if (isset($_POST['description']) && ! empty($_POST['description'])) {
|
||||
$currentCanvasId = (int) session('current'.strtoupper(static::CANVAS_NAME).'Canvas');
|
||||
|
||||
$canvasItem = [
|
||||
'box' => $params['box'],
|
||||
'author' => session('userdata.id'),
|
||||
'description' => $params['description'],
|
||||
'status' => $params['status'],
|
||||
'relates' => $params['relates'],
|
||||
'assumptions' => $params['assumptions'],
|
||||
'data' => $params['data'],
|
||||
'conclusion' => $params['conclusion'],
|
||||
'canvasId' => $currentCanvasId,
|
||||
];
|
||||
|
||||
// Resolves the target board's real project from canvasId and authorizes CREATE.
|
||||
$id = $this->blueprintsService->createCanvasItem($canvasItem, $canvasType);
|
||||
|
||||
$canvasItem['id'] = $id;
|
||||
|
||||
$canvasTypes = $this->canvasRepo->getCanvasTypes();
|
||||
|
||||
$this->tpl->setNotification($canvasTypes[$params['box']].' successfully created', 'success', strtoupper(static::CANVAS_NAME).'canvasitem_created');
|
||||
|
||||
$notification = app()->make(NotificationModel::class);
|
||||
$notification->url = [
|
||||
'url' => BASE_URL.'/'.static::CANVAS_NAME.'canvas'.'/editCanvasComment/'.(int) ($params['itemId'] ?? $id),
|
||||
'text' => $this->language->__('email_notifications.canvas_item_update_cta'),
|
||||
];
|
||||
$notification->entity = $canvasItem;
|
||||
$notification->module = static::CANVAS_NAME.'canvas';
|
||||
$notification->action = 'created';
|
||||
$notification->projectId = session('currentProject');
|
||||
$notification->subject = $this->language->__('email_notifications.canvas_board_item_created');
|
||||
$notification->authorId = session('userdata.id');
|
||||
$notification->message = sprintf(
|
||||
$this->language->__('email_notifications.canvas_item_created_message'),
|
||||
session('userdata.name'),
|
||||
$canvasItem['description']
|
||||
);
|
||||
|
||||
$this->projectService->notifyProjectUsers($notification);
|
||||
|
||||
$this->tpl->setNotification($this->language->__('notification.element_created'), 'success', strtoupper(static::CANVAS_NAME).'canvasitem_created');
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas'.'/editCanvasComment/'.$id);
|
||||
} else {
|
||||
$this->tpl->setNotification($this->language->__('notification.please_enter_element_title'), 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($params['comment']) === true) {
|
||||
$itemId = (int) ($_GET['id'] ?? 0);
|
||||
|
||||
// Only allow commenting on an item the user can view in their project.
|
||||
if (! $this->blueprintsService->getCanvasItem($itemId, $canvasType)) {
|
||||
return $this->tpl->displayPartial('errors.error404');
|
||||
}
|
||||
|
||||
$values = [
|
||||
'text' => $params['text'],
|
||||
'date' => date('Y-m-d H:i:s'),
|
||||
'userId' => (session('userdata.id')),
|
||||
'moduleId' => $itemId,
|
||||
'commentParent' => ($params['father']),
|
||||
];
|
||||
|
||||
$message = $this->commentsRepo->addComment($values, static::CANVAS_NAME.'canvasitem');
|
||||
$this->tpl->setNotification($this->language->__('notifications.comment_create_success'), 'success', strtoupper(static::CANVAS_NAME).'canvasitemcomment_created');
|
||||
|
||||
$notification = app()->make(NotificationModel::class);
|
||||
$notification->url = [
|
||||
'url' => BASE_URL.'/'.static::CANVAS_NAME.'canvas'.'/editCanvasComment/'.$itemId,
|
||||
'text' => $this->language->__('email_notifications.canvas_item_update_cta'),
|
||||
];
|
||||
$notification->entity = $values;
|
||||
$notification->module = static::CANVAS_NAME.'canvas';
|
||||
$notification->action = 'commented';
|
||||
$notification->projectId = session('currentProject');
|
||||
$notification->subject = $this->language->__('email_notifications.canvas_board_comment_created');
|
||||
$notification->authorId = session('userdata.id');
|
||||
$notification->message = sprintf(
|
||||
$this->language->__('email_notifications.canvas_item__comment_created_message'),
|
||||
session('userdata.name')
|
||||
);
|
||||
|
||||
$this->projectService->notifyProjectUsers($notification);
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas'.'/editCanvasComment/'.$itemId);
|
||||
}
|
||||
|
||||
// Fallback re-display: VIEW-authorize the item; false = missing/foreign/unauthorized -> 404.
|
||||
$itemId = (int) ($_GET['id'] ?? 0);
|
||||
$canvasItem = $this->blueprintsService->getCanvasItem($itemId, $canvasType);
|
||||
if ($itemId > 0 && ! $canvasItem) {
|
||||
return $this->tpl->displayPartial('errors.error404');
|
||||
}
|
||||
|
||||
$this->tpl->assign('id', $itemId);
|
||||
$this->tpl->assign('canvasTypes', $this->canvasRepo->getCanvasTypes());
|
||||
$this->tpl->assign('canvasItem', $canvasItem ?: []);
|
||||
|
||||
return $this->tpl->displayPartial(static::CANVAS_NAME.'canvas.canvasComment');
|
||||
}
|
||||
|
||||
/**
|
||||
* put - handle put requests
|
||||
*/
|
||||
public function put($params) {}
|
||||
|
||||
/**
|
||||
* delete - handle delete requests
|
||||
*/
|
||||
public function delete($params) {}
|
||||
}
|
||||
387
app/Domain/Canvas/Controllers/EditCanvasItem.php
Normal file
387
app/Domain/Canvas/Controllers/EditCanvasItem.php
Normal file
@@ -0,0 +1,387 @@
|
||||
<?php
|
||||
|
||||
namespace Leantime\Domain\Canvas\Controllers;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Leantime\Core\Auth\Permissions\RequiresPermission;
|
||||
use Leantime\Core\Controller\Controller;
|
||||
use Leantime\Core\Controller\Frontcontroller;
|
||||
use Leantime\Core\Http\IncomingRequest;
|
||||
use Leantime\Core\Language;
|
||||
use Leantime\Core\UI\Template;
|
||||
use Leantime\Domain\Blueprints\Permissions\BlueprintsPermissions;
|
||||
use Leantime\Domain\Blueprints\Services\Blueprints as BlueprintsService;
|
||||
use Leantime\Domain\Comments\Repositories\Comments as CommentRepository;
|
||||
use Leantime\Domain\Notifications\Models\Notification as NotificationModel;
|
||||
use Leantime\Domain\Projects\Services\Projects as ProjectService;
|
||||
use Leantime\Domain\Tickets\Services\Tickets as TicketService;
|
||||
|
||||
/**
|
||||
* editCanvasItem class - Generic canvas controller / Edit Canvas Item.
|
||||
*
|
||||
* By-id canvas item access routes through the Blueprints service (scoped to this canvas type,
|
||||
* static::CANVAS_NAME.'canvas') so it is authorized against the item's real project; the
|
||||
* per-variant repo is used only for label/config reads. The base canvas type ('??canvas') has
|
||||
* no data — these controllers are reached via subclasses (e.g. Logicmodelcanvas).
|
||||
*/
|
||||
class EditCanvasItem extends Controller
|
||||
{
|
||||
/**
|
||||
* Constant that must be redefined
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected const CANVAS_NAME = '??';
|
||||
|
||||
private TicketService $ticketService;
|
||||
|
||||
private ProjectService $projectService;
|
||||
|
||||
private CommentRepository $commentsRepo;
|
||||
|
||||
private BlueprintsService $blueprintsService;
|
||||
|
||||
private object $canvasRepo;
|
||||
|
||||
/**
|
||||
* __construct - constructor
|
||||
*/
|
||||
public function __construct(
|
||||
IncomingRequest $incomingRequest,
|
||||
Template $tpl,
|
||||
Language $language
|
||||
) {
|
||||
$this->ticketService = app()->make(TicketService::class);
|
||||
$this->projectService = app()->make(ProjectService::class);
|
||||
$this->commentsRepo = app()->make(CommentRepository::class);
|
||||
$this->blueprintsService = app()->make(BlueprintsService::class);
|
||||
$canvasName = Str::studly(static::CANVAS_NAME).'canvas';
|
||||
$repoName = app()->getNamespace()."Domain\\$canvasName\\Repositories\\$canvasName";
|
||||
$this->canvasRepo = app()->make($repoName);
|
||||
|
||||
parent::__construct($incomingRequest, $tpl, $language);
|
||||
}
|
||||
|
||||
/**
|
||||
* get - handle get requests
|
||||
*/
|
||||
#[RequiresPermission(BlueprintsPermissions::VIEW, entityScoped: true)]
|
||||
public function get($params)
|
||||
{
|
||||
$canvasType = static::CANVAS_NAME.'canvas';
|
||||
$commentModule = static::CANVAS_NAME.'canvas'.'item';
|
||||
|
||||
if (isset($params['id'])) {
|
||||
// Resolve + VIEW-authorize the item against its real project BEFORE any mutation.
|
||||
$canvasItem = $this->blueprintsService->getCanvasItem((int) $params['id'], $canvasType);
|
||||
if (! $canvasItem) {
|
||||
return $this->tpl->displayPartial('errors.error404');
|
||||
}
|
||||
|
||||
// Delete comment — only when it belongs to THIS gated item (module + moduleId);
|
||||
// deleteComment() filters on the comment id alone, so the bind prevents deleting a
|
||||
// foreign item's / project's comment.
|
||||
if (isset($params['delComment'])) {
|
||||
$commentId = (int) ($params['delComment']);
|
||||
$comment = $this->commentsRepo->getComment($commentId);
|
||||
if ($comment !== false
|
||||
&& (string) $comment['module'] === $commentModule
|
||||
&& (int) $comment['moduleId'] === (int) $canvasItem['id']) {
|
||||
$this->commentsRepo->deleteComment($commentId);
|
||||
$this->tpl->setNotification($this->language->__('notifications.comment_deleted'), 'success');
|
||||
}
|
||||
}
|
||||
|
||||
// Delete milestone relationship — an EDIT, authorized by the service.
|
||||
if (isset($params['removeMilestone'])) {
|
||||
$this->blueprintsService->patchCanvasItem((int) $params['id'], ['milestoneId' => ''], $canvasType);
|
||||
$canvasItem = $this->blueprintsService->getCanvasItem((int) $params['id'], $canvasType);
|
||||
$this->tpl->setNotification($this->language->__('notifications.milestone_detached'), 'success');
|
||||
}
|
||||
|
||||
$comments = $this->commentsRepo->getComments($commentModule, $canvasItem['id']);
|
||||
$this->tpl->assign(
|
||||
'numComments',
|
||||
$this->commentsRepo->countComments($commentModule, $canvasItem['id'])
|
||||
);
|
||||
} else {
|
||||
if (isset($params['type'])) {
|
||||
$type = strip_tags($params['type']);
|
||||
} else {
|
||||
$type = array_key_first($this->canvasRepo->elementLabels);
|
||||
}
|
||||
|
||||
$canvasItem = [
|
||||
'id' => '',
|
||||
'box' => $type,
|
||||
'description' => '',
|
||||
'status' => array_key_first($this->canvasRepo->getStatusLabels()),
|
||||
'relates' => array_key_first($this->canvasRepo->getRelatesLabels()),
|
||||
'assumptions' => '',
|
||||
'data' => '',
|
||||
'conclusion' => '',
|
||||
'milestoneHeadline' => '',
|
||||
'milestoneId' => '',
|
||||
];
|
||||
|
||||
$comments = [];
|
||||
}
|
||||
|
||||
$this->tpl->assign('comments', $comments);
|
||||
|
||||
$allProjectMilestones = $this->ticketService->getAllMilestones(['sprint' => '', 'type' => 'milestone', 'currentProject' => session('currentProject')]);
|
||||
$this->tpl->assign('milestones', $allProjectMilestones);
|
||||
$this->tpl->assign('canvasItem', $canvasItem);
|
||||
$this->tpl->assign('canvasIcon', $this->canvasRepo->getIcon());
|
||||
$this->tpl->assign('relatesLabels', $this->canvasRepo->getRelatesLabels());
|
||||
$this->tpl->assign('canvasTypes', $this->canvasRepo->getCanvasTypes());
|
||||
$this->tpl->assign('statusLabels', $this->canvasRepo->getStatusLabels());
|
||||
$this->tpl->assign('dataLabels', $this->canvasRepo->getDataLabels());
|
||||
$this->tpl->assign('currentCanvas', (int) session('current'.strtoupper(static::CANVAS_NAME).'Canvas'));
|
||||
|
||||
return $this->tpl->displayPartial(static::CANVAS_NAME.'canvas'.'.canvasDialog');
|
||||
}
|
||||
|
||||
/**
|
||||
* post - handle post requests
|
||||
*/
|
||||
#[RequiresPermission(BlueprintsPermissions::EDIT, entityScoped: true)]
|
||||
public function post($params)
|
||||
{
|
||||
$canvasType = static::CANVAS_NAME.'canvas';
|
||||
|
||||
if (isset($params['changeItem'])) {
|
||||
|
||||
if (isset($params['itemId']) && ! empty($params['itemId'])) {
|
||||
if (isset($params['description']) && ! empty($params['description'])) {
|
||||
$currentCanvasId = (int) session('current'.strtoupper(static::CANVAS_NAME).'Canvas');
|
||||
|
||||
$canvasItem = [
|
||||
'box' => $params['box'],
|
||||
'author' => session('userdata.id'),
|
||||
'description' => $params['description'],
|
||||
'status' => $params['status'],
|
||||
'relates' => $params['relates'],
|
||||
'assumptions' => $params['assumptions'],
|
||||
'data' => $params['data'],
|
||||
'conclusion' => $params['conclusion'],
|
||||
'itemId' => $params['itemId'],
|
||||
'canvasId' => $currentCanvasId,
|
||||
'milestoneId' => $params['milestoneId'],
|
||||
'dependentMilstone' => '',
|
||||
'id' => $params['itemId'],
|
||||
];
|
||||
|
||||
if (isset($params['newMilestone']) && $params['newMilestone'] != '') {
|
||||
$params['headline'] = $params['newMilestone'];
|
||||
$params['tags'] = '#ccc';
|
||||
$params['editFrom'] = dtHelper()->userNow()->formatDateForUser();
|
||||
$params['editTo'] = dtHelper()->userNow()->addDays(7)->formatDateForUser();
|
||||
$params['dependentMilestone'] = '';
|
||||
$id = $this->ticketService->quickAddMilestone($params);
|
||||
|
||||
if ($id !== false) {
|
||||
$canvasItem['milestoneId'] = $id;
|
||||
}
|
||||
}
|
||||
if (isset($params['existingMilestone']) && $params['existingMilestone'] != '') {
|
||||
$canvasItem['milestoneId'] = $params['existingMilestone'];
|
||||
}
|
||||
|
||||
// Resolves the item's real project from itemId and authorizes EDIT there.
|
||||
$this->blueprintsService->updateCanvasItem($canvasItem, $canvasType);
|
||||
|
||||
$comments = $this->commentsRepo->getComments(static::CANVAS_NAME.'canvas'.'item', $params['itemId']);
|
||||
$this->tpl->assign('numComments', $this->commentsRepo->countComments(
|
||||
static::CANVAS_NAME.'canvas'.'item',
|
||||
$params['itemId']
|
||||
));
|
||||
$this->tpl->assign('comments', $comments);
|
||||
|
||||
$this->tpl->setNotification($this->language->__('notifications.canvas_item_updates'), 'success');
|
||||
|
||||
$subject = $this->language->__('email_notifications.canvas_board_edited');
|
||||
$actual_link = BASE_URL.'/'.static::CANVAS_NAME.'canvas'.'#/editCanvasItem/'.(int) $params['itemId'];
|
||||
$message = sprintf(
|
||||
$this->language->__('email_notifications.canvas_item_update_message'),
|
||||
session('userdata.name'),
|
||||
strip_tags($canvasItem['description'])
|
||||
);
|
||||
|
||||
$notification = app()->make(NotificationModel::class);
|
||||
$notification->url = [
|
||||
'url' => $actual_link,
|
||||
'text' => $this->language->__('email_notifications.canvas_item_update_cta'),
|
||||
];
|
||||
$notification->entity = $canvasItem;
|
||||
$notification->module = static::CANVAS_NAME.'canvas';
|
||||
$notification->action = 'updated';
|
||||
$notification->projectId = session('currentProject');
|
||||
$notification->subject = $subject;
|
||||
$notification->authorId = session('userdata.id');
|
||||
$notification->message = $message;
|
||||
|
||||
$this->projectService->notifyProjectUsers($notification);
|
||||
|
||||
$closeModal = '';
|
||||
if (isset($_POST['submitAction']) && $_POST['submitAction'] == 'closeModal') {
|
||||
$closeModal = '?closeModal=true';
|
||||
}
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas'.'/editCanvasItem/'.$params['itemId'].$closeModal);
|
||||
} else {
|
||||
$this->tpl->setNotification($this->language->__('notification.please_enter_title'), 'error');
|
||||
}
|
||||
} else {
|
||||
if (isset($_POST['description']) && ! empty($_POST['description'])) {
|
||||
$currentCanvasId = (int) session('current'.strtoupper(static::CANVAS_NAME).'Canvas');
|
||||
|
||||
$canvasItem = [
|
||||
'box' => $params['box'],
|
||||
'author' => session('userdata.id'),
|
||||
'description' => $params['description'],
|
||||
'status' => $params['status'],
|
||||
'relates' => $params['relates'],
|
||||
'assumptions' => $params['assumptions'],
|
||||
'data' => $params['data'],
|
||||
'conclusion' => $params['conclusion'],
|
||||
'canvasId' => $currentCanvasId,
|
||||
];
|
||||
|
||||
// Resolves the target board's real project from canvasId and authorizes CREATE.
|
||||
$id = $this->blueprintsService->createCanvasItem($canvasItem, $canvasType);
|
||||
$canvasTypes = $this->canvasRepo->getCanvasTypes();
|
||||
|
||||
$this->tpl->setNotification($canvasTypes[$params['box']]['title'].' successfully created', 'success', ''.$params['box'].'_item_created');
|
||||
|
||||
$subject = $this->language->__('email_notifications.canvas_board_item_created');
|
||||
$actual_link = BASE_URL.'/'.static::CANVAS_NAME.'canvas'.'#/editCanvasItem/'.(int) ($params['itemId'] ?? $id);
|
||||
$message = sprintf(
|
||||
$this->language->__('email_notifications.canvas_item_created_message'),
|
||||
session('userdata.name'),
|
||||
strip_tags($canvasItem['description'])
|
||||
);
|
||||
|
||||
$notification = app()->make(NotificationModel::class);
|
||||
$notification->url = [
|
||||
'url' => $actual_link,
|
||||
'text' => $this->language->__('email_notifications.canvas_item_update_cta'),
|
||||
];
|
||||
|
||||
$notification->entity = $canvasItem;
|
||||
$notification->module = static::CANVAS_NAME.'canvas';
|
||||
$notification->action = 'created';
|
||||
$notification->projectId = session('currentProject');
|
||||
$notification->subject = $subject;
|
||||
$notification->authorId = session('userdata.id');
|
||||
$notification->message = $message;
|
||||
|
||||
$this->projectService->notifyProjectUsers($notification);
|
||||
|
||||
$this->tpl->setNotification($this->language->__('notification.element_created'), 'success');
|
||||
|
||||
$closeModal = '';
|
||||
if (isset($_POST['submitAction']) && $_POST['submitAction'] == 'closeModal') {
|
||||
$closeModal = '?closeModal=true';
|
||||
}
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas'.'/editCanvasItem/'.$id.$closeModal);
|
||||
} else {
|
||||
$this->tpl->setNotification($this->language->__('notification.please_enter_title'), 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($params['comment']) && isset($params['id'])) {
|
||||
$itemId = (int) $params['id'];
|
||||
|
||||
// Only allow commenting on an item the user can view in their project.
|
||||
if (! $this->blueprintsService->getCanvasItem($itemId, $canvasType)) {
|
||||
return $this->tpl->displayPartial('errors.error404');
|
||||
}
|
||||
|
||||
$values = [
|
||||
'text' => $params['text'],
|
||||
'date' => date('Y-m-d H:i:s'),
|
||||
'userId' => (session('userdata.id')),
|
||||
'moduleId' => $itemId,
|
||||
'commentParent' => ($params['father']),
|
||||
];
|
||||
|
||||
$commentId = $this->commentsRepo->addComment($values, static::CANVAS_NAME.'canvas'.'item');
|
||||
$this->tpl->setNotification($this->language->__('notifications.comment_create_success'), 'success');
|
||||
$values['id'] = $commentId;
|
||||
|
||||
$subject = $this->language->__('email_notifications.canvas_board_comment_created');
|
||||
$actual_link = BASE_URL.'/'.static::CANVAS_NAME.'canvas'.'#/editCanvasItem/'.$itemId;
|
||||
$message = sprintf(
|
||||
$this->language->__('email_notifications.canvas_item__comment_created_message'),
|
||||
session('userdata.name')
|
||||
);
|
||||
|
||||
$notification = app()->make(NotificationModel::class);
|
||||
$notification->url = [
|
||||
'url' => $actual_link,
|
||||
'text' => $this->language->__('email_notifications.canvas_item_update_cta'),
|
||||
];
|
||||
$notification->entity = $values;
|
||||
$notification->module = static::CANVAS_NAME.'canvas';
|
||||
$notification->action = 'commented';
|
||||
$notification->projectId = session('currentProject');
|
||||
$notification->subject = $subject;
|
||||
$notification->authorId = session('userdata.id');
|
||||
$notification->message = $message;
|
||||
|
||||
$this->projectService->notifyProjectUsers($notification);
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas'.'/editCanvasItem/'.$itemId);
|
||||
}
|
||||
|
||||
$allProjectMilestones = $this->ticketService->getAllMilestones(['sprint' => '', 'type' => 'milestone', 'currentProject' => session('currentProject')]);
|
||||
$this->tpl->assign('milestones', $allProjectMilestones);
|
||||
$this->tpl->assign('canvasTypes', $this->canvasRepo->getCanvasTypes());
|
||||
$this->tpl->assign('statusLabels', $this->canvasRepo->getStatusLabels());
|
||||
$this->tpl->assign('relatesLabels', $this->canvasRepo->getRelatesLabels());
|
||||
$this->tpl->assign('dataLabels', $this->canvasRepo->getDataLabels());
|
||||
if (isset($params['id'])) {
|
||||
$canvasItemId = (int) $params['id'];
|
||||
// VIEW-authorize before re-displaying; false = missing/foreign/unauthorized -> 404.
|
||||
$canvasItem = $this->blueprintsService->getCanvasItem($canvasItemId, $canvasType);
|
||||
if (! $canvasItem) {
|
||||
return $this->tpl->displayPartial('errors.error404');
|
||||
}
|
||||
$comments = $this->commentsRepo->getComments(static::CANVAS_NAME.'canvas'.'item', $canvasItemId);
|
||||
$this->tpl->assign('canvasItem', $canvasItem);
|
||||
} else {
|
||||
$value = [
|
||||
'id' => '',
|
||||
'box' => $params['box'],
|
||||
'author' => session('userdata.id'),
|
||||
'description' => '',
|
||||
'status' => array_key_first($this->canvasRepo->getStatusLabels()),
|
||||
'relates' => array_key_first($this->canvasRepo->getRelatesLabels()),
|
||||
'assumptions' => '',
|
||||
'data' => '',
|
||||
'conclusion' => '',
|
||||
'milestoneHeadline' => '',
|
||||
'milestoneId' => '',
|
||||
];
|
||||
$comments = [];
|
||||
$this->tpl->assign('canvasItem', $value);
|
||||
}
|
||||
$this->tpl->assign('comments', $comments);
|
||||
$this->tpl->assign('currentCanvas', (int) session('current'.strtoupper(static::CANVAS_NAME).'Canvas'));
|
||||
|
||||
return $this->tpl->displayPartial(static::CANVAS_NAME.'canvas'.'.canvasDialog');
|
||||
}
|
||||
|
||||
/**
|
||||
* put - handle put requests
|
||||
*/
|
||||
public function put($params) {}
|
||||
|
||||
/**
|
||||
* delete - handle delete requests
|
||||
*/
|
||||
public function delete($params) {}
|
||||
}
|
||||
170
app/Domain/Canvas/Controllers/Export.php
Normal file
170
app/Domain/Canvas/Controllers/Export.php
Normal file
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
namespace Leantime\Domain\Canvas\Controllers;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||
use Illuminate\Support\Str;
|
||||
use Leantime\Core\Auth\Permissions\RequiresPermission;
|
||||
use Leantime\Core\Configuration\Environment as EnvironmentCore;
|
||||
use Leantime\Core\Controller\Controller;
|
||||
use Leantime\Core\Language as LanguageCore;
|
||||
use Leantime\Domain\Blueprints\Permissions\BlueprintsPermissions;
|
||||
use Leantime\Domain\Blueprints\Services\Blueprints as BlueprintsService;
|
||||
use Leantime\Domain\Projects\Services\Projects as ProjectService;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Exports a canvas board as an XML file.
|
||||
*/
|
||||
class Export extends Controller
|
||||
{
|
||||
/**
|
||||
* Constant that must be redefined by subclasses.
|
||||
*/
|
||||
protected const CANVAS_NAME = '??';
|
||||
|
||||
protected const CANVAS_TYPE = 'canvas';
|
||||
|
||||
protected EnvironmentCore $config;
|
||||
|
||||
protected LanguageCore $language;
|
||||
|
||||
protected mixed $canvasRepo;
|
||||
|
||||
protected BlueprintsService $blueprintsService;
|
||||
|
||||
protected array $canvasTypes;
|
||||
|
||||
protected array $statusLabels;
|
||||
|
||||
protected array $relatesLabels;
|
||||
|
||||
protected array $dataLabels;
|
||||
|
||||
/**
|
||||
* Initializes dependencies.
|
||||
*/
|
||||
public function init(
|
||||
EnvironmentCore $config,
|
||||
LanguageCore $language,
|
||||
): void {
|
||||
$this->config = $config;
|
||||
$this->language = $language;
|
||||
$this->blueprintsService = app()->make(BlueprintsService::class);
|
||||
|
||||
$canvasName = Str::studly(static::CANVAS_NAME).static::CANVAS_TYPE;
|
||||
$repoName = app()->getNamespace()."Domain\\$canvasName\\Repositories\\$canvasName";
|
||||
$this->canvasRepo = app()->make($repoName);
|
||||
|
||||
$this->canvasTypes = $this->canvasRepo->getCanvasTypes();
|
||||
$this->statusLabels = $this->canvasRepo->getStatusLabels();
|
||||
$this->relatesLabels = $this->canvasRepo->getRelatesLabels();
|
||||
$this->dataLabels = $this->canvasRepo->getDataLabels();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and serves an XML export of the canvas.
|
||||
*
|
||||
* @param array $params Request parameters
|
||||
*/
|
||||
#[RequiresPermission(BlueprintsPermissions::VIEW, entityScoped: true)]
|
||||
public function get(array $params): Response
|
||||
{
|
||||
$canvasId = (int) ($params['id'] ?? $_GET['id'] ?? 0);
|
||||
|
||||
if ($canvasId <= 0 && session()->exists('current'.strtoupper(static::CANVAS_NAME).'Canvas')) {
|
||||
$canvasId = (int) session('current'.strtoupper(static::CANVAS_NAME).'Canvas');
|
||||
}
|
||||
|
||||
if ($canvasId <= 0) {
|
||||
return new Response;
|
||||
}
|
||||
|
||||
$exportData = $this->export($canvasId);
|
||||
|
||||
clearstatcache();
|
||||
|
||||
$response = new Response($exportData);
|
||||
$response->headers->set('Content-type', 'application/xml');
|
||||
$response->headers->set('Content-Disposition', 'attachment; filename="'.static::CANVAS_NAME.static::CANVAS_TYPE.'-'.$canvasId.'.xml"');
|
||||
$response->headers->set('Cache-Control', 'no-cache');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates XML data for the given canvas.
|
||||
*
|
||||
* @param int $id Canvas identifier
|
||||
* @return string XML data
|
||||
*
|
||||
* @throws BindingResolutionException
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function export(int $id): string
|
||||
{
|
||||
// getBoard authorizes VIEW against the board's real project and returns false for a
|
||||
// missing/foreign/unauthorized board (export is reachable by arbitrary board id).
|
||||
$canvasAry = $this->blueprintsService->getBoard($id, static::CANVAS_NAME.static::CANVAS_TYPE);
|
||||
! empty($canvasAry) || throw new Exception("Cannot find canvas with id '$id'");
|
||||
|
||||
$projectId = $canvasAry[0]['projectId'];
|
||||
$recordsAry = $this->blueprintsService->getBoardItems($id, static::CANVAS_NAME.static::CANVAS_TYPE, static::CANVAS_NAME.'canvasitem');
|
||||
|
||||
$projectService = app()->make(ProjectService::class);
|
||||
$projectAry = $projectService->getProject($projectId);
|
||||
! empty($projectAry) || throw new Exception("Cannot retrieve project id '$projectId'");
|
||||
|
||||
$xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>'.PHP_EOL.PHP_EOL;
|
||||
$xml .= $this->xmlExport(static::CANVAS_NAME.static::CANVAS_TYPE, $canvasAry[0]['title'], $recordsAry);
|
||||
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates XML markup for canvas data.
|
||||
*
|
||||
* @param string $canvasKey Encoded canvas name
|
||||
* @param string $canvasTitle Canvas title
|
||||
* @param array $recordsAry Array of canvas entry records
|
||||
* @param int $indent Indent level to use
|
||||
* @return string XML data
|
||||
*/
|
||||
protected function xmlExport(string $canvasKey, string $canvasTitle, array $recordsAry, int $indent = 0): string
|
||||
{
|
||||
$is = str_repeat(' ', 4 * $indent);
|
||||
$tab = str_repeat(' ', 4);
|
||||
$xml = $is.'<canvas key="'.$canvasKey.'">'.PHP_EOL;
|
||||
$xml .= $is.$tab.'<title>'.$canvasTitle.'</title>'.PHP_EOL;
|
||||
$xml .= $is.$tab.'<content>'.PHP_EOL;
|
||||
|
||||
foreach ($this->canvasTypes as $key => $data) {
|
||||
$xml .= $is.$tab.$tab.'<element key="'.$key.'">'.PHP_EOL;
|
||||
|
||||
foreach ($recordsAry as $record) {
|
||||
if ($record['box'] === $key) {
|
||||
$xml .= $is.$tab.$tab.$tab.'<item>'.PHP_EOL;
|
||||
$xml .= $is.$tab.$tab.$tab.$tab.'<created>'.($record['created'] ?? '').'</created>'.PHP_EOL;
|
||||
$xml .= $is.$tab.$tab.$tab.$tab.'<modified>'.($record['modified'] ?? '').'</modified>'.PHP_EOL;
|
||||
$xml .= $is.$tab.$tab.$tab.$tab.'<author id="'.$record['author'].'" firstname="'.($record['authorFirstname'] ?? '').'" '.
|
||||
'lastname="'.($record['authorLastname'] ?? '').'"/>'.PHP_EOL;
|
||||
|
||||
$xml .= $is.$tab.$tab.$tab.$tab.'<description>'.($record['description'] ?? '').'</description>'.PHP_EOL;
|
||||
$xml .= $is.$tab.$tab.$tab.$tab.'<status key="'.($record['status'] ?? '').'" />'.PHP_EOL;
|
||||
$xml .= $is.$tab.$tab.$tab.$tab.'<relates key="'.($record['relates'] ?? '').'" />'.PHP_EOL;
|
||||
$xml .= $is.$tab.$tab.$tab.$tab.'<assumptions>'.($record['assumptions'] ?? '').'</assumptions>'.PHP_EOL;
|
||||
$xml .= $is.$tab.$tab.$tab.$tab.'<data>'.($record['data'] ?? '').'</data>'.PHP_EOL;
|
||||
$xml .= $is.$tab.$tab.$tab.$tab.'<conclusion>'.($record['conclusion'] ?? '').'</conclusion>'.PHP_EOL;
|
||||
$xml .= $is.$tab.$tab.$tab.'</item>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
$xml .= $is.$tab.$tab.'</element>'.PHP_EOL;
|
||||
}
|
||||
$xml .= $is.$tab.'</content>'.PHP_EOL;
|
||||
$xml .= $is.'</canvas>'.PHP_EOL;
|
||||
|
||||
return $xml;
|
||||
}
|
||||
}
|
||||
398
app/Domain/Canvas/Controllers/ShowCanvas.php
Normal file
398
app/Domain/Canvas/Controllers/ShowCanvas.php
Normal file
@@ -0,0 +1,398 @@
|
||||
<?php
|
||||
|
||||
namespace Leantime\Domain\Canvas\Controllers;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Leantime\Core\Auth\Permissions\RequiresPermission;
|
||||
use Leantime\Core\Controller\Controller;
|
||||
use Leantime\Core\Controller\Frontcontroller;
|
||||
use Leantime\Core\Mailer as MailerCore;
|
||||
use Leantime\Domain\Blueprints\Permissions\BlueprintsPermissions;
|
||||
use Leantime\Domain\Blueprints\Services\Blueprints as BlueprintsService;
|
||||
use Leantime\Domain\Canvas\Services\Canvas as CanvaService;
|
||||
use Leantime\Domain\Projects\Services\Projects as ProjectService;
|
||||
use Leantime\Domain\Queue\Repositories\Queue as QueueRepository;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class ShowCanvas extends Controller
|
||||
{
|
||||
/**
|
||||
* Constant that must be redefined by subclasses.
|
||||
*/
|
||||
protected const CANVAS_NAME = '??';
|
||||
|
||||
private ProjectService $projectService;
|
||||
|
||||
private BlueprintsService $blueprintsService;
|
||||
|
||||
private object $canvasRepo;
|
||||
|
||||
/**
|
||||
* Initializes dependencies.
|
||||
*/
|
||||
public function init(ProjectService $projectService): void
|
||||
{
|
||||
$this->projectService = $projectService;
|
||||
$this->blueprintsService = app()->make(BlueprintsService::class);
|
||||
$canvasName = Str::studly(static::CANVAS_NAME).'canvas';
|
||||
$repoName = app()->getNamespace()."Domain\\$canvasName\\Repositories\\$canvasName";
|
||||
$this->canvasRepo = app()->make($repoName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the canvas board view.
|
||||
*
|
||||
* @param array $params Request parameters
|
||||
*/
|
||||
#[RequiresPermission(BlueprintsPermissions::VIEW)]
|
||||
public function get(array $params): Response
|
||||
{
|
||||
$allCanvas = $this->canvasRepo->getAllCanvas(session('currentProject'));
|
||||
$currentCanvasId = $this->resolveCurrentCanvasId($allCanvas, $params);
|
||||
|
||||
if (isset($_REQUEST['searchCanvas'])) {
|
||||
$currentCanvasId = (int) $_REQUEST['searchCanvas'];
|
||||
session(['current'.strtoupper(static::CANVAS_NAME).'Canvas' => $currentCanvasId]);
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas/showCanvas/');
|
||||
}
|
||||
|
||||
$this->assignTemplateVars($currentCanvasId, $allCanvas);
|
||||
|
||||
if (! isset($_GET['raw'])) {
|
||||
return $this->tpl->display(static::CANVAS_NAME.'canvas.showCanvas');
|
||||
}
|
||||
|
||||
return new Response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles canvas mutations (create, edit, clone, merge, import).
|
||||
*
|
||||
* @param array $params Request parameters
|
||||
*/
|
||||
#[RequiresPermission(BlueprintsPermissions::EDIT)]
|
||||
public function post(array $params): Response
|
||||
{
|
||||
$allCanvas = $this->canvasRepo->getAllCanvas(session('currentProject'));
|
||||
$currentCanvasId = $this->resolveCurrentCanvasId($allCanvas, $params);
|
||||
|
||||
if (isset($_POST['newCanvas'])) {
|
||||
$result = $this->handleNewCanvas($currentCanvasId, $allCanvas);
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['editCanvas']) && $currentCanvasId > 0) {
|
||||
$result = $this->handleEditCanvas($currentCanvasId);
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['cloneCanvas']) && $currentCanvasId > 0) {
|
||||
$result = $this->handleCloneCanvas($currentCanvasId, $allCanvas);
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['mergeCanvas']) && $currentCanvasId > 0) {
|
||||
$result = $this->handleMergeCanvas($currentCanvasId);
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['importCanvas'])) {
|
||||
$result = $this->handleImportCanvas($currentCanvasId, $allCanvas);
|
||||
if ($result !== null) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
$allCanvas = $this->canvasRepo->getAllCanvas(session('currentProject'));
|
||||
$this->assignTemplateVars($currentCanvasId, $allCanvas);
|
||||
|
||||
if (! isset($_GET['raw'])) {
|
||||
return $this->tpl->display(static::CANVAS_NAME.'canvas.showCanvas');
|
||||
}
|
||||
|
||||
return new Response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the current canvas ID from session, GET params, or creates a default.
|
||||
*/
|
||||
private function resolveCurrentCanvasId(array &$allCanvas, array $params): int
|
||||
{
|
||||
$sessionKey = 'current'.strtoupper(static::CANVAS_NAME).'Canvas';
|
||||
|
||||
if (! $allCanvas) {
|
||||
$values = [
|
||||
'title' => $this->language->__('label.board'),
|
||||
'author' => session('userdata.id'),
|
||||
'projectId' => session('currentProject'),
|
||||
];
|
||||
$currentCanvasId = $this->canvasRepo->addCanvas($values);
|
||||
$allCanvas = $this->canvasRepo->getAllCanvas(session('currentProject'));
|
||||
|
||||
return $currentCanvasId;
|
||||
}
|
||||
|
||||
$currentCanvasId = -1;
|
||||
|
||||
if (session()->exists($sessionKey)) {
|
||||
$currentCanvasId = session($sessionKey);
|
||||
|
||||
$found = false;
|
||||
foreach ($allCanvas as $row) {
|
||||
if ($currentCanvasId == $row['id']) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $found) {
|
||||
$currentCanvasId = -1;
|
||||
session([$sessionKey => '']);
|
||||
}
|
||||
} else {
|
||||
session([$sessionKey => '']);
|
||||
}
|
||||
|
||||
if (session($sessionKey) == '') {
|
||||
$currentCanvasId = $allCanvas[0]['id'];
|
||||
session([$sessionKey => $currentCanvasId]);
|
||||
}
|
||||
|
||||
if (isset($params['id'])) {
|
||||
// Only honor an explicit board id that belongs to the CURRENT project's boards
|
||||
// ($allCanvas is project-scoped). A foreign/unknown id must not become the active
|
||||
// board — otherwise assignTemplateVars would read another project's items.
|
||||
$requestedId = (int) $params['id'];
|
||||
$projectBoardIds = array_map(static fn ($row) => (int) $row['id'], $allCanvas);
|
||||
if (in_array($requestedId, $projectBoardIds, true)) {
|
||||
$currentCanvasId = $requestedId;
|
||||
session([$sessionKey => $currentCanvasId]);
|
||||
}
|
||||
}
|
||||
|
||||
return $currentCanvasId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles creating a new canvas board.
|
||||
*/
|
||||
private function handleNewCanvas(int &$currentCanvasId, array &$allCanvas): ?Response
|
||||
{
|
||||
if (! isset($_POST['canvastitle']) || empty($_POST['canvastitle'])) {
|
||||
$this->tpl->setNotification($this->language->__('notification.please_enter_title'), 'error');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->canvasRepo->existCanvas(session('currentProject'), $_POST['canvastitle'])) {
|
||||
$this->tpl->setNotification($this->language->__('notification.board_exists'), 'error');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$values = [
|
||||
'title' => $_POST['canvastitle'],
|
||||
'author' => session('userdata.id'),
|
||||
'projectId' => session('currentProject'),
|
||||
];
|
||||
// createBoard authorizes CREATE against the target (current) project.
|
||||
$currentCanvasId = $this->blueprintsService->createBoard($values, static::CANVAS_NAME.'canvas');
|
||||
$allCanvas = $this->canvasRepo->getAllCanvas(session('currentProject'));
|
||||
|
||||
$this->notifyBoardCreated($values['title'], 'notification.board_created', 'email_notifications.canvas_created_message');
|
||||
|
||||
$this->tpl->setNotification($this->language->__('notification.board_created'), 'success', static::CANVAS_NAME.'board_created');
|
||||
session(['current'.strtoupper(static::CANVAS_NAME).'Canvas' => $currentCanvasId]);
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas/showCanvas/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles editing a canvas board title.
|
||||
*/
|
||||
private function handleEditCanvas(int &$currentCanvasId): ?Response
|
||||
{
|
||||
if (! isset($_POST['canvastitle']) || empty($_POST['canvastitle'])) {
|
||||
$this->tpl->setNotification($this->language->__('notification.please_enter_title'), 'error');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->canvasRepo->existCanvas(session('currentProject'), $_POST['canvastitle'])) {
|
||||
$this->tpl->setNotification($this->language->__('notification.board_exists'), 'error');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// renameBoard authorizes EDIT against the board's real project.
|
||||
$currentCanvasId = $this->blueprintsService->renameBoard($currentCanvasId, $_POST['canvastitle'], static::CANVAS_NAME.'canvas');
|
||||
|
||||
$this->tpl->setNotification($this->language->__('notification.board_edited'), 'success');
|
||||
|
||||
return $this->tpl->displayPartial('canvas.boardDialog');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles cloning a canvas board.
|
||||
*/
|
||||
private function handleCloneCanvas(int &$currentCanvasId, array &$allCanvas): ?Response
|
||||
{
|
||||
if (! isset($_POST['canvastitle']) || empty($_POST['canvastitle'])) {
|
||||
$this->tpl->setNotification($this->language->__('notification.please_enter_title'), 'error');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->canvasRepo->existCanvas(session('currentProject'), $_POST['canvastitle'])) {
|
||||
$this->tpl->setNotification($this->language->__('notification.board_exists'), 'error');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// copyBoard authorizes VIEW on the source board's project and CREATE on the target.
|
||||
$currentCanvasId = $this->blueprintsService->copyBoard(
|
||||
$currentCanvasId,
|
||||
(int) session('currentProject'),
|
||||
(int) session('userdata.id'),
|
||||
$_POST['canvastitle'],
|
||||
static::CANVAS_NAME.'canvas'
|
||||
);
|
||||
$allCanvas = $this->canvasRepo->getAllCanvas(session('currentProject'));
|
||||
|
||||
$this->tpl->setNotification($this->language->__('notification.board_copied'), 'success');
|
||||
session(['current'.strtoupper(static::CANVAS_NAME).'Canvas' => $currentCanvasId]);
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas/showCanvas/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles merging two canvas boards.
|
||||
*/
|
||||
private function handleMergeCanvas(int $currentCanvasId): ?Response
|
||||
{
|
||||
if (! isset($_POST['canvasid']) || $_POST['canvasid'] <= 0) {
|
||||
$this->tpl->setNotification($this->language->__('notification.internal_error'), 'error');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// mergeBoard authorizes EDIT on the target board's project and VIEW on the source's.
|
||||
$status = $this->blueprintsService->mergeBoard($currentCanvasId, (int) $_POST['canvasid'], static::CANVAS_NAME.'canvas');
|
||||
|
||||
if ($status) {
|
||||
$this->tpl->setNotification($this->language->__('notification.board_merged'), 'success');
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas/showCanvas/');
|
||||
}
|
||||
|
||||
$this->tpl->setNotification($this->language->__('notification.merge_error'), 'error');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles importing a canvas from an XML file.
|
||||
*/
|
||||
private function handleImportCanvas(int &$currentCanvasId, array &$allCanvas): ?Response
|
||||
{
|
||||
if (! isset($_FILES['canvasfile']) || $_FILES['canvasfile']['error'] !== 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$uploadfile = tempnam(sys_get_temp_dir(), 'leantime.').'.xml';
|
||||
|
||||
if (! move_uploaded_file($_FILES['canvasfile']['tmp_name'], $uploadfile)) {
|
||||
$this->tpl->setNotification($this->language->__('notification.board_import_failed'), 'error');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$services = app()->make(CanvaService::class);
|
||||
$importCanvasId = $services->import(
|
||||
$uploadfile,
|
||||
static::CANVAS_NAME.'canvas',
|
||||
projectId: session('currentProject'),
|
||||
authorId: session('userdata.id')
|
||||
);
|
||||
unlink($uploadfile);
|
||||
|
||||
if ($importCanvasId === false) {
|
||||
$this->tpl->setNotification($this->language->__('notification.board_import_failed'), 'error');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$currentCanvasId = $importCanvasId;
|
||||
$allCanvas = $this->canvasRepo->getAllCanvas(session('currentProject'));
|
||||
session(['current'.strtoupper(static::CANVAS_NAME).'Canvas' => $currentCanvasId]);
|
||||
|
||||
$canvas = $this->blueprintsService->getBoard($currentCanvasId, static::CANVAS_NAME.'canvas');
|
||||
$this->notifyBoardCreated(
|
||||
strip_tags($canvas !== false ? ($canvas[0]['title'] ?? '') : ''),
|
||||
'notification.board_imported',
|
||||
'email_notifications.canvas_imported_message'
|
||||
);
|
||||
|
||||
$this->tpl->setNotification($this->language->__('notification.board_imported'), 'success');
|
||||
|
||||
return Frontcontroller::redirect(BASE_URL.'/'.static::CANVAS_NAME.'canvas/showCanvas/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends board creation/import notifications to project users.
|
||||
*/
|
||||
private function notifyBoardCreated(string $title, string $subjectKey, string $messageKey): void
|
||||
{
|
||||
$mailer = app()->make(MailerCore::class);
|
||||
$users = $this->projectService->getUsersToNotify(session('currentProject'));
|
||||
|
||||
$mailer->setSubject($this->language->__($subjectKey));
|
||||
$message = sprintf(
|
||||
$this->language->__($messageKey),
|
||||
session('userdata.name'),
|
||||
"<a href='".CURRENT_URL."'>".strip_tags($title).'</a>'
|
||||
);
|
||||
$mailer->setHtml($message);
|
||||
|
||||
$queue = app()->make(QueueRepository::class);
|
||||
$queue->queueMessageToUsers(
|
||||
$users,
|
||||
$message,
|
||||
$this->language->__($subjectKey),
|
||||
session('currentProject')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns common template variables.
|
||||
*/
|
||||
private function assignTemplateVars(int $currentCanvasId, array $allCanvas): void
|
||||
{
|
||||
$filter['status'] = $_GET['filter_status'] ?? (session('filter_status') ?? 'all');
|
||||
session(['filter_status' => $filter['status']]);
|
||||
$filter['relates'] = $_GET['filter_relates'] ?? (session('filter_relates') ?? 'all');
|
||||
session(['filter_relates' => $filter['relates']]);
|
||||
|
||||
$this->tpl->assign('filter', $filter);
|
||||
$this->tpl->assign('currentCanvas', $currentCanvasId);
|
||||
$this->tpl->assign('canvasIcon', $this->canvasRepo->getIcon());
|
||||
$this->tpl->assign('canvasTypes', $this->canvasRepo->getCanvasTypes());
|
||||
$this->tpl->assign('statusLabels', $this->canvasRepo->getStatusLabels());
|
||||
$this->tpl->assign('relatesLabels', $this->canvasRepo->getRelatesLabels());
|
||||
$this->tpl->assign('dataLabels', $this->canvasRepo->getDataLabels());
|
||||
$this->tpl->assign('disclaimer', $this->canvasRepo->getDisclaimer());
|
||||
$this->tpl->assign('allCanvas', $allCanvas);
|
||||
// getBoardItems authorizes VIEW against the board's real project; [] for foreign/unknown.
|
||||
$this->tpl->assign('canvasItems', $this->blueprintsService->getBoardItems($currentCanvasId, static::CANVAS_NAME.'canvas', static::CANVAS_NAME.'canvasitem'));
|
||||
$this->tpl->assign('users', $this->projectService->getUsersAssignedToProject(session('currentProject')));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user