added project start and end date (#1303)

* added sortable js library
* activity in invoice is optional
* added javascript widget for paginated boxes
* fix activity dropdown for globals only
* added timesheet service to reduce code duplication
* use repository to query for teams in dropdowns
* added project validator
* validate project start and end against timesheet
* include begin and end in dynamic form requests for projects
* added timezone and language option to import flag, improve timesheet import speed
* deactivate cross-timezone filter
* add virtual fields to field order list
* composer update
* added param to ignore dates
* position loader icon fixed - fixes #1330
* permission problem when creating a new project - fixes #1340
* remove dev dependencies webserver and thanks bundle
* stop information leak (begin and end date) in duration mode - fixes #1307
* unify timesheet edit dialog for user and admins
* fix security issue, own rates exposed to unauthorized users in multi-update dialog
This commit is contained in:
Kevin Papst
2020-01-05 02:49:01 +01:00
committed by GitHub
parent 50383673ca
commit d6798eed1e
121 changed files with 2465 additions and 1439 deletions

View File

@@ -92,6 +92,12 @@ final class ActivityFormTypeQuery
public function isGlobalsOnly(): bool
{
return null === $this->activity && null === $this->project;
return
(
null === $this->activity ||
($this->activity instanceof Activity && null === $this->activity->getProject())
)
&&
null === $this->project;
}
}

View File

@@ -26,15 +26,15 @@ class BaseQuery
public const DEFAULT_PAGE = 1;
/**
* @deprecated since 1.4, will be removed with 1.6
* @deprecated since 1.4, will be removed with 2.0
*/
public const RESULT_TYPE_OBJECTS = 'Objects';
/**
* @deprecated since 1.4, will be removed with 1.6
* @deprecated since 1.4, will be removed with 2.0
*/
public const RESULT_TYPE_PAGER = 'PagerFanta';
/**
* @deprecated since 1.4, will be removed with 1.6
* @deprecated since 1.4, will be removed with 2.0
*/
public const RESULT_TYPE_QUERYBUILDER = 'QueryBuilder';
@@ -63,7 +63,7 @@ class BaseQuery
private $order = self::ORDER_ASC;
/**
* @var string
* @deprecated since 1.4, will be removed with 1.6
* @deprecated since 1.4, will be removed with 2.0
*/
private $resultType = self::RESULT_TYPE_PAGER;
/**
@@ -79,6 +79,23 @@ class BaseQuery
*/
private $searchTerm;
/**
* @param Team[] $teams
* @return $this
*/
public function setTeams(?array $teams): self
{
$this->teams = [];
if (null !== $teams) {
foreach ($teams as $team) {
$this->addTeam($team);
}
}
return $this;
}
public function addTeam(Team $team): self
{
$this->teams[$team->getId()] = $team;
@@ -189,7 +206,7 @@ class BaseQuery
*/
public function getResultType()
{
@trigger_error('BaseQuery::getResultType() is deprecated and will be removed with 1.6', E_USER_DEPRECATED);
@trigger_error('BaseQuery::getResultType() is deprecated and will be removed with 2.0', E_USER_DEPRECATED);
return $this->resultType;
}
@@ -254,4 +271,27 @@ class BaseQuery
return $this;
}
public function copyTo(BaseQuery $query): BaseQuery
{
$query->setDefaults($this->defaults);
if (null !== $this->getCurrentUser()) {
$query->setCurrentUser($this->getCurrentUser());
}
$query->setOrder($this->getOrder());
$query->setOrderBy($this->getOrderBy());
$query->setSearchTerm($this->getSearchTerm());
$query->setPage($this->getPage());
$query->setPageSize($this->getPageSize());
foreach ($this->getTeams() as $team) {
$query->addTeam($team);
}
if ($this instanceof VisibilityInterface && $query instanceof VisibilityInterface) {
$query->setVisibility($this->getVisibility());
}
return $query;
}
}

View File

