Release 2.0.13 (#3955)
- added missing escape to prevent HTML injection - added missing color attribute - upgrade theme - use dropdown submenu if title is set, otherwise dropdown tends to get too long - allow to use card-table instead of card-body - added `required` attribute to username and password field - fix pagination back to page 1 - prevent tag name too long - re-add missing user preferences link
This commit is contained in:
@@ -17,11 +17,11 @@ class Constants
|
||||
/**
|
||||
* The current release version
|
||||
*/
|
||||
public const VERSION = '2.0.12';
|
||||
public const VERSION = '2.0.13';
|
||||
/**
|
||||
* The current release: major * 10000 + minor * 100 + patch
|
||||
*/
|
||||
public const VERSION_ID = 20012;
|
||||
public const VERSION_ID = 20013;
|
||||
/**
|
||||
* The software name
|
||||
*/
|
||||
|
||||
@@ -87,6 +87,7 @@ final class ReportUsersMonthController extends AbstractController
|
||||
$values->setDate($dateTimeFactory->getStartOfMonth());
|
||||
}
|
||||
|
||||
/** @var \DateTime $start */
|
||||
$start = $values->getDate();
|
||||
$start->modify('first day of 00:00:00');
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace App\Controller\Reporting;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Model\DailyStatistic;
|
||||
use App\Reporting\MonthByUser\MonthByUser;
|
||||
use App\Reporting\MonthByUser\MonthByUserForm;
|
||||
@@ -64,12 +65,14 @@ final class UserMonthController extends AbstractUserReportController
|
||||
$values->setDate($dateTimeFactory->getStartOfMonth());
|
||||
}
|
||||
|
||||
/** @var \DateTime $start */
|
||||
$start = $values->getDate();
|
||||
$start->modify('first day of 00:00:00');
|
||||
|
||||
$end = clone $start;
|
||||
$end->modify('last day of 23:59:59');
|
||||
|
||||
/** @var User $selectedUser */
|
||||
$selectedUser = $values->getUser();
|
||||
|
||||
$previousMonth = clone $start;
|
||||
|
||||
@@ -55,12 +55,12 @@ final class TagFixtures extends Fixture
|
||||
$tagName = $faker->text(rand(5, 10));
|
||||
}
|
||||
|
||||
if (\in_array($tagName, $existing)) {
|
||||
if (\in_array(mb_strtolower($tagName), $existing, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$existing[] = $tagName;
|
||||
$tag->setName($tagName);
|
||||
$existing[] = mb_strtolower($tagName);
|
||||
$tag->setName(mb_substr($tagName, 0, 100));
|
||||
|
||||
$manager->persist($tag);
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
namespace App\DataFixtures;
|
||||
|
||||
use App\Entity\Activity;
|
||||
use App\Entity\Customer;
|
||||
use App\Entity\Project;
|
||||
use App\Entity\Tag;
|
||||
use App\Entity\Timesheet;
|
||||
@@ -58,12 +57,8 @@ final class TimesheetFixtures extends Fixture implements FixtureGroupInterface
|
||||
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
$results = $this->findRandom($manager, Customer::class, 50);
|
||||
|
||||
$allUser = $this->getAllUsers($manager);
|
||||
|
||||
$faker = Factory::create();
|
||||
|
||||
$all = 0;
|
||||
|
||||
foreach ($allUser as $user) {
|
||||
|
||||
@@ -47,6 +47,10 @@ final class UserSubscriber extends AbstractActionsSubscriber
|
||||
$event->addActionToSubmenu('edit', $id, $action);
|
||||
}
|
||||
|
||||
if ($this->isGranted('preferences', $user)) {
|
||||
$event->addConfig($this->path('user_profile_preferences', ['username' => $user->getUserIdentifier()]));
|
||||
}
|
||||
|
||||
if (($event->getUser()->getId() === $user->getId() && $this->isGranted('report:user')) || $this->isGranted('report:other')) {
|
||||
$event->addActionToSubmenu('report', 'weekly', ['url' => $this->path('report_user_week', ['user' => $user->getId()]), 'translation_domain' => 'reporting', 'title' => 'report_user_week']);
|
||||
$event->addActionToSubmenu('report', 'monthly', ['url' => $this->path('report_user_month', ['user' => $user->getId()]), 'translation_domain' => 'reporting', 'title' => 'report_user_month']);
|
||||
|
||||
@@ -60,7 +60,7 @@ final class TagArrayToStringTransformer implements DataTransformerInterface
|
||||
|
||||
foreach ($newNames as $name) {
|
||||
$tag = new Tag();
|
||||
$tag->setName($name);
|
||||
$tag->setName(mb_substr($name, 0, 100));
|
||||
$tags[] = $tag;
|
||||
|
||||
// new tags persist automatically thanks to the cascade={"persist"}
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace App\Form\Type;
|
||||
|
||||
use App\Configuration\SystemConfiguration;
|
||||
use App\Constants;
|
||||
use App\Utils\Color;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\DataTransformerInterface;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
@@ -39,6 +40,13 @@ final class ColorChoiceType extends AbstractType implements DataTransformerInter
|
||||
],
|
||||
'label' => 'color',
|
||||
'empty_data' => null,
|
||||
'choice_attr' => function ($color, $name) {
|
||||
if ($color === null) {
|
||||
$color = (new Color())->getRandom($name);
|
||||
}
|
||||
|
||||
return ['data-color' => $color];
|
||||
},
|
||||
];
|
||||
|
||||
$choices = [];
|
||||
|
||||
@@ -80,7 +80,7 @@ final class TagsSelectType extends AbstractType
|
||||
$newNames = array_diff($newNames, $foundTagNames);
|
||||
foreach ($newNames as $name) {
|
||||
$tag = new Tag();
|
||||
$tag->setName($name);
|
||||
$tag->setName(mb_substr($name, 0, 100));
|
||||
$this->tagRepository->saveTag($tag);
|
||||
$newData[] = $tag->getId();
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ namespace App\Model;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Model\Statistic\StatisticDate;
|
||||
use DateTime;
|
||||
use DateTimeInterface;
|
||||
|
||||
final class DailyStatistic implements DateStatisticInterface
|
||||
@@ -19,16 +18,14 @@ final class DailyStatistic implements DateStatisticInterface
|
||||
/**
|
||||
* @var array<string, StatisticDate>
|
||||
*/
|
||||
private $days = [];
|
||||
private $begin;
|
||||
private $end;
|
||||
private $user;
|
||||
private array $days = [];
|
||||
private DateTimeInterface $begin;
|
||||
private DateTimeInterface $end;
|
||||
|
||||
public function __construct(DateTime $begin, DateTime $end, User $user)
|
||||
public function __construct(DateTimeInterface $begin, DateTimeInterface $end, private User $user)
|
||||
{
|
||||
$this->begin = clone $begin;
|
||||
$this->end = clone $end;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
public function getUser(): User
|
||||
@@ -42,7 +39,7 @@ final class DailyStatistic implements DateStatisticInterface
|
||||
return;
|
||||
}
|
||||
|
||||
$tmp = clone $this->begin;
|
||||
$tmp = \DateTime::createFromInterface($this->begin);
|
||||
$tmp->setTime(0, 0, 0);
|
||||
while ($tmp < $this->end) {
|
||||
$id = $tmp->format('Y-m-d');
|
||||
|
||||
@@ -116,7 +116,7 @@ final class LocaleFormatExtensions extends AbstractExtension implements LocaleAw
|
||||
return $this->locale;
|
||||
}
|
||||
|
||||
public function isWeekend(DateTime|string|null $dateTime): bool
|
||||
public function isWeekend(\DateTimeInterface|string|null $dateTime): bool
|
||||
{
|
||||
if (!$dateTime instanceof \DateTime) {
|
||||
return false;
|
||||
@@ -141,7 +141,7 @@ final class LocaleFormatExtensions extends AbstractExtension implements LocaleAw
|
||||
return ($day === 0 || $day === 6);
|
||||
}
|
||||
|
||||
public function dateShort(DateTime|string|null $date): string
|
||||
public function dateShort(\DateTimeInterface|string|null $date): string
|
||||
{
|
||||
return (string) $this->getFormatter()->dateShort($date);
|
||||
}
|
||||
@@ -158,17 +158,17 @@ final class LocaleFormatExtensions extends AbstractExtension implements LocaleAw
|
||||
return new DateTime($date, new \DateTimeZone($timezone));
|
||||
}
|
||||
|
||||
public function dateFormat(DateTime|string|null $date, string $format): string
|
||||
public function dateFormat(\DateTimeInterface|string|null $date, string $format): string
|
||||
{
|
||||
return (string) $this->getFormatter()->dateFormat($date, $format);
|
||||
}
|
||||
|
||||
public function dateWeekday(DateTime $date): string
|
||||
public function dateWeekday(\DateTimeInterface $date): string
|
||||
{
|
||||
return $this->dayName($date, true) . ' ' . $this->getFormatter()->dateFormat($date, 'd');
|
||||
}
|
||||
|
||||
public function time(DateTime|string|null $date): string
|
||||
public function time(\DateTimeInterface|string|null $date): string
|
||||
{
|
||||
return (string) $this->getFormatter()->time($date);
|
||||
}
|
||||
@@ -192,12 +192,12 @@ final class LocaleFormatExtensions extends AbstractExtension implements LocaleAw
|
||||
return $months;
|
||||
}
|
||||
|
||||
public function monthName(\DateTime $dateTime, bool $withYear = false): string
|
||||
public function monthName(\DateTimeInterface $dateTime, bool $withYear = false): string
|
||||
{
|
||||
return $this->getFormatter()->monthName($dateTime, $withYear);
|
||||
}
|
||||
|
||||
public function dayName(\DateTime $dateTime, bool $short = false): string
|
||||
public function dayName(\DateTimeInterface $dateTime, bool $short = false): string
|
||||
{
|
||||
return $this->getFormatter()->dayName($dateTime, $short);
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ final class LocaleFormatter
|
||||
/**
|
||||
* @see https://unicode-org.github.io/icu/userguide/format_parse/datetime/
|
||||
*/
|
||||
private function formatIntl(\DateTime $dateTime, string $format): string
|
||||
private function formatIntl(\DateTimeInterface $dateTime, string $format): string
|
||||
{
|
||||
$formatter = new IntlDateFormatter(
|
||||
$this->locale,
|
||||
@@ -303,12 +303,12 @@ final class LocaleFormatter
|
||||
return (string) $formatted;
|
||||
}
|
||||
|
||||
public function monthName(\DateTime $dateTime, bool $withYear = false): string
|
||||
public function monthName(\DateTimeInterface $dateTime, bool $withYear = false): string
|
||||
{
|
||||
return $this->formatIntl($dateTime, ($withYear ? 'LLLL yyyy' : 'LLLL'));
|
||||
}
|
||||
|
||||
public function dayName(\DateTime $dateTime, bool $short = false): string
|
||||
public function dayName(\DateTimeInterface $dateTime, bool $short = false): string
|
||||
{
|
||||
return $this->formatIntl($dateTime, ($short ? 'EE' : 'EEEE'));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user