Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e5f4c7f68 | ||
|
|
d27ff7d574 | ||
|
|
15455f648e | ||
|
|
66bc94037d | ||
|
|
25ff60b34b | ||
|
|
c7a2e68a82 | ||
|
|
bb937a664b | ||
|
|
3d42f16c38 | ||
|
|
9d3fa5fa9d | ||
|
|
8c2b7fe548 | ||
|
|
176cbd86f0 | ||
|
|
261c43086a | ||
|
|
65098ee587 | ||
|
|
9563eae0b1 | ||
|
|
cfc388aa77 | ||
|
|
c096510b3d |
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "zendframework/zend-expressive-skeleton",
|
"name": "mtas/mtas-tv-backend",
|
||||||
"description": "Zend expressive skeleton. Begin developing PSR-15 middleware applications in seconds!",
|
"description": "MTAS-TV backend api",
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"homepage": "https://github.com/zendframework/zend-expressive-skeleton",
|
"homepage": "https://gogs.ragnarok.yvan.hu/MTAS/mtas-tv-backend",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"skeleton",
|
"skeleton",
|
||||||
@ -63,7 +63,8 @@
|
|||||||
"zendframework/zend-json": "^3.1",
|
"zendframework/zend-json": "^3.1",
|
||||||
"zendframework/zend-log": "^2.10",
|
"zendframework/zend-log": "^2.10",
|
||||||
"zendframework/zend-servicemanager": "^3.3",
|
"zendframework/zend-servicemanager": "^3.3",
|
||||||
"zendframework/zend-stdlib": "^3.1"
|
"zendframework/zend-stdlib": "^3.1",
|
||||||
|
"ext-posix": "*"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^7.0.1",
|
"phpunit/phpunit": "^7.0.1",
|
||||||
|
|||||||
16
config/autoload/cli.global.php
Executable file
16
config/autoload/cli.global.php
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'dependencies' => [
|
||||||
|
'factories' => [
|
||||||
|
App\Command\UpdatePageCachesCommand::class => App\Command\UpdatePageCachesFactory::class,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'console' => [
|
||||||
|
'commands' => [
|
||||||
|
App\Command\UpdatePageCachesCommand::class,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
28
config/autoload/local.php.dist
Normal file → Executable file
28
config/autoload/local.php.dist
Normal file → Executable file
@ -9,4 +9,32 @@
|
|||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
'app.config' => [
|
||||||
|
'jira.user' => '',
|
||||||
|
'jira.password' => '',
|
||||||
|
|
||||||
|
'url.jiraAvatar' => 'https://cc-jira.rnd.ki.sw.ericsson.se/secure/useravatar?ownerId=%s',
|
||||||
|
'url.jiraIssue' => 'https://cc-jira.rnd.ki.sw.ericsson.se/rest/api/2/issue/%s?fields=%s',
|
||||||
|
'url.jiraWatchedIssues' => 'https://cc-jira.rnd.ki.sw.ericsson.se/rest/api/2/search?jql=%s&maxResults=1000&fields=%s',
|
||||||
|
'url.jiraKanbanBoard' => 'https://cc-jira.rnd.ki.sw.ericsson.se/rest/api/2/search?jql=filter=%s&maxResults=1000&fields=%s',
|
||||||
|
'jira.filterFields' => [
|
||||||
|
'summary',
|
||||||
|
'priority',
|
||||||
|
'issuetype',
|
||||||
|
'labels',
|
||||||
|
'assignee',
|
||||||
|
'status',
|
||||||
|
'worklog',
|
||||||
|
'updated',
|
||||||
|
'fixVersions',
|
||||||
|
|
||||||
|
'customfield_11711', // epic link field
|
||||||
|
'customfield_11712', // epic name
|
||||||
|
'customfield_13662', // additional jiraAssignees
|
||||||
|
],
|
||||||
|
|
||||||
|
'http.proxy.enabled' => false,
|
||||||
|
'http.proxy.type' => CURLPROXY_SOCKS5,
|
||||||
|
'http.proxy.url' => "localhost:1080",
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
4
config/routes.php
Normal file → Executable file
4
config/routes.php
Normal file → Executable file
@ -46,6 +46,6 @@ return function (Application $app, MiddlewareFactory $factory, ContainerInterfac
|
|||||||
$app->route('/api/slide[/{id:\d+}]', App\Handler\SlideHandler::class)->setName('api.slide');
|
$app->route('/api/slide[/{id:\d+}]', App\Handler\SlideHandler::class)->setName('api.slide');
|
||||||
|
|
||||||
$app->get('/avatars/{signum}', App\Handler\AvatarHandler::class,'avatar.image');
|
$app->get('/avatars/{signum}', App\Handler\AvatarHandler::class,'avatar.image');
|
||||||
$app->get('/api/kanban[/{filterId:\d+}]', App\Handler\KanbanHandler::class,'api.team.kanban');
|
$app->get('/api/kanban/{teamId:\d+}', App\Handler\KanbanHandler::class,'api.team.kanban');
|
||||||
|
$app->get('/api/watched/{teamId:\d+}', App\Handler\WatchedHandler::class,'api.team.watched');
|
||||||
};
|
};
|
||||||
|
|||||||
79
deploy-local-build.php
Normal file
79
deploy-local-build.php
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
namespace Deployer;
|
||||||
|
require 'recipe/common.php';
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
set('ssh_type', 'native');
|
||||||
|
set('ssh_multiplexing', true);
|
||||||
|
|
||||||
|
#set('repository', 'https://gogs.ragnarok.yvan.hu/MTAS/mtas-tv-backend.git');
|
||||||
|
set('shared_files', [
|
||||||
|
'config/autoload/local.php',
|
||||||
|
'config/autoload/los-basepath.local.php',
|
||||||
|
'config/autoload/doctrine.local.php',
|
||||||
|
'data/production.db',
|
||||||
|
]);
|
||||||
|
/*
|
||||||
|
set('shared_dirs', [
|
||||||
|
'data/persistent',
|
||||||
|
]);
|
||||||
|
*/
|
||||||
|
set('writable_dirs', [
|
||||||
|
'data/cache',
|
||||||
|
'data/logs',
|
||||||
|
]);
|
||||||
|
set('keep_releases', 3);
|
||||||
|
set('default_stage', 'production');
|
||||||
|
|
||||||
|
|
||||||
|
// Servers - mtas : esekivws5222a.rnd.ki.sw.ericsson.se
|
||||||
|
host('mtas')
|
||||||
|
->stage('production')
|
||||||
|
->user('edvidan')
|
||||||
|
->forwardAgent()
|
||||||
|
->set('deploy_path', '/proj/webdocs/mtoolbox/root/mtastv-inst/backend');
|
||||||
|
|
||||||
|
|
||||||
|
task('build', function() {
|
||||||
|
run('composer install --verbose --prefer-dist --no-progress --no-interaction --no-dev --optimize-autoloader');
|
||||||
|
run('composer archive --file=release-pkg');
|
||||||
|
run('tar -czf vendor-pkg.tar.gz vendor');
|
||||||
|
})->local();
|
||||||
|
|
||||||
|
task('upload', function() {
|
||||||
|
upload('release-pkg.tar', '{{release_path}}');
|
||||||
|
upload('vendor-pkg.tar.gz', '{{release_path}}');
|
||||||
|
cd('{{release_path}}');
|
||||||
|
run('tar -xf release-pkg.tar');
|
||||||
|
run('tar -xzf vendor-pkg.tar.gz');
|
||||||
|
});
|
||||||
|
|
||||||
|
task('clean-uploaded', function() {
|
||||||
|
cd('{{release_path}}');
|
||||||
|
run('rm -f release-pkg.tar vendor-pkg.tar.gz');
|
||||||
|
});
|
||||||
|
|
||||||
|
task('restore-dev', function() {
|
||||||
|
run('composer install --verbose --no-progress --no-interaction');
|
||||||
|
})->local();
|
||||||
|
|
||||||
|
task('release', [
|
||||||
|
'deploy:lock',
|
||||||
|
'deploy:prepare',
|
||||||
|
'deploy:release',
|
||||||
|
'upload',
|
||||||
|
'clean-uploaded',
|
||||||
|
'deploy:shared',
|
||||||
|
'deploy:writable',
|
||||||
|
'deploy:symlink',
|
||||||
|
'deploy:unlock',
|
||||||
|
]);
|
||||||
|
|
||||||
|
desc('Deploy your project');
|
||||||
|
task('deploy', [
|
||||||
|
'build',
|
||||||
|
'release',
|
||||||
|
'cleanup',
|
||||||
|
'restore-dev',
|
||||||
|
'success',
|
||||||
|
]);
|
||||||
@ -23,9 +23,8 @@ set('keep_releases', 3);
|
|||||||
set('default_stage', 'production');
|
set('default_stage', 'production');
|
||||||
|
|
||||||
|
|
||||||
// Servers
|
|
||||||
host('vasgyuro.tsp')
|
host('vasgyuro.tsp')
|
||||||
->stage('production')
|
->stage('staging')
|
||||||
->user('edvidan')
|
->user('edvidan')
|
||||||
->forwardAgent()
|
->forwardAgent()
|
||||||
->set('php_service_name', 'php7.1-fpm')
|
->set('php_service_name', 'php7.1-fpm')
|
||||||
@ -37,7 +36,7 @@ task('php-fpm:reload', function () {
|
|||||||
// The user must have rights for restart service
|
// The user must have rights for restart service
|
||||||
// /etc/sudoers: username ALL=NOPASSWD:/bin/systemctl restart php-fpm.service
|
// /etc/sudoers: username ALL=NOPASSWD:/bin/systemctl restart php-fpm.service
|
||||||
run('sudo service {{php_service_name}} reload');
|
run('sudo service {{php_service_name}} reload');
|
||||||
}); //->onlyOn('alfheim');
|
});
|
||||||
after('deploy:symlink', 'php-fpm:reload');
|
after('deploy:symlink', 'php-fpm:reload');
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 675 B |
Binary file not shown.
|
Before Width: | Height: | Size: 288 B |
108
src/App/Command/UpdatePageCachesCommand.php
Executable file
108
src/App/Command/UpdatePageCachesCommand.php
Executable file
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use App\Service\JiraCollectorService;
|
||||||
|
use App\Service\TeamService;
|
||||||
|
use LosMiddleware\LosLog\StaticLogger;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
class UpdatePageCachesCommand extends Command
|
||||||
|
{
|
||||||
|
const LOCK_FILE = 'data/update-caches-cron.lock';
|
||||||
|
|
||||||
|
/** @var JiraCollectorService */
|
||||||
|
private $jiraCollectorService;
|
||||||
|
|
||||||
|
/** @var TeamService */
|
||||||
|
private $teamService;
|
||||||
|
|
||||||
|
public function __construct(JiraCollectorService $jiraCollectorService,
|
||||||
|
TeamService $teamService)
|
||||||
|
{
|
||||||
|
$this->jiraCollectorService = $jiraCollectorService;
|
||||||
|
$this->teamService = $teamService;
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the command
|
||||||
|
*/
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('cache:update')
|
||||||
|
->setDescription('Updates page-cache data for kanban pages');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param InputInterface $input
|
||||||
|
* @param OutputInterface $output
|
||||||
|
* @return int|null|void
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
if ($this->isLocked()) {
|
||||||
|
$output->writeln("Lock file exists, not starting.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->createLock();
|
||||||
|
$teams = $this->teamService->listTeams();
|
||||||
|
foreach ($teams as $team) {
|
||||||
|
if ($team->isKanbanEnabled() && null !== $team->getFilterId()) {
|
||||||
|
set_time_limit(30);
|
||||||
|
$this->jiraCollectorService->getKanbanBoard($team->getId(), true);
|
||||||
|
}
|
||||||
|
if ($team->isWatchedEnabled()) {
|
||||||
|
set_time_limit(30);
|
||||||
|
$this->jiraCollectorService->getTeamWatchedIssues($team->getId(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->releaseLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the lock file
|
||||||
|
*/
|
||||||
|
private function createLock(): void
|
||||||
|
{
|
||||||
|
file_put_contents(self::LOCK_FILE, posix_getpid());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the lock file
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function releaseLock(): bool
|
||||||
|
{
|
||||||
|
return unlink(self::LOCK_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if lock file exists, also removes stale lock
|
||||||
|
* @return bool
|
||||||
|
* @throws \LosMiddleware\LosLog\Exception\InvalidArgumentException
|
||||||
|
*/
|
||||||
|
private function isLocked(): bool
|
||||||
|
{
|
||||||
|
if (!file_exists(self::LOCK_FILE)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
StaticLogger::save("[1] LOCK file exists.");
|
||||||
|
|
||||||
|
$pid = (int)file_get_contents(self::LOCK_FILE);
|
||||||
|
if (posix_getpgid($pid)) {
|
||||||
|
StaticLogger::save("[2] PID is running");
|
||||||
|
$binPath = readlink("/proc/${pid}/exe");
|
||||||
|
$binName = basename($binPath);
|
||||||
|
return substr($binName, 0, 3) === 'php';
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticLogger::save("[2] No process found.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/App/Command/UpdatePageCachesFactory.php
Executable file
42
src/App/Command/UpdatePageCachesFactory.php
Executable file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use App\Handler\AvatarHandler;
|
||||||
|
use App\Service\JiraCollectorService;
|
||||||
|
use App\Service\TeamService;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
use Zend\Expressive\MiddlewareContainer;
|
||||||
|
use Zend\Expressive\MiddlewareFactory;
|
||||||
|
use Zend\Expressive\Router\Route;
|
||||||
|
use Zend\Expressive\Router\RouterInterface;
|
||||||
|
|
||||||
|
class UpdatePageCachesFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param ContainerInterface $container
|
||||||
|
* @return UpdatePageCachesCommand
|
||||||
|
*/
|
||||||
|
public function __invoke(ContainerInterface $container)
|
||||||
|
{
|
||||||
|
$middlewareContainer = new MiddlewareContainer($container);
|
||||||
|
$factory = new MiddlewareFactory($middlewareContainer);
|
||||||
|
$avatarHandlerMiddleware = $factory->prepare(AvatarHandler::class);
|
||||||
|
|
||||||
|
$avatarRoute = new Route(
|
||||||
|
'/avatars/{signum}',
|
||||||
|
$avatarHandlerMiddleware,
|
||||||
|
Route::HTTP_METHOD_ANY,
|
||||||
|
'avatar.image'
|
||||||
|
);
|
||||||
|
/** @var \Zend\Expressive\Router\FastRouteRouter $router */
|
||||||
|
$router = $container->get(RouterInterface::class);
|
||||||
|
$router->addRoute($avatarRoute);
|
||||||
|
|
||||||
|
$jiraCollectorService = $container->get(JiraCollectorService::class);
|
||||||
|
$teamService = $container->get(TeamService::class);
|
||||||
|
return new UpdatePageCachesCommand($jiraCollectorService, $teamService);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/App/ConfigProvider.php
Normal file → Executable file
1
src/App/ConfigProvider.php
Normal file → Executable file
@ -42,6 +42,7 @@ class ConfigProvider
|
|||||||
Handler\SlidePositionHandler::class => Handler\SlidePositionHandlerFactory::class,
|
Handler\SlidePositionHandler::class => Handler\SlidePositionHandlerFactory::class,
|
||||||
Handler\AvatarHandler::class => Handler\AvatarHandlerFactory::class,
|
Handler\AvatarHandler::class => Handler\AvatarHandlerFactory::class,
|
||||||
Handler\KanbanHandler::class =>Handler\KanbanHandlerFactory::class,
|
Handler\KanbanHandler::class =>Handler\KanbanHandlerFactory::class,
|
||||||
|
Handler\WatchedHandler::class =>Handler\WatchedHandlerFactory::class,
|
||||||
|
|
||||||
Service\TeamService::class => Service\TeamServiceFactory::class,
|
Service\TeamService::class => Service\TeamServiceFactory::class,
|
||||||
Service\SlideManager::class => Service\SlideManagerFactory::class,
|
Service\SlideManager::class => Service\SlideManagerFactory::class,
|
||||||
|
|||||||
25
src/App/Entity/KanbanBoard.php
Normal file → Executable file
25
src/App/Entity/KanbanBoard.php
Normal file → Executable file
@ -8,19 +8,13 @@ use Doctrine\Common\Collections\ArrayCollection;
|
|||||||
|
|
||||||
class KanbanBoard implements \JsonSerializable
|
class KanbanBoard implements \JsonSerializable
|
||||||
{
|
{
|
||||||
// const PRIO_TRIVIAL = 0;
|
const PRIO_MAP = [
|
||||||
// const PRIO_MINOR = 1;
|
'Trivial' => 0,
|
||||||
// const PRIO_MAJOR = 2;
|
'Minor' => 1,
|
||||||
// const PRIO_CRITICAL = 3;
|
'Major' => 2,
|
||||||
// const PRIO_BLOCKER = 4;
|
'Critical' => 3,
|
||||||
|
'Blocker' => 4,
|
||||||
// private $priorityMap = [
|
];
|
||||||
// 'Trivial' => self::PRIO_TRIVIAL,
|
|
||||||
// 'Minor' => self::PRIO_MINOR,
|
|
||||||
// 'Major' => self::PRIO_MAJOR,
|
|
||||||
// 'Critical' => self::PRIO_CRITICAL,
|
|
||||||
// 'Blocker' => self::PRIO_BLOCKER,
|
|
||||||
// ];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var KanbanEntry[]|ArrayCollection
|
* @var KanbanEntry[]|ArrayCollection
|
||||||
@ -225,7 +219,10 @@ class KanbanBoard implements \JsonSerializable
|
|||||||
private function prioSort(array $toSort): array
|
private function prioSort(array $toSort): array
|
||||||
{
|
{
|
||||||
usort($toSort, function (KanbanEntry $a, KanbanEntry $b) {
|
usort($toSort, function (KanbanEntry $a, KanbanEntry $b) {
|
||||||
return $a->getTaurusPrio() <=> $b->getTaurusPrio();
|
// if (null !== $a->getTaurusPrio()) {
|
||||||
|
return $a->getTaurusPrio() <=> $b->getTaurusPrio();
|
||||||
|
// }
|
||||||
|
// return self::PRIO_MAP[$b->getIssuePriority()] <=> self::PRIO_MAP[$a->getIssuePriority()];
|
||||||
});
|
});
|
||||||
return $toSort;
|
return $toSort;
|
||||||
}
|
}
|
||||||
|
|||||||
83
src/App/Entity/KanbanColumn.php
Normal file
83
src/App/Entity/KanbanColumn.php
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
class KanbanColumn implements \JsonSerializable
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
private $jiraStatusName = "";
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $label = "";
|
||||||
|
|
||||||
|
/** @var integer */
|
||||||
|
private $wipLimit = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getJiraStatusName(): ?string
|
||||||
|
{
|
||||||
|
return $this->jiraStatusName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $jiraStatusName
|
||||||
|
* @return KanbanColumn
|
||||||
|
*/
|
||||||
|
public function setJiraStatusName(?string $jiraStatusName): KanbanColumn
|
||||||
|
{
|
||||||
|
$this->jiraStatusName = $jiraStatusName;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLabel(): ?string
|
||||||
|
{
|
||||||
|
return $this->label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $label
|
||||||
|
* @return KanbanColumn
|
||||||
|
*/
|
||||||
|
public function setLabel(?string $label): KanbanColumn
|
||||||
|
{
|
||||||
|
$this->label = $label;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getWipLimit(): ?int
|
||||||
|
{
|
||||||
|
return $this->wipLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $wipLimit
|
||||||
|
* @return KanbanColumn
|
||||||
|
*/
|
||||||
|
public function setWipLimit(?int $wipLimit): KanbanColumn
|
||||||
|
{
|
||||||
|
$this->wipLimit = $wipLimit;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function jsonSerialize()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'jiraStatusName' => $this->getJiraStatusName(),
|
||||||
|
'label' => $this->getLabel(),
|
||||||
|
'wipLimit' => $this->getWipLimit(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/App/Entity/KanbanEntry.php
Normal file → Executable file
55
src/App/Entity/KanbanEntry.php
Normal file → Executable file
@ -29,6 +29,12 @@ class KanbanEntry implements \JsonSerializable
|
|||||||
*/
|
*/
|
||||||
private $issueType;
|
private $issueType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JIRA: link to parent is in a custom field, parent has the epic name as a custom field
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $epicName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var JiraStatus
|
* @var JiraStatus
|
||||||
*/
|
*/
|
||||||
@ -40,7 +46,6 @@ class KanbanEntry implements \JsonSerializable
|
|||||||
private $assignee;
|
private $assignee;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JIRA: customfield_10401
|
|
||||||
* @var JiraAssignee[]
|
* @var JiraAssignee[]
|
||||||
*/
|
*/
|
||||||
private $additionalAssignees;
|
private $additionalAssignees;
|
||||||
@ -66,68 +71,57 @@ class KanbanEntry implements \JsonSerializable
|
|||||||
private $fixVersions;
|
private $fixVersions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JIRA: customfield_11226
|
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
private $prio;
|
private $prio;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JIRA: customfield_11225
|
|
||||||
* @var string[]|ArrayCollection
|
* @var string[]|ArrayCollection
|
||||||
*/
|
*/
|
||||||
private $functionalAreas;
|
private $functionalAreas;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JIRA: customfield_10010
|
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $externalId;
|
private $externalId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JIRA: customfield_10850
|
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $externalLink;
|
private $externalLink;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JIRA: customfield_10840
|
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $project;
|
private $project;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JIRA: customfield_10844
|
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $mhwebStatus;
|
private $mhwebStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JIRA: customfield_10847
|
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private $mhwebHot;
|
private $mhwebHot;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JIRA: customfield_10849
|
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private $mhwebExternal = false;
|
private $mhwebExternal = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JIRA: customfield_10904
|
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $team;
|
private $team;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JIRA: customfield_11692
|
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $answerCode;
|
private $answerCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ITS OVER 9000!
|
* ITS OVER 9000!
|
||||||
* JIRA: customfield_12500
|
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
private $taurusPrio = 9001;
|
private $taurusPrio = 9001;
|
||||||
@ -228,6 +222,24 @@ class KanbanEntry implements \JsonSerializable
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getEpicName(): ?string
|
||||||
|
{
|
||||||
|
return $this->epicName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $epicName
|
||||||
|
* @return KanbanEntry
|
||||||
|
*/
|
||||||
|
public function setEpicName(?string $epicName): KanbanEntry
|
||||||
|
{
|
||||||
|
$this->epicName = $epicName;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return JiraStatus
|
* @return JiraStatus
|
||||||
*/
|
*/
|
||||||
@ -309,7 +321,7 @@ class KanbanEntry implements \JsonSerializable
|
|||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getIssuePriority(): string
|
public function getIssuePriority(): ?string
|
||||||
{
|
{
|
||||||
return $this->issuePriority;
|
return $this->issuePriority;
|
||||||
}
|
}
|
||||||
@ -318,7 +330,7 @@ class KanbanEntry implements \JsonSerializable
|
|||||||
* @param string $issuePriority
|
* @param string $issuePriority
|
||||||
* @return KanbanEntry
|
* @return KanbanEntry
|
||||||
*/
|
*/
|
||||||
public function setIssuePriority(string $issuePriority): KanbanEntry
|
public function setIssuePriority(?string $issuePriority): KanbanEntry
|
||||||
{
|
{
|
||||||
$this->issuePriority = $issuePriority;
|
$this->issuePriority = $issuePriority;
|
||||||
return $this;
|
return $this;
|
||||||
@ -327,7 +339,7 @@ class KanbanEntry implements \JsonSerializable
|
|||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getIssuePriorityIcon(): string
|
public function getIssuePriorityIcon(): ?string
|
||||||
{
|
{
|
||||||
return $this->issuePriorityIcon;
|
return $this->issuePriorityIcon;
|
||||||
}
|
}
|
||||||
@ -336,7 +348,7 @@ class KanbanEntry implements \JsonSerializable
|
|||||||
* @param string $issuePriorityIcon
|
* @param string $issuePriorityIcon
|
||||||
* @return KanbanEntry
|
* @return KanbanEntry
|
||||||
*/
|
*/
|
||||||
public function setIssuePriorityIcon(string $issuePriorityIcon): KanbanEntry
|
public function setIssuePriorityIcon(?string $issuePriorityIcon): KanbanEntry
|
||||||
{
|
{
|
||||||
$this->issuePriorityIcon = $issuePriorityIcon;
|
$this->issuePriorityIcon = $issuePriorityIcon;
|
||||||
return $this;
|
return $this;
|
||||||
@ -664,22 +676,13 @@ class KanbanEntry implements \JsonSerializable
|
|||||||
'key' => $this->getKey(),
|
'key' => $this->getKey(),
|
||||||
'summary' => $this->getSummary(),
|
'summary' => $this->getSummary(),
|
||||||
'issueType' => $this->getIssueType(),
|
'issueType' => $this->getIssueType(),
|
||||||
|
'epicName' => $this->getEpicName(),
|
||||||
'status' => $this->getStatus(),
|
'status' => $this->getStatus(),
|
||||||
'assignee' => $this->getAssignee(),
|
'assignee' => $this->getAssignee(),
|
||||||
'additionalAssignees' => $this->getAdditionalAssignees()->getValues(),
|
'additionalAssignees' => $this->getAdditionalAssignees()->getValues(),
|
||||||
'issuePriority' => $this->getIssuePriority(),
|
'issuePriority' => $this->getIssuePriority(),
|
||||||
'issuePriorityIcon' => $this->getIssuePriorityIcon(),
|
'issuePriorityIcon' => $this->getIssuePriorityIcon(),
|
||||||
'labels' => $this->getLabels(),
|
'labels' => $this->getLabels(),
|
||||||
'prio' => $this->getPrio(),
|
|
||||||
'functionalArea' => $this->getFunctionalAreas()->getValues(),
|
|
||||||
'externalId' => $this->getExternalId(),
|
|
||||||
'externalLink' => $this->getExternalLink(),
|
|
||||||
'project' => $this->getProject(),
|
|
||||||
'mhwebStatus' => $this->getMhwebStatus(),
|
|
||||||
'mhwebHot' => $this->getMhwebHot(),
|
|
||||||
'mhwebExternal' => $this->getMhwebExternal(),
|
|
||||||
'team' => $this->getTeam(),
|
|
||||||
'answerCode' => $this->getAnswerCode(),
|
|
||||||
'taurusPrio' => $this->getTaurusPrio(),
|
'taurusPrio' => $this->getTaurusPrio(),
|
||||||
'worklog' => $this->getWorklog(),
|
'worklog' => $this->getWorklog(),
|
||||||
'daysBlocked' => $this->getDaysBlocked(),
|
'daysBlocked' => $this->getDaysBlocked(),
|
||||||
|
|||||||
153
src/App/Entity/Slide.php
Normal file → Executable file
153
src/App/Entity/Slide.php
Normal file → Executable file
@ -4,6 +4,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Entity;
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Gedmo\Mapping\Annotation as Gedmo;
|
use Gedmo\Mapping\Annotation as Gedmo;
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
@ -15,6 +17,12 @@ use JsonSerializable;
|
|||||||
*/
|
*/
|
||||||
class Slide implements JsonSerializable
|
class Slide implements JsonSerializable
|
||||||
{
|
{
|
||||||
|
const TYPE_MARKDOWN = 'markdown';
|
||||||
|
const TYPE_IFRAME = 'iframe';
|
||||||
|
|
||||||
|
const VISIBILITY_PUBLIC = 'public';
|
||||||
|
const VISIBILITY_TEAM = 'team';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Id
|
* @ORM\Id
|
||||||
* @ORM\GeneratedValue(strategy="IDENTITY")
|
* @ORM\GeneratedValue(strategy="IDENTITY")
|
||||||
@ -30,18 +38,29 @@ class Slide implements JsonSerializable
|
|||||||
private $title;
|
private $title;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(targetEntity="Team", inversedBy="slides")
|
* @ORM\Column(name="type", type="string", length=50, options={"default" = "markdown"})
|
||||||
* @ORM\JoinColumn(name="team_id", referencedColumnName="id")
|
* @var string
|
||||||
* @var Team
|
|
||||||
*/
|
*/
|
||||||
private $team;
|
private $type = self::TYPE_MARKDOWN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(name="slide_data", type="text", nullable=false)
|
* @ORM\Column(name="visibility", type="string", length=50, options={"default" = "public"})
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $visibility = self::VISIBILITY_PUBLIC;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="slide_data", type="text", nullable=true)
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $slideData;
|
private $slideData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="slide_url", type="text", nullable=true)
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $slideUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(name="is_visible", type="boolean")
|
* @ORM\Column(name="is_visible", type="boolean")
|
||||||
* @var bool
|
* @var bool
|
||||||
@ -69,6 +88,17 @@ class Slide implements JsonSerializable
|
|||||||
*/
|
*/
|
||||||
private $position;
|
private $position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToMany(targetEntity="Team", inversedBy="slides", cascade={"persist", "remove"})
|
||||||
|
* @var Team[]|ArrayCollection
|
||||||
|
*/
|
||||||
|
private $teams;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->teams = new ArrayCollection();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
@ -106,20 +136,38 @@ class Slide implements JsonSerializable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Team
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getTeam(): ?Team
|
public function getType(): ?string
|
||||||
{
|
{
|
||||||
return $this->team;
|
return $this->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Team $team
|
* @param string $type
|
||||||
* @return Slide
|
* @return Slide
|
||||||
*/
|
*/
|
||||||
public function setTeam(?Team $team): Slide
|
public function setType(?string $type): Slide
|
||||||
{
|
{
|
||||||
$this->team = $team;
|
$this->type = $type;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getVisibility(): ?string
|
||||||
|
{
|
||||||
|
return $this->visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $visibility
|
||||||
|
* @return Slide
|
||||||
|
*/
|
||||||
|
public function setVisibility(?string $visibility): Slide
|
||||||
|
{
|
||||||
|
$this->visibility = $visibility;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,12 +183,30 @@ class Slide implements JsonSerializable
|
|||||||
* @param string $slideData
|
* @param string $slideData
|
||||||
* @return Slide
|
* @return Slide
|
||||||
*/
|
*/
|
||||||
public function setSlideData(string $slideData): Slide
|
public function setSlideData(?string $slideData): Slide
|
||||||
{
|
{
|
||||||
$this->slideData = $slideData;
|
$this->slideData = $slideData;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSlideUrl(): ?string
|
||||||
|
{
|
||||||
|
return $this->slideUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $slideUrl
|
||||||
|
* @return Slide
|
||||||
|
*/
|
||||||
|
public function setSlideUrl(?string $slideUrl): Slide
|
||||||
|
{
|
||||||
|
$this->slideUrl = $slideUrl;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
@ -213,6 +279,64 @@ class Slide implements JsonSerializable
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Team $team
|
||||||
|
* @return Slide
|
||||||
|
*/
|
||||||
|
public function addTeam(Team $team): Slide
|
||||||
|
{
|
||||||
|
if (!$this->teams->contains($team)) {
|
||||||
|
$this->teams->add($team);
|
||||||
|
}
|
||||||
|
//$team->addSlide($this);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Team[] $teams
|
||||||
|
* @return Slide
|
||||||
|
*/
|
||||||
|
public function addTeams($teams): Slide
|
||||||
|
{
|
||||||
|
foreach ($teams as $team) {
|
||||||
|
$this->addTeam($team);
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Team[]|Collection
|
||||||
|
*/
|
||||||
|
public function getTeams(): Collection
|
||||||
|
{
|
||||||
|
return $this->teams;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Team $team
|
||||||
|
* @return Slide
|
||||||
|
*/
|
||||||
|
public function removeTeam(Team $team): Slide
|
||||||
|
{
|
||||||
|
if ($this->teams->contains($team)) {
|
||||||
|
$this->teams->removeElement($team);
|
||||||
|
}
|
||||||
|
//$team->removeSlide($this);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Team[] $teams
|
||||||
|
* @return Slide
|
||||||
|
*/
|
||||||
|
public function removeTeams($teams): Slide
|
||||||
|
{
|
||||||
|
foreach ($teams as $team) {
|
||||||
|
$this->removeTeam($team);
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
@ -221,8 +345,11 @@ class Slide implements JsonSerializable
|
|||||||
return [
|
return [
|
||||||
'id' => $this->getId(),
|
'id' => $this->getId(),
|
||||||
'title' => $this->getTitle(),
|
'title' => $this->getTitle(),
|
||||||
'team' => $this->getTeam(),
|
'type' => $this->getType(),
|
||||||
|
'visibility' => $this->getVisibility(),
|
||||||
|
'teams' => $this->getTeams()->getValues(),
|
||||||
'slideData' => $this->getSlideData(),
|
'slideData' => $this->getSlideData(),
|
||||||
|
'slideUrl' => $this->getSlideUrl(),
|
||||||
'isVisible' => $this->isVisible(),
|
'isVisible' => $this->isVisible(),
|
||||||
'createdAt' => $this->getCreatedAt()
|
'createdAt' => $this->getCreatedAt()
|
||||||
? $this->getCreatedAt()->format("Y-m-d H:i:s")
|
? $this->getCreatedAt()->format("Y-m-d H:i:s")
|
||||||
|
|||||||
334
src/App/Entity/Team.php
Normal file → Executable file
334
src/App/Entity/Team.php
Normal file → Executable file
@ -37,21 +37,97 @@ class Team implements JsonSerializable
|
|||||||
private $members;
|
private $members;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(
|
* @ORM\Column(name="labels", type="json", nullable=true)
|
||||||
* targetEntity="Slide",
|
* @var array
|
||||||
* mappedBy="team",
|
*/
|
||||||
* cascade={"persist", "remove"},
|
private $labels;
|
||||||
* orphanRemoval=true
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToMany(targetEntity="Slide", mappedBy="teams", cascade={"persist", "remove"})
|
||||||
|
* @ORM\JoinTable(
|
||||||
|
* name="team_slides",
|
||||||
|
* joinColumns={
|
||||||
|
* @ORM\JoinColumn(name="team_id", referencedColumnName="id")
|
||||||
|
* },
|
||||||
|
* inverseJoinColumns={
|
||||||
|
* @ORM\JoinColumn(name="slide_id", referencedColumnName="id")
|
||||||
|
* }
|
||||||
* )
|
* )
|
||||||
* @var Slide[]|Collection
|
* @var Slide[]|Collection
|
||||||
*/
|
*/
|
||||||
private $slides;
|
private $slides;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="kanban_enabled", type="boolean", options={"default" = true})
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $kanbanEnabled = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="commit_tracker_enabled", type="boolean", options={"default" = true})
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $commitTrackerEnabled = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="watched_enabled", type="boolean", options={"default" = true})
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $watchedEnabled = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="filter_id", type="integer", nullable=true)
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $filterId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="daily_lock_enabled", type="boolean", options={"default" = false})
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $dailyLockEnabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="daily_start_time", type="time_immutable", nullable=true)
|
||||||
|
* @var \DateTimeImmutable
|
||||||
|
*/
|
||||||
|
private $dailyStartTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="daily_end_time", type="time_immutable", nullable=true)
|
||||||
|
* @var \DateTimeImmutable
|
||||||
|
*/
|
||||||
|
private $dailyEndTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="backlog_column", type="json", nullable=true)
|
||||||
|
* @var KanbanColumn
|
||||||
|
*/
|
||||||
|
private $backlogColumn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="inprogress_column", type="json", nullable=true)
|
||||||
|
* @var KanbanColumn
|
||||||
|
*/
|
||||||
|
private $inprogressColumn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="verification_column", type="json", nullable=true)
|
||||||
|
* @var KanbanColumn
|
||||||
|
*/
|
||||||
|
private $verificationColumn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(name="done_column", type="json", nullable=true)
|
||||||
|
* @var KanbanColumn
|
||||||
|
*/
|
||||||
|
private $doneColumn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(name="is_active", type="boolean")
|
* @ORM\Column(name="is_active", type="boolean")
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
private $isActive;
|
private $isActive = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(name="created_at", type="datetime_immutable", nullable=true)
|
* @ORM\Column(name="created_at", type="datetime_immutable", nullable=true)
|
||||||
@ -69,8 +145,14 @@ class Team implements JsonSerializable
|
|||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->slides = new ArrayCollection;
|
|
||||||
$this->members = new \ArrayObject;
|
$this->members = new \ArrayObject;
|
||||||
|
$this->labels = new \ArrayObject;
|
||||||
|
$this->slides = new ArrayCollection;
|
||||||
|
|
||||||
|
$this->backlogColumn = new KanbanColumn();
|
||||||
|
$this->inprogressColumn = new KanbanColumn();
|
||||||
|
$this->verificationColumn = new KanbanColumn();
|
||||||
|
$this->doneColumn = new KanbanColumn();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -127,15 +209,34 @@ class Team implements JsonSerializable
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getLabels()
|
||||||
|
{
|
||||||
|
return $this->labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $labels
|
||||||
|
* @return Team
|
||||||
|
*/
|
||||||
|
public function setLabels(array $labels): Team
|
||||||
|
{
|
||||||
|
$this->labels = $labels;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Slide $slide
|
* @param Slide $slide
|
||||||
* @return Team
|
* @return Team
|
||||||
*/
|
*/
|
||||||
public function addSlides(Slide $slide): Team
|
public function addSlide(Slide $slide): Team
|
||||||
{
|
{
|
||||||
if (!$this->slides->contains($slide)) {
|
if (!$this->slides->contains($slide)) {
|
||||||
$this->slides->removeElement($slide);
|
$this->slides->removeElement($slide);
|
||||||
}
|
}
|
||||||
|
//$slide->addTeam($this);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +257,205 @@ class Team implements JsonSerializable
|
|||||||
if ($this->slides->contains($slide)) {
|
if ($this->slides->contains($slide)) {
|
||||||
$this->slides->removeElement($slide);
|
$this->slides->removeElement($slide);
|
||||||
}
|
}
|
||||||
|
//$slide->removeTeam($this);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isKanbanEnabled(): bool
|
||||||
|
{
|
||||||
|
return $this->kanbanEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $kanbanEnabled
|
||||||
|
* @return Team
|
||||||
|
*/
|
||||||
|
public function setKanbanEnabled(bool $kanbanEnabled): Team
|
||||||
|
{
|
||||||
|
$this->kanbanEnabled = $kanbanEnabled;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isCommitTrackerEnabled(): bool
|
||||||
|
{
|
||||||
|
return $this->commitTrackerEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $commitTrackerEnabled
|
||||||
|
* @return Team
|
||||||
|
*/
|
||||||
|
public function setCommitTrackerEnabled(bool $commitTrackerEnabled): Team
|
||||||
|
{
|
||||||
|
$this->commitTrackerEnabled = $commitTrackerEnabled;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isWatchedEnabled(): bool
|
||||||
|
{
|
||||||
|
return $this->watchedEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $watchedEnabled
|
||||||
|
* @return Team
|
||||||
|
*/
|
||||||
|
public function setWatchedEnabled(bool $watchedEnabled): Team
|
||||||
|
{
|
||||||
|
$this->watchedEnabled = $watchedEnabled;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getFilterId(): ?int
|
||||||
|
{
|
||||||
|
return $this->filterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $filterId
|
||||||
|
* @return Team
|
||||||
|
*/
|
||||||
|
public function setFilterId(?int $filterId): Team
|
||||||
|
{
|
||||||
|
$this->filterId = $filterId;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDailyLockEnabled(): bool
|
||||||
|
{
|
||||||
|
return $this->dailyLockEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $dailyLockEnabled
|
||||||
|
* @return Team
|
||||||
|
*/
|
||||||
|
public function setDailyLockEnabled(bool $dailyLockEnabled): Team
|
||||||
|
{
|
||||||
|
$this->dailyLockEnabled = $dailyLockEnabled;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \DateTimeImmutable
|
||||||
|
*/
|
||||||
|
public function getDailyStartTime(): ?\DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->dailyStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \DateTimeInterface $dailyStartTime
|
||||||
|
* @return Team
|
||||||
|
*/
|
||||||
|
public function setDailyStartTime(?\DateTimeInterface $dailyStartTime): Team
|
||||||
|
{
|
||||||
|
$this->dailyStartTime = $dailyStartTime;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \DateTimeImmutable
|
||||||
|
*/
|
||||||
|
public function getDailyEndTime(): ?\DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->dailyEndTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \DateTimeInterface $dailyEndTime
|
||||||
|
* @return Team
|
||||||
|
*/
|
||||||
|
public function setDailyEndTime(?\DateTimeInterface $dailyEndTime): Team
|
||||||
|
{
|
||||||
|
$this->dailyEndTime = $dailyEndTime;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|KanbanColumn
|
||||||
|
*/
|
||||||
|
public function getBacklogColumn()
|
||||||
|
{
|
||||||
|
return $this->backlogColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $backlogColumn
|
||||||
|
* @return Team
|
||||||
|
*/
|
||||||
|
public function setBacklogColumn(?array $backlogColumn): Team
|
||||||
|
{
|
||||||
|
$this->backlogColumn = $backlogColumn;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|KanbanColumn
|
||||||
|
*/
|
||||||
|
public function getInprogressColumn()
|
||||||
|
{
|
||||||
|
return $this->inprogressColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $inprogressColumn
|
||||||
|
* @return Team
|
||||||
|
*/
|
||||||
|
public function setInprogressColumn(array $inprogressColumn): Team
|
||||||
|
{
|
||||||
|
$this->inprogressColumn = $inprogressColumn;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|KanbanColumn
|
||||||
|
*/
|
||||||
|
public function getVerificationColumn()
|
||||||
|
{
|
||||||
|
return $this->verificationColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $verificationColumn
|
||||||
|
* @return Team
|
||||||
|
*/
|
||||||
|
public function setVerificationColumn(?array $verificationColumn): Team
|
||||||
|
{
|
||||||
|
$this->verificationColumn = $verificationColumn;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|KanbanColumn
|
||||||
|
*/
|
||||||
|
public function getDoneColumn()
|
||||||
|
{
|
||||||
|
return $this->doneColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $doneColumn
|
||||||
|
* @return Team
|
||||||
|
*/
|
||||||
|
public function setDoneColumn(?array $doneColumn): Team
|
||||||
|
{
|
||||||
|
$this->doneColumn = $doneColumn;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +521,23 @@ class Team implements JsonSerializable
|
|||||||
return [
|
return [
|
||||||
'id' => $this->getId(),
|
'id' => $this->getId(),
|
||||||
'name' => $this->getName(),
|
'name' => $this->getName(),
|
||||||
'members' => $this->getMembers(),
|
'members' => $this->getMembers() ?? [],
|
||||||
|
'labels' => $this->getLabels() ?? [],
|
||||||
|
'kanbanEnabled' => $this->isKanbanEnabled(),
|
||||||
|
'commitTrackerEnabled' => $this->isCommitTrackerEnabled(),
|
||||||
|
'watchedEnabled' => $this->isWatchedEnabled(),
|
||||||
|
'filterId' => $this->getFilterId(),
|
||||||
|
'dailyLockEnabled' => $this->isDailyLockEnabled(),
|
||||||
|
'dailyStartTime' => $this->getDailyStartTime()
|
||||||
|
? $this->getDailyStartTime()->format("H:i")
|
||||||
|
: null,
|
||||||
|
'dailyEndTime' => $this->getDailyEndTime()
|
||||||
|
? $this->getDailyEndTime()->format("H:i")
|
||||||
|
: null,
|
||||||
|
'backlogColumn' => $this->getBacklogColumn() ?? new KanbanColumn(),
|
||||||
|
'inprogressColumn' => $this->getInprogressColumn() ?? new KanbanColumn(),
|
||||||
|
'verificationColumn' => $this->getVerificationColumn() ?? new KanbanColumn(),
|
||||||
|
'doneColumn' => $this->getDoneColumn() ?? new KanbanColumn(),
|
||||||
'isActive' => $this->isActive(),
|
'isActive' => $this->isActive(),
|
||||||
'createdAt' => $this->getCreatedAt()
|
'createdAt' => $this->getCreatedAt()
|
||||||
? $this->getCreatedAt()->format("Y-m-d H:i:s")
|
? $this->getCreatedAt()->format("Y-m-d H:i:s")
|
||||||
|
|||||||
105
src/App/Entity/WatchedIssue.php
Executable file
105
src/App/Entity/WatchedIssue.php
Executable file
@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
class WatchedIssue implements \JsonSerializable
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
private $issue;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $summary;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $assignee;
|
||||||
|
|
||||||
|
/** @var WatchedIssueComment */
|
||||||
|
private $comment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getIssue(): ?string
|
||||||
|
{
|
||||||
|
return $this->issue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $issue
|
||||||
|
* @return WatchedIssue
|
||||||
|
*/
|
||||||
|
public function setIssue(string $issue): WatchedIssue
|
||||||
|
{
|
||||||
|
$this->issue = $issue;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSummary(): ?string
|
||||||
|
{
|
||||||
|
return $this->summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $summary
|
||||||
|
* @return WatchedIssue
|
||||||
|
*/
|
||||||
|
public function setSummary(string $summary): WatchedIssue
|
||||||
|
{
|
||||||
|
$this->summary = $summary;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getAssignee(): ?string
|
||||||
|
{
|
||||||
|
return $this->assignee;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $assignee
|
||||||
|
* @return WatchedIssue
|
||||||
|
*/
|
||||||
|
public function setAssignee(?string $assignee): WatchedIssue
|
||||||
|
{
|
||||||
|
$this->assignee = $assignee;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return WatchedIssueComment
|
||||||
|
*/
|
||||||
|
public function getComment(): ?WatchedIssueComment
|
||||||
|
{
|
||||||
|
return $this->comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param WatchedIssueComment $comment
|
||||||
|
* @return WatchedIssue
|
||||||
|
*/
|
||||||
|
public function setComment(?WatchedIssueComment $comment): WatchedIssue
|
||||||
|
{
|
||||||
|
$this->comment = $comment;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function jsonSerialize()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'issue' => $this->getIssue(),
|
||||||
|
'summary' => $this->getSummary(),
|
||||||
|
'assignee' => $this->getAssignee(),
|
||||||
|
'comment' => $this->getComment() ?? new WatchedIssueComment(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
105
src/App/Entity/WatchedIssueComment.php
Executable file
105
src/App/Entity/WatchedIssueComment.php
Executable file
@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
class WatchedIssueComment implements \JsonSerializable
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
private $signum;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $name;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $content;
|
||||||
|
|
||||||
|
/** @var \DateTimeImmutable */
|
||||||
|
private $date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSignum(): ?string
|
||||||
|
{
|
||||||
|
return $this->signum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $signum
|
||||||
|
* @return WatchedIssueComment
|
||||||
|
*/
|
||||||
|
public function setSignum(string $signum): WatchedIssueComment
|
||||||
|
{
|
||||||
|
$this->signum = $signum;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getName(): ?string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
* @return WatchedIssueComment
|
||||||
|
*/
|
||||||
|
public function setName(string $name): WatchedIssueComment
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getContent(): ?string
|
||||||
|
{
|
||||||
|
return $this->content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $content
|
||||||
|
* @return WatchedIssueComment
|
||||||
|
*/
|
||||||
|
public function setContent(string $content): WatchedIssueComment
|
||||||
|
{
|
||||||
|
$this->content = $content;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \DateTimeImmutable
|
||||||
|
*/
|
||||||
|
public function getDate(): ?\DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \DateTimeImmutable $date
|
||||||
|
* @return WatchedIssueComment
|
||||||
|
*/
|
||||||
|
public function setDate(\DateTimeImmutable $date): WatchedIssueComment
|
||||||
|
{
|
||||||
|
$this->date = $date;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function jsonSerialize()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'signum' => $this->getSignum(),
|
||||||
|
'name' => $this->getName(),
|
||||||
|
'content' => $this->getContent(),
|
||||||
|
'date' => $this->getDate() ? $this->getDate()->format("Y-m-d H:i:s") : null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/App/Form/Slide.php
Normal file → Executable file
53
src/App/Form/Slide.php
Normal file → Executable file
@ -30,9 +30,34 @@ class Slide
|
|||||||
*/
|
*/
|
||||||
private $title;
|
private $title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
* @Annotation\Required(true)
|
||||||
|
* @Annotation\InputFilter("Zend\Filter\StringTrim")
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "Slide type"
|
||||||
|
* })
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
* @Annotation\Required(true)
|
||||||
|
* @Annotation\InputFilter("Zend\Filter\StringTrim")
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "Slide visibility"
|
||||||
|
* })
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $visibility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Annotation\Type("doctrine.object_select")
|
* @Annotation\Type("doctrine.object_select")
|
||||||
* @Annotation\Required(false)
|
* @Annotation\Required(false)
|
||||||
|
* @Annotation\Attributes({
|
||||||
|
* "multiple": true
|
||||||
|
* })
|
||||||
* @Annotation\Options({
|
* @Annotation\Options({
|
||||||
* "property": "name",
|
* "property": "name",
|
||||||
* "label": "Team",
|
* "label": "Team",
|
||||||
@ -48,21 +73,39 @@ class Slide
|
|||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* })
|
* })
|
||||||
* @var
|
* @var Team[]
|
||||||
*/
|
*/
|
||||||
private $team;
|
private $teams;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Annotation\Type("Zend\Form\Element\Text")
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
* @Annotation\Required(true)
|
* @Annotation\Required(false)
|
||||||
* @Annotation\InputFilter("Zend\Filter\StringTrim")
|
* @Annotation\InputFilter("Zend\Filter\StringTrim")
|
||||||
* @Annotation\Options({
|
* @Annotation\Options({
|
||||||
* "label": "Slide contents"
|
* "label": "Slide contents (type markdown)"
|
||||||
* })
|
* })
|
||||||
* @var
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $slideData;
|
private $slideData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
* @Annotation\Required(false)
|
||||||
|
* @Annotation\InputFilter("Zend\Filter\StringTrim")
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "Slide url (type iframe)"
|
||||||
|
* })
|
||||||
|
* @Annotation\Validator({
|
||||||
|
* "name":"Uri",
|
||||||
|
* "options": {
|
||||||
|
* "allowAbsolute": true,
|
||||||
|
* "allowRelative": false,
|
||||||
|
* }
|
||||||
|
* })
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $slideUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Annotation\Type("Zend\Form\Element\Checkbox")
|
* @Annotation\Type("Zend\Form\Element\Checkbox")
|
||||||
* @Annotation\Options({
|
* @Annotation\Options({
|
||||||
|
|||||||
150
src/App/Form/Team.php
Normal file → Executable file
150
src/App/Form/Team.php
Normal file → Executable file
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Form;
|
namespace App\Form;
|
||||||
|
|
||||||
|
use App\Entity\KanbanColumn;
|
||||||
use Zend\Form\Annotation;
|
use Zend\Form\Annotation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,6 +42,155 @@ class Team
|
|||||||
*/
|
*/
|
||||||
private $members;
|
private $members;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a dummy field, not a text actually. Only used to filter the input
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
* @Annotation\Required(false)
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "Labels"
|
||||||
|
* })
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $labels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a dummy field, not a text actually. Only used to filter the input
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "Active"
|
||||||
|
* })
|
||||||
|
* @Annotation\Validator({
|
||||||
|
* "name":"NotEmpty",
|
||||||
|
* "options": {"type": Zend\Validator\NotEmpty::NULL}
|
||||||
|
* })
|
||||||
|
* @Annotation\Required(false)
|
||||||
|
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $kanbanEnabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a dummy field, not a text actually. Only used to filter the input
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "Active"
|
||||||
|
* })
|
||||||
|
* @Annotation\Validator({
|
||||||
|
* "name":"NotEmpty",
|
||||||
|
* "options": {"type": Zend\Validator\NotEmpty::NULL}
|
||||||
|
* })
|
||||||
|
* @Annotation\Required(false)
|
||||||
|
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $commitTrackerEnabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a dummy field, not a text actually. Only used to filter the input
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "Active"
|
||||||
|
* })
|
||||||
|
* @Annotation\Validator({
|
||||||
|
* "name":"NotEmpty",
|
||||||
|
* "options": {"type": Zend\Validator\NotEmpty::NULL}
|
||||||
|
* })
|
||||||
|
* @Annotation\Required(false)
|
||||||
|
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $watchedEnabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Number")
|
||||||
|
* @Annotation\Required(true)
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "Jira filter id"
|
||||||
|
* })
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $filterId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Also a dummy field, a
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "Enabled"
|
||||||
|
* })
|
||||||
|
* @Annotation\Validator({
|
||||||
|
* "name":"NotEmpty",
|
||||||
|
* "options": {"type": Zend\Validator\NotEmpty::NULL}
|
||||||
|
* })
|
||||||
|
* @Annotation\Required(false)
|
||||||
|
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $dailyLockEnabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
* @Annotation\Required(false)
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "Start time"
|
||||||
|
* })
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $dailyStartTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
* @Annotation\Required(false)
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "End time"
|
||||||
|
* })
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $dailyEndTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a dummy field, not a text actually. Only used to filter the input
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
* @Annotation\Required(true)
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "1st column"
|
||||||
|
* })
|
||||||
|
* @var KanbanColumn
|
||||||
|
*/
|
||||||
|
private $backlogColumn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a dummy field, not a text actually. Only used to filter the input
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
* @Annotation\Required(true)
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "1st column"
|
||||||
|
* })
|
||||||
|
* @var KanbanColumn
|
||||||
|
*/
|
||||||
|
private $inprogressColumn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a dummy field, not a text actually. Only used to filter the input
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
* @Annotation\Required(true)
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "1st column"
|
||||||
|
* })
|
||||||
|
* @var KanbanColumn
|
||||||
|
*/
|
||||||
|
private $verificationColumn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a dummy field, not a text actually. Only used to filter the input
|
||||||
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
* @Annotation\Required(true)
|
||||||
|
* @Annotation\Options({
|
||||||
|
* "label": "1st column"
|
||||||
|
* })
|
||||||
|
* @var KanbanColumn
|
||||||
|
*/
|
||||||
|
private $doneColumn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Also a dummy field, a
|
* Also a dummy field, a
|
||||||
* @Annotation\Type("Zend\Form\Element\Text")
|
* @Annotation\Type("Zend\Form\Element\Text")
|
||||||
|
|||||||
5
src/App/Handler/AvatarHandler.php
Normal file → Executable file
5
src/App/Handler/AvatarHandler.php
Normal file → Executable file
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace App\Handler;
|
namespace App\Handler;
|
||||||
|
|
||||||
use App\Service\AvatarService;
|
use App\Service\AvatarService;
|
||||||
|
use finfo;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Psr\Http\Server\RequestHandlerInterface;
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
@ -36,8 +37,10 @@ class AvatarHandler implements RequestHandlerInterface
|
|||||||
} catch (\UnexpectedValueException $e) {
|
} catch (\UnexpectedValueException $e) {
|
||||||
return new TextResponse("Avatar not found", 404);
|
return new TextResponse("Avatar not found", 404);
|
||||||
}
|
}
|
||||||
|
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||||||
|
$contentType = $finfo->buffer($avatarImageData);
|
||||||
return (new TextResponse($avatarImageData, 200, [
|
return (new TextResponse($avatarImageData, 200, [
|
||||||
'content-type' => 'image/png',
|
'content-type' => $contentType,
|
||||||
]))->withHeader('Expires', '0')
|
]))->withHeader('Expires', '0')
|
||||||
->withHeader('Cache-Control', 'must-revalidate');
|
->withHeader('Cache-Control', 'must-revalidate');
|
||||||
}
|
}
|
||||||
|
|||||||
4
src/App/Handler/KanbanHandler.php
Normal file → Executable file
4
src/App/Handler/KanbanHandler.php
Normal file → Executable file
@ -32,9 +32,9 @@ class KanbanHandler implements RequestHandlerInterface
|
|||||||
*/
|
*/
|
||||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||||
{
|
{
|
||||||
$filterId = $request->getAttribute('filterId');
|
$teamId = (int)$request->getAttribute('teamId');
|
||||||
/** @var KanbanBoard $kanbanResult */
|
/** @var KanbanBoard $kanbanResult */
|
||||||
$kanbanResult = $this->dataCollector->getKanbanBoard($filterId);
|
$kanbanResult = $this->dataCollector->getKanbanBoard($teamId);
|
||||||
return new JsonResponse($kanbanResult);
|
return new JsonResponse($kanbanResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
40
src/App/Handler/WatchedHandler.php
Executable file
40
src/App/Handler/WatchedHandler.php
Executable file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Handler;
|
||||||
|
|
||||||
|
use App\Entity\KanbanBoard;
|
||||||
|
use App\Service\JiraCollectorService;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface;
|
||||||
|
use Zend\Diactoros\Response\JsonResponse;
|
||||||
|
|
||||||
|
class WatchedHandler implements RequestHandlerInterface
|
||||||
|
{
|
||||||
|
/** @var JiraCollectorService */
|
||||||
|
private $dataCollector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KanbanAction constructor.
|
||||||
|
* @param JiraCollectorService $dataCollectorService
|
||||||
|
*/
|
||||||
|
public function __construct(JiraCollectorService $dataCollectorService)
|
||||||
|
{
|
||||||
|
$this->dataCollector = $dataCollectorService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ServerRequestInterface $request
|
||||||
|
* @return ResponseInterface
|
||||||
|
* @todo filterId
|
||||||
|
*/
|
||||||
|
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||||
|
{
|
||||||
|
$teamId = (int)$request->getAttribute('teamId');
|
||||||
|
/** @var KanbanBoard $kanbanResult */
|
||||||
|
$kanbanResult = $this->dataCollector->getTeamWatchedIssues($teamId);
|
||||||
|
return new JsonResponse($kanbanResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/App/Handler/WatchedHandlerFactory.php
Executable file
22
src/App/Handler/WatchedHandlerFactory.php
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Handler;
|
||||||
|
|
||||||
|
use App\Service\JiraCollectorService;
|
||||||
|
use Interop\Container\ContainerInterface;
|
||||||
|
|
||||||
|
class WatchedHandlerFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param ContainerInterface $container
|
||||||
|
* @return WatchedHandler
|
||||||
|
*/
|
||||||
|
public function __invoke(ContainerInterface $container)
|
||||||
|
{
|
||||||
|
/** @var JiraCollectorService $dataCollectorService */
|
||||||
|
$dataCollectorService = $container->get(JiraCollectorService::class);
|
||||||
|
return new WatchedHandler($dataCollectorService);
|
||||||
|
}
|
||||||
|
}
|
||||||
310
src/App/Service/JiraCollectorService.php
Normal file → Executable file
310
src/App/Service/JiraCollectorService.php
Normal file → Executable file
@ -9,6 +9,9 @@ use App\Entity\JiraIssueType;
|
|||||||
use App\Entity\JiraStatus;
|
use App\Entity\JiraStatus;
|
||||||
use App\Entity\KanbanBoard;
|
use App\Entity\KanbanBoard;
|
||||||
use App\Entity\KanbanEntry;
|
use App\Entity\KanbanEntry;
|
||||||
|
use App\Entity\Team;
|
||||||
|
use App\Entity\WatchedIssue;
|
||||||
|
use App\Entity\WatchedIssueComment;
|
||||||
use Zend\Cache\Storage\StorageInterface;
|
use Zend\Cache\Storage\StorageInterface;
|
||||||
use Zend\Config\Config;
|
use Zend\Config\Config;
|
||||||
use Zend\Expressive\Router\RouterInterface;
|
use Zend\Expressive\Router\RouterInterface;
|
||||||
@ -18,8 +21,26 @@ use Zend\Json\Json;
|
|||||||
|
|
||||||
class JiraCollectorService
|
class JiraCollectorService
|
||||||
{
|
{
|
||||||
|
|
||||||
const CACHE_KEY_KANBANBOARD = 'kanbanBoard';
|
const CACHE_KEY_KANBANBOARD = 'kanbanBoard';
|
||||||
|
const CACHE_KEY_WATCHED = 'watchedIssues';
|
||||||
|
const BACKLOG_FIELD_DELIMITER = ';';
|
||||||
|
|
||||||
|
const EPIC_TICKET_LINK = 'customfield_11711';
|
||||||
|
const EPIC_NAME_FIELD = 'customfield_11712';
|
||||||
|
|
||||||
|
const STATUS_DONE = 'done';
|
||||||
|
const STATUS_CLOSED = 'closed';
|
||||||
|
const STATUS_ANSWERED = 'answered';
|
||||||
|
const STATUS_RESOLVED = 'resolved';
|
||||||
|
|
||||||
|
const IGNORED_STATUSES = [
|
||||||
|
self::STATUS_DONE,
|
||||||
|
self::STATUS_CLOSED,
|
||||||
|
self::STATUS_ANSWERED,
|
||||||
|
self::STATUS_RESOLVED,
|
||||||
|
];
|
||||||
|
|
||||||
|
const WATCH_FILTER = 'status NOT IN (%s) AND watcher in (%s) AND "Last change" not in (%s) ORDER BY "Last Comment"';
|
||||||
|
|
||||||
/** @var StorageInterface */
|
/** @var StorageInterface */
|
||||||
private $cache;
|
private $cache;
|
||||||
@ -33,39 +54,55 @@ class JiraCollectorService
|
|||||||
/** @var RouterInterface */
|
/** @var RouterInterface */
|
||||||
private $router;
|
private $router;
|
||||||
|
|
||||||
|
/** @var TeamService */
|
||||||
|
private $teamService;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private $cachedEpics = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JiraClientService constructor.
|
* JiraClientService constructor.
|
||||||
* @param StorageInterface $cache
|
* @param StorageInterface $cache
|
||||||
* @param Client $client
|
* @param Client $client
|
||||||
* @param Config $config
|
* @param Config $config
|
||||||
* @param RouterInterface $router
|
* @param RouterInterface $router
|
||||||
|
* @param TeamService $teamService
|
||||||
*/
|
*/
|
||||||
public function __construct(StorageInterface $cache, Client $client, Config $config, RouterInterface $router)
|
public function __construct(StorageInterface $cache,
|
||||||
|
Client $client,
|
||||||
|
Config $config,
|
||||||
|
RouterInterface $router,
|
||||||
|
TeamService $teamService)
|
||||||
{
|
{
|
||||||
$this->cache = $cache;
|
$this->cache = $cache;
|
||||||
$this->router = $router;
|
$this->router = $router;
|
||||||
$this->httpClient = $client;
|
$this->httpClient = $client;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
|
$this->teamService = $teamService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $filterId
|
* @param int $teamId
|
||||||
* @param bool $forceReload
|
* @param bool $forceReload
|
||||||
* @return KanbanBoard
|
* @return KanbanBoard
|
||||||
*/
|
*/
|
||||||
public function getKanbanBoard(int $filterId = null, bool $forceReload = false): KanbanBoard
|
public function getKanbanBoard(int $teamId, bool $forceReload = false): KanbanBoard
|
||||||
{
|
{
|
||||||
$kanbanBoard = $this->cache->getItem('kanbanBoard');
|
$team = $this->teamService->getTeam($teamId);
|
||||||
|
$teamName = $team->getName();
|
||||||
|
$kanbanBoard = $this->cache->getItem(sprintf("%s-%s", self::CACHE_KEY_KANBANBOARD, $teamName));
|
||||||
if ($forceReload || null === $kanbanBoard) {
|
if ($forceReload || null === $kanbanBoard) {
|
||||||
$user = $this->config->get('jira.user');
|
$user = $this->config->get('jira.user');
|
||||||
$password = $this->config->get('jira.password');
|
$password = $this->config->get('jira.password');
|
||||||
|
|
||||||
/** @var Config $kanbanBoardUriParams */
|
/** @var Config $kanbanBoardUriParams */
|
||||||
$kanbanBoardUriParams = $this->config->get('url.jiraKanbanBoard');
|
$kanbanBoardUri = $this->config->get('url.jiraKanbanBoard');
|
||||||
|
$kanbanBoardFilter = $this->config->get('jira.filterFields')->toArray();
|
||||||
|
|
||||||
$kanbanBoardUri = sprintf(
|
$kanbanBoardUri = sprintf(
|
||||||
$kanbanBoardUriParams['baseUrl'],
|
$kanbanBoardUri,
|
||||||
isset($filterId) ? $filterId : $kanbanBoardUriParams['filterId'],
|
$team->getFilterId(),
|
||||||
implode(",", $kanbanBoardUriParams['fields']->toArray())
|
implode(",", $kanbanBoardFilter)
|
||||||
);
|
);
|
||||||
|
|
||||||
$response = $this->httpClient
|
$response = $this->httpClient
|
||||||
@ -74,37 +111,196 @@ class JiraCollectorService
|
|||||||
->send();
|
->send();
|
||||||
|
|
||||||
if (!$response->isSuccess()) {
|
if (!$response->isSuccess()) {
|
||||||
throw new \UnexpectedValueException("Bad JIRA result", $response->getStatusCode());
|
throw new \UnexpectedValueException(sprintf(
|
||||||
|
"Bad JIRA result for URL:\n%s",
|
||||||
|
$kanbanBoardUri
|
||||||
|
), $response->getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
$parsedJsonData = Decoder::decode($response->getBody(), Json::TYPE_ARRAY);
|
$parsedJsonData = Decoder::decode($response->getBody(), Json::TYPE_ARRAY);
|
||||||
|
|
||||||
$kanbanBoard = $this->hydrateKanbanBoard($parsedJsonData);
|
$kanbanBoard = $this->hydrateKanbanBoard($team, $parsedJsonData);
|
||||||
$this->cache->setItem(self::CACHE_KEY_KANBANBOARD, serialize($kanbanBoard));
|
$this->cache->setItem(sprintf("%s-%s", self::CACHE_KEY_KANBANBOARD, $teamName), serialize($kanbanBoard));
|
||||||
} else {
|
return $kanbanBoard;
|
||||||
$kanbanBoard = unserialize($kanbanBoard);
|
|
||||||
}
|
}
|
||||||
|
return unserialize($kanbanBoard);
|
||||||
return $kanbanBoard;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param int $teamId
|
||||||
|
* @param bool $forceReload
|
||||||
|
* @return array
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function getTeamWatchedIssues(int $teamId, bool $forceReload = false)
|
||||||
|
{
|
||||||
|
$team = $this->teamService->getTeam($teamId);
|
||||||
|
$teamName = $team->getName();
|
||||||
|
$watchedIssues = $this->cache->getItem(sprintf("%s-%s", self::CACHE_KEY_WATCHED, $teamName));
|
||||||
|
if ($forceReload || null === $watchedIssues) {
|
||||||
|
$members = array_map(function (array $member): string {
|
||||||
|
return $member['signum'];
|
||||||
|
}, $team->getMembers());
|
||||||
|
$preparedMembers = sprintf('"%s"', implode('","', $members));
|
||||||
|
|
||||||
|
$filter = sprintf(
|
||||||
|
self::WATCH_FILTER,
|
||||||
|
sprintf('"%s"', implode('","', self::IGNORED_STATUSES)),
|
||||||
|
$preparedMembers, $preparedMembers
|
||||||
|
);
|
||||||
|
|
||||||
|
$user = $this->config->get('jira.user');
|
||||||
|
$password = $this->config->get('jira.password');
|
||||||
|
/** @var Config $kanbanBoardUriParams */
|
||||||
|
$jiraWatchedIssues = $this->config->get('url.jiraWatchedIssues');
|
||||||
|
$kanbanBoardFilterFields = [
|
||||||
|
'assignee',
|
||||||
|
'summary',
|
||||||
|
'comment',
|
||||||
|
];
|
||||||
|
$issueFields = implode(",", $kanbanBoardFilterFields);
|
||||||
|
|
||||||
|
$jiraIssueUri = sprintf($jiraWatchedIssues, $filter, $issueFields);
|
||||||
|
$response = $this->httpClient
|
||||||
|
->setUri($jiraIssueUri)
|
||||||
|
->setAuth($user, $password)
|
||||||
|
->send();
|
||||||
|
|
||||||
|
if (!$response->isSuccess()) {
|
||||||
|
throw new \UnexpectedValueException(sprintf(
|
||||||
|
"Bad JIRA result for URL:\n%s",
|
||||||
|
$jiraIssueUri
|
||||||
|
), $response->getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
$watchedIssues = $this->hydrateWatchedIssues(Decoder::decode($response->getBody(), Json::TYPE_ARRAY), $members);
|
||||||
|
$this->cache->setItem(sprintf("%s-%s", self::CACHE_KEY_WATCHED, $teamName), serialize($watchedIssues));
|
||||||
|
return $watchedIssues;
|
||||||
|
}
|
||||||
|
return unserialize($watchedIssues);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $parsedJson
|
||||||
|
* @param array $members
|
||||||
|
* @return array
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
private function hydrateWatchedIssues(array $parsedJson, array $members)
|
||||||
|
{
|
||||||
|
/** @var WatchedIssue[] $hydratedResult */
|
||||||
|
$hydratedResult = [];
|
||||||
|
|
||||||
|
foreach ($parsedJson['issues'] as $issueJson) {
|
||||||
|
$issueItem = new WatchedIssue();
|
||||||
|
$issueItem->setIssue($issueJson['key'])
|
||||||
|
->setAssignee($issueJson['fields']['assignee']['name'])
|
||||||
|
->setSummary(html_entity_decode($issueJson['fields']['summary']));
|
||||||
|
|
||||||
|
$issueComments = [];
|
||||||
|
foreach ($issueJson['fields']['comment']['comments'] as $commentJson) {
|
||||||
|
$issueComment = new WatchedIssueComment();
|
||||||
|
$issueComment->setSignum($commentJson['updateAuthor']['name'])
|
||||||
|
->setName($commentJson['updateAuthor']['displayName'])
|
||||||
|
->setContent(html_entity_decode($commentJson['body']))
|
||||||
|
->setDate(new \DateTimeImmutable($commentJson['updated']));
|
||||||
|
$issueComments[] = $issueComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
usort($issueComments, function(WatchedIssueComment $a, WatchedIssueComment $b) {
|
||||||
|
return $a->getDate() <=> $b->getDate();
|
||||||
|
});
|
||||||
|
|
||||||
|
$lastComment = array_pop($issueComments);
|
||||||
|
unset($issueComments);
|
||||||
|
$issueItem->setComment($lastComment);
|
||||||
|
|
||||||
|
$hydratedResult[] = $issueItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sanity check, we only want items where last change was a comment, but that is not possible
|
||||||
|
* with JIRA jql at the moment.
|
||||||
|
*/
|
||||||
|
return array_filter($hydratedResult, function(WatchedIssue $issue) use ($members) {
|
||||||
|
return null !== $issue->getComment()
|
||||||
|
? !in_array($issue->getComment()->getSignum(), $members)
|
||||||
|
: false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $parentKey
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
private function getEpicNameFromParent(string $parentKey): ?string
|
||||||
|
{
|
||||||
|
if (array_key_exists($parentKey, $this->cachedEpics)) {
|
||||||
|
return $this->cachedEpics[$parentKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $this->config->get('jira.user');
|
||||||
|
$password = $this->config->get('jira.password');
|
||||||
|
/** @var Config $kanbanBoardUriParams */
|
||||||
|
$jiraIssueBaseUrl = $this->config->get('url.jiraIssue');
|
||||||
|
$kanbanBoardFilter = $this->config->get('jira.filterFields')->toArray();
|
||||||
|
$kanbanBoardFilterString = implode(",", $kanbanBoardFilter);
|
||||||
|
$jiraIssueUri = sprintf($jiraIssueBaseUrl, $parentKey, $kanbanBoardFilterString);
|
||||||
|
|
||||||
|
$response = $this->httpClient
|
||||||
|
->setUri($jiraIssueUri)
|
||||||
|
->setAuth($user, $password)
|
||||||
|
->send();
|
||||||
|
|
||||||
|
if (!$response->isSuccess()) {
|
||||||
|
throw new \UnexpectedValueException("Bad JIRA result: $jiraIssueUri", $response->getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
$parsedJsonParentData = Decoder::decode($response->getBody(), Json::TYPE_ARRAY);
|
||||||
|
if ($parsedJsonParentData['fields'][self::EPIC_TICKET_LINK]) {
|
||||||
|
$jiraIssueUri = sprintf(
|
||||||
|
$jiraIssueBaseUrl,
|
||||||
|
$parsedJsonParentData['fields'][self::EPIC_TICKET_LINK],
|
||||||
|
$kanbanBoardFilterString
|
||||||
|
);
|
||||||
|
$response = $this->httpClient
|
||||||
|
->setUri($jiraIssueUri)
|
||||||
|
->setAuth($user, $password)
|
||||||
|
->send();
|
||||||
|
|
||||||
|
if (!$response->isSuccess()) {
|
||||||
|
throw new \UnexpectedValueException("Bad JIRA result", $response->getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
$parsedJsonEpicData = Decoder::decode($response->getBody(), Json::TYPE_ARRAY);
|
||||||
|
$this->cachedEpics[$parentKey] = $parsedJsonEpicData['fields'][self::EPIC_NAME_FIELD];
|
||||||
|
return $this->cachedEpics[$parentKey];
|
||||||
|
}
|
||||||
|
$this->cachedEpics[$parentKey] = null;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Team $team
|
||||||
* @param $parsedJsonData
|
* @param $parsedJsonData
|
||||||
* @return KanbanBoard
|
* @return KanbanBoard
|
||||||
* @todo check if avatar has to be locally cached
|
* @todo check if avatar has to be locally cached
|
||||||
*/
|
*/
|
||||||
private function hydrateKanbanBoard($parsedJsonData): KanbanBoard
|
private function hydrateKanbanBoard(Team $team, $parsedJsonData): KanbanBoard
|
||||||
{
|
{
|
||||||
$kanbanBoard = new KanbanBoard();
|
$kanbanBoard = new KanbanBoard();
|
||||||
|
|
||||||
|
$teamBacklogColumns = explode(self::BACKLOG_FIELD_DELIMITER, $team->getBacklogColumn()["jiraStatusName"]);
|
||||||
|
$teamInprogressColumns = explode(self::BACKLOG_FIELD_DELIMITER, $team->getInprogressColumn()["jiraStatusName"]);
|
||||||
|
$teamVerificationColumns = explode(self::BACKLOG_FIELD_DELIMITER, $team->getVerificationColumn()["jiraStatusName"]);
|
||||||
|
$teamDoneColumns = explode(self::BACKLOG_FIELD_DELIMITER, $team->getDoneColumn()["jiraStatusName"]);
|
||||||
|
|
||||||
foreach ($parsedJsonData['issues'] as $jsonIssue) {
|
foreach ($parsedJsonData['issues'] as $jsonIssue) {
|
||||||
|
set_time_limit(30);
|
||||||
$kanbanEntry = new KanbanEntry();
|
$kanbanEntry = new KanbanEntry();
|
||||||
$kanbanEntry->setId(intval($jsonIssue['id']))
|
$kanbanEntry->setId(intval($jsonIssue['id']))
|
||||||
->setKey($jsonIssue['key'])
|
->setKey($jsonIssue['key'])
|
||||||
->setSummary($jsonIssue['fields']['summary'])
|
->setSummary($jsonIssue['fields']['summary'])
|
||||||
->setExternalLink($jsonIssue['fields']['customfield_10850'])
|
|
||||||
->setMhwebStatus($jsonIssue['fields']['customfield_10844'])
|
|
||||||
->setAnswerCode($jsonIssue['fields']['customfield_11692'])
|
|
||||||
->setIssuePriority($jsonIssue['fields']['priority']['name'])
|
->setIssuePriority($jsonIssue['fields']['priority']['name'])
|
||||||
->setIssuePriorityIcon($jsonIssue['fields']['priority']['iconUrl'])
|
->setIssuePriorityIcon($jsonIssue['fields']['priority']['iconUrl'])
|
||||||
->setLabels($jsonIssue['fields']['labels'])
|
->setLabels($jsonIssue['fields']['labels'])
|
||||||
@ -143,48 +339,13 @@ class JiraCollectorService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// externalId : customfield_10010
|
// epicName: have to fetch 2 extra records
|
||||||
if (isset($jsonIssue['fields']['customfield_10010'])) {
|
if (isset($jsonIssue['fields'][self::EPIC_TICKET_LINK])) {
|
||||||
$kanbanEntry->setExternalId($jsonIssue['fields']['customfield_10010']);
|
$epicName = $this->getEpicNameFromParent($jsonIssue['key']);
|
||||||
}
|
$kanbanEntry->setEpicName($epicName);
|
||||||
|
} elseif (isset($jsonIssue['fields']['parent'])) {
|
||||||
// prio : customfield_10840
|
$epicName = $this->getEpicNameFromParent($jsonIssue['fields']['parent']['key']);
|
||||||
if (isset($jsonIssue['fields']['customfield_11226'])) {
|
$kanbanEntry->setEpicName($epicName);
|
||||||
$kanbanEntry->setPrio($jsonIssue['fields']['customfield_11226']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// functional area : customfield_11225
|
|
||||||
if (isset($jsonIssue['fields']['customfield_11225'])) {
|
|
||||||
foreach ($jsonIssue['fields']['customfield_11225'] as $functionalArea) {
|
|
||||||
$kanbanEntry->addFunctionalArea($functionalArea['value']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// project : customfield_10840
|
|
||||||
if (isset($jsonIssue['fields']['customfield_10840'])) {
|
|
||||||
$kanbanEntry->setProject($jsonIssue['fields']['customfield_10840']['value']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// mhweb hot : customfield_10847
|
|
||||||
if (isset($jsonIssue['fields']['customfield_10847'])) {
|
|
||||||
$boolVal = $jsonIssue['fields']['customfield_10847'][0]['value'] == 'yes';
|
|
||||||
$kanbanEntry->setMhwebHot($boolVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// mhweb external : customfield_10849
|
|
||||||
if (isset($jsonIssue['fields']['customfield_10849'])) {
|
|
||||||
$boolVal = $jsonIssue['fields']['customfield_10849'][0]['value'] == 'yes';
|
|
||||||
$kanbanEntry->setMhwebExternal($boolVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// team : customfield_10904
|
|
||||||
if (isset($jsonIssue['fields']['customfield_10904'])) {
|
|
||||||
$kanbanEntry->setTeam($jsonIssue['fields']['customfield_10904']['value']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// team : customfield_12500
|
|
||||||
if (isset($jsonIssue['fields']['customfield_12500'])) {
|
|
||||||
$kanbanEntry->setTaurusPrio($jsonIssue['fields']['customfield_12500']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// jira status
|
// jira status
|
||||||
@ -222,20 +383,17 @@ class JiraCollectorService
|
|||||||
}
|
}
|
||||||
|
|
||||||
$kanbanEntry->setUpdatedAt(new \DateTime($jsonIssue['fields']['updated']));
|
$kanbanEntry->setUpdatedAt(new \DateTime($jsonIssue['fields']['updated']));
|
||||||
|
if (in_array($jiraStatus->getName(), $teamBacklogColumns)) {
|
||||||
switch ($jiraStatus->getName()) {
|
$kanbanBoard->addInbox($kanbanEntry);
|
||||||
case "Backlog":
|
}
|
||||||
$kanbanBoard->addInbox($kanbanEntry);
|
elseif (in_array($jiraStatus->getName(), $teamInprogressColumns)) {
|
||||||
break;
|
$kanbanBoard->addInProgress($kanbanEntry);
|
||||||
case "In Progress":
|
}
|
||||||
$kanbanBoard->addInProgress($kanbanEntry);
|
elseif (in_array($jiraStatus->getName(), $teamVerificationColumns)) {
|
||||||
break;
|
$kanbanBoard->addVerification($kanbanEntry);
|
||||||
case "Verification":
|
}
|
||||||
$kanbanBoard->addVerification($kanbanEntry);
|
elseif (in_array($jiraStatus->getName(), $teamDoneColumns)) {
|
||||||
break;
|
$kanbanBoard->addDone($kanbanEntry);
|
||||||
case "Done":
|
|
||||||
$kanbanBoard->addDone($kanbanEntry);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
unset($kanbanEntry);
|
unset($kanbanEntry);
|
||||||
}
|
}
|
||||||
|
|||||||
3
src/App/Service/JiraCollectorServiceFactory.php
Normal file → Executable file
3
src/App/Service/JiraCollectorServiceFactory.php
Normal file → Executable file
@ -18,6 +18,7 @@ class JiraCollectorServiceFactory
|
|||||||
$httpClient = $container->get(Client::class);
|
$httpClient = $container->get(Client::class);
|
||||||
$config = new Config($configArray['app.config']);
|
$config = new Config($configArray['app.config']);
|
||||||
$router = $container->get(RouterInterface::class);
|
$router = $container->get(RouterInterface::class);
|
||||||
return new JiraCollectorService($cache,$httpClient, $config, $router);
|
$teamService = $container->get(TeamService::class);
|
||||||
|
return new JiraCollectorService($cache,$httpClient, $config, $router, $teamService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
0
src/App/Service/SlideManager.php
Normal file → Executable file
0
src/App/Service/SlideManager.php
Normal file → Executable file
3
src/App/Service/TeamService.php
Normal file → Executable file
3
src/App/Service/TeamService.php
Normal file → Executable file
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace App\Service;
|
namespace App\Service;
|
||||||
|
|
||||||
use App\Entity\Team;
|
use App\Entity\Team;
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\ORM\EntityManager;
|
use Doctrine\ORM\EntityManager;
|
||||||
use Doctrine\ORM\EntityNotFoundException;
|
use Doctrine\ORM\EntityNotFoundException;
|
||||||
use Zend\Form\Form;
|
use Zend\Form\Form;
|
||||||
@ -26,7 +27,7 @@ class TeamService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return Team[]|ArrayCollection
|
||||||
*/
|
*/
|
||||||
public function listTeams(): array
|
public function listTeams(): array
|
||||||
{
|
{
|
||||||
|
|||||||
23
src/DoctrineExpressiveModule/Hydrator/DoctrineObject.php
Normal file → Executable file
23
src/DoctrineExpressiveModule/Hydrator/DoctrineObject.php
Normal file → Executable file
@ -20,6 +20,7 @@
|
|||||||
namespace DoctrineExpressiveModule\Hydrator;
|
namespace DoctrineExpressiveModule\Hydrator;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
|
use DateTimeImmutable;
|
||||||
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
|
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
|
||||||
use Doctrine\Common\Persistence\ObjectManager;
|
use Doctrine\Common\Persistence\ObjectManager;
|
||||||
use Doctrine\Common\Util\Inflector;
|
use Doctrine\Common\Util\Inflector;
|
||||||
@ -484,9 +485,10 @@ class DoctrineObject extends AbstractHydrator
|
|||||||
/**
|
/**
|
||||||
* Handle various type conversions that should be supported natively by Doctrine (like DateTime)
|
* Handle various type conversions that should be supported natively by Doctrine (like DateTime)
|
||||||
*
|
*
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
* @param string $typeOfField
|
* @param string $typeOfField
|
||||||
* @return DateTime
|
* @return DateTime|DateTimeImmutable
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
protected function handleTypeConversions($value, $typeOfField)
|
protected function handleTypeConversions($value, $typeOfField)
|
||||||
{
|
{
|
||||||
@ -507,6 +509,23 @@ class DoctrineObject extends AbstractHydrator
|
|||||||
$value = new DateTime($value);
|
$value = new DateTime($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'datetimetz_immutable':
|
||||||
|
case 'datetime_immutable':
|
||||||
|
case 'time_immutable':
|
||||||
|
case 'date_immutable':
|
||||||
|
if ('' === $value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_int($value)) {
|
||||||
|
$dateTime = new DateTimeImmutable();
|
||||||
|
$dateTime->setTimestamp($value);
|
||||||
|
$value = $dateTime;
|
||||||
|
} elseif (is_string($value)) {
|
||||||
|
$value = new DateTimeImmutable($value);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user