@@ -12,8 +12,10 @@ namespace App\Repository\Query;
/**
* Can be used for advanced queries with the: CustomerRepository
*/
class CustomerQuery extends VisibilityQuery
class CustomerQuery extends BaseQuery implements VisibilityInterface
{
use VisibilityTrait;
public const CUSTOMER_ORDER_ALLOWED = ['id', 'name', 'comment', 'country', 'number'];
public function __construct()

View File

@@ -36,6 +36,10 @@ final class ProjectFormTypeQuery
* @var array<Team>
*/
private $teams = [];
/**
* @var bool
*/
private $ignoreDate = false;
/**
* @param Project|int|null $project
@@ -126,4 +130,16 @@ final class ProjectFormTypeQuery
return $this;
}
public function isIgnoreDate(): bool
{
return $this->ignoreDate;
}
public function setIgnoreDate(bool $ignoreDate): ProjectFormTypeQuery
{
$this->ignoreDate = $ignoreDate;
return $this;
}
}

View File

@@ -14,18 +14,27 @@ use App\Entity\Customer;
/**
* Can be used for advanced queries with the: ProjectRepository
*/
class ProjectQuery extends CustomerQuery
class ProjectQuery extends BaseQuery implements VisibilityInterface
{
public const PROJECT_ORDER_ALLOWED = ['id', 'name', 'comment', 'customer', 'orderNumber'];
use VisibilityTrait;
public const PROJECT_ORDER_ALLOWED = ['id', 'name', 'comment', 'customer', 'orderNumber', 'projectStart', 'projectEnd'];
/**
* @var Customer|int|null
*/
private $customer;
/**
* @var \DateTime
*/
private $projectStart;
/**
* @var \DateTime
*/
private $projectEnd;
public function __construct()
{
parent::__construct();
$this->setDefaults([
'orderBy' => 'name',
]);
@@ -49,4 +58,28 @@ class ProjectQuery extends CustomerQuery
return $this;
}
public function getProjectStart(): ?\DateTime
{
return $this->projectStart;
}
public function setProjectStart(?\DateTime $projectStart): ProjectQuery
{
$this->projectStart = $projectStart;
return $this;
}
public function getProjectEnd(): ?\DateTime
{
return $this->projectEnd;
}
public function setProjectEnd(?\DateTime $projectEnd): ProjectQuery
{
$this->projectEnd = $projectEnd;
return $this;
}
}

View File

@@ -12,8 +12,10 @@ namespace App\Repository\Query;
/**
* Can be used for advanced queries with the: UserRepository
*/
class UserQuery extends VisibilityQuery
class UserQuery extends BaseQuery implements VisibilityInterface
{
use VisibilityTrait;
public const USER_ORDER_ALLOWED = ['id', 'alias', 'username', 'title', 'email'];
/**

View File

@@ -0,0 +1,31 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Repository\Query;
interface VisibilityInterface
{
public const SHOW_VISIBLE = 1;
public const SHOW_HIDDEN = 2;
public const SHOW_BOTH = 3;
public const ALLOWED_VISIBILITY_STATES = [
self::SHOW_BOTH,
self::SHOW_VISIBLE,
self::SHOW_HIDDEN,
];
public function getVisibility(): int;
/**
* @param int $visibility
* @return mixed
*/
public function setVisibility($visibility);
}

View File

@@ -11,43 +11,10 @@ namespace App\Repository\Query;
/**
* Query class for Repositories with a visibility field.
*
* @deprecated since 1.7, will be removed with 2.0
*/
class VisibilityQuery extends BaseQuery
class VisibilityQuery extends BaseQuery implements VisibilityInterface
{
public const SHOW_VISIBLE = 1;
public const SHOW_HIDDEN = 2;
public const SHOW_BOTH = 3;
public const ALLOWED_VISIBILITY_STATES = [
self::SHOW_BOTH,
self::SHOW_VISIBLE,
self::SHOW_HIDDEN,
];
/**
* @var int
*/
private $visibility = self::SHOW_VISIBLE;
/**
* @return int
*/
public function getVisibility()
{
return $this->visibility;
}
/**
* @param int $visibility
* @return $this
*/
public function setVisibility($visibility)
{
$visibility = (int) $visibility;
if (in_array($visibility, self::ALLOWED_VISIBILITY_STATES, true)) {
$this->visibility = $visibility;
}
return $this;
}
use VisibilityTrait;
}

View File

@@ -0,0 +1,33 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Repository\Query;
trait VisibilityTrait
{
/**
* @var int
*/
private $visibility = VisibilityInterface::SHOW_VISIBLE;
public function getVisibility(): int
{
return $this->visibility;
}
public function setVisibility($visibility)
{
$visibility = (int) $visibility;
if (in_array($visibility, VisibilityInterface::ALLOWED_VISIBILITY_STATES, true)) {
$this->visibility = $visibility;
}
return $this;
}
}