Improve create and start permission handling (#613)
This commit is contained in:
@@ -226,7 +226,6 @@ abstract class ControllerBaseTest extends WebTestCase
|
||||
if (count($validation) < 1) {
|
||||
// decorated form fields with icon have a different html structure, see kimai-theme.html.twig
|
||||
$classes = $field->parents()->getNode(1)->getAttribute('class');
|
||||
$this->assertContains('has-feedback', $classes, 'Form field has no validation message: ' . $name);
|
||||
$this->assertContains('has-error', $classes, 'Form field has no validation message: ' . $name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,9 +324,8 @@ class TimesheetControllerTest extends ControllerBaseTest
|
||||
$response = $client->getResponse();
|
||||
$this->assertTrue($response->isSuccessful());
|
||||
|
||||
$docuUrl = $this->createUrl('/help/timesheet');
|
||||
$this->assertContains(
|
||||
'<a href="' . $docuUrl . '"><i class="far fa-question-circle"></i></a>',
|
||||
'href="https://www.kimai.org/documentation/timesheet.html"',
|
||||
$response->getContent(),
|
||||
'Could not find link to documentation'
|
||||
);
|
||||
|
||||
@@ -40,8 +40,7 @@ abstract class AbstractEntityTest extends KernelTestCase
|
||||
foreach ($violations as $validation) {
|
||||
$violatedFields[$validation->getPropertyPath()] = $validation->getPropertyPath();
|
||||
}
|
||||
|
||||
$this->assertEquals($expected, count($violatedFields), sprintf('Expected %s violations, found %s in %s.', $expected, $actual, implode(', ', array_keys($violatedFields))));
|
||||
$countViolations = count($violatedFields);
|
||||
|
||||
foreach ($fieldNames as $id => $propertyPath) {
|
||||
$foundField = false;
|
||||
@@ -54,6 +53,7 @@ abstract class AbstractEntityTest extends KernelTestCase
|
||||
}
|
||||
|
||||
$this->assertEmpty($violatedFields, sprintf('Unexpected violations found: %s', implode(', ', $violatedFields)));
|
||||
$this->assertEquals($expected, $countViolations, sprintf('Expected %s violations, found %s in %s.', $expected, $actual, implode(', ', array_keys($violatedFields))));
|
||||
}
|
||||
|
||||
protected function assertHasNoViolations($entity)
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace App\Tests\Export\Renderer;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Export\Renderer\PDFRenderer;
|
||||
use App\Repository\UserRepository;
|
||||
use App\Security\CurrentUser;
|
||||
use App\Timesheet\UserDateTimeFactory;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
|
||||
@@ -25,12 +27,17 @@ class PdfRendererTest extends AbstractRendererTest
|
||||
{
|
||||
protected function getDateTimeFactory()
|
||||
{
|
||||
$user = new User();
|
||||
$repository = $this->getMockBuilder(UserRepository::class)->setMethods(['getById'])->disableOriginalConstructor()->getMock();
|
||||
$repository->expects($this->once())->method('getById')->willReturn($user);
|
||||
$token = $this->getMockBuilder(UsernamePasswordToken::class)->setMethods(['getUser'])->disableOriginalConstructor()->getMock();
|
||||
$token->expects($this->once())->method('getUser')->willReturn(new User());
|
||||
$token->expects($this->once())->method('getUser')->willReturn($user);
|
||||
$tokenStorage = new TokenStorage();
|
||||
$tokenStorage->setToken($token);
|
||||
|
||||
return new UserDateTimeFactory($tokenStorage);
|
||||
$user = new CurrentUser($tokenStorage, $repository);
|
||||
|
||||
return new UserDateTimeFactory($user);
|
||||
}
|
||||
|
||||
public function testConfiguration()
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace App\Tests\Timesheet;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Entity\UserPreference;
|
||||
use App\Repository\UserRepository;
|
||||
use App\Security\CurrentUser;
|
||||
use App\Timesheet\UserDateTimeFactory;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
|
||||
@@ -24,18 +26,27 @@ class UserDateTimeFactoryTest extends TestCase
|
||||
public const TEST_TIMEZONE = 'Antarctica/DumontDUrville';
|
||||
|
||||
protected function createDateTimeFactory(string $timezone)
|
||||
{
|
||||
return new UserDateTimeFactory($this->getCurrentUserMock($timezone));
|
||||
}
|
||||
|
||||
protected function getCurrentUserMock($timezone = null)
|
||||
{
|
||||
$user = new User();
|
||||
$pref = new UserPreference();
|
||||
$pref->setName('timezone');
|
||||
$pref->setValue($timezone);
|
||||
$user->addPreference($pref);
|
||||
if (null !== $timezone) {
|
||||
$pref = new UserPreference();
|
||||
$pref->setName('timezone');
|
||||
$pref->setValue($timezone);
|
||||
$user->addPreference($pref);
|
||||
}
|
||||
$repository = $this->getMockBuilder(UserRepository::class)->setMethods(['getById'])->disableOriginalConstructor()->getMock();
|
||||
$repository->expects($this->once())->method('getById')->willReturn($user);
|
||||
$token = $this->getMockBuilder(UsernamePasswordToken::class)->setMethods(['getUser'])->disableOriginalConstructor()->getMock();
|
||||
$token->expects($this->once())->method('getUser')->willReturn($user);
|
||||
$tokenStorage = new TokenStorage();
|
||||
$tokenStorage->setToken($token);
|
||||
|
||||
return new UserDateTimeFactory($tokenStorage);
|
||||
return new CurrentUser($tokenStorage, $repository);
|
||||
}
|
||||
|
||||
public function testGetTimezone()
|
||||
@@ -46,12 +57,14 @@ class UserDateTimeFactoryTest extends TestCase
|
||||
|
||||
public function testGetTimezoneWithFallbackTimezone()
|
||||
{
|
||||
$repository = $this->getMockBuilder(UserRepository::class)->disableOriginalConstructor()->getMock();
|
||||
$token = $this->getMockBuilder(UsernamePasswordToken::class)->setMethods(['getUser'])->disableOriginalConstructor()->getMock();
|
||||
$token->expects($this->once())->method('getUser')->willReturn('anonymous');
|
||||
$tokenStorage = new TokenStorage();
|
||||
$tokenStorage->setToken($token);
|
||||
|
||||
$sut = new UserDateTimeFactory($tokenStorage);
|
||||
$current = new CurrentUser($tokenStorage, $repository);
|
||||
$sut = new UserDateTimeFactory($current);
|
||||
$this->assertEquals(date_default_timezone_get(), $sut->getTimezone()->getName());
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ class ExtensionsTest extends TestCase
|
||||
|
||||
public function testGetFilters()
|
||||
{
|
||||
$filters = ['duration', 'money', 'currency', 'country', 'icon'];
|
||||
$filters = ['duration', 'money', 'currency', 'country', 'icon', 'docu_link'];
|
||||
$sut = $this->getSut($this->localeDe);
|
||||
$twigFilters = $sut->getFilters();
|
||||
$this->assertCount(count($filters), $twigFilters);
|
||||
@@ -227,4 +227,21 @@ class ExtensionsTest extends TestCase
|
||||
$this->assertEquals('', $sut->icon('foo'));
|
||||
$this->assertEquals('bar', $sut->icon('foo', 'bar'));
|
||||
}
|
||||
|
||||
public function testDocuLink()
|
||||
{
|
||||
$data = [
|
||||
'timesheet.html' => 'https://www.kimai.org/documentation/timesheet.html',
|
||||
'timesheet.html#duration-format' => 'https://www.kimai.org/documentation/timesheet.html#duration-format',
|
||||
'invoice.html' => 'https://www.kimai.org/documentation/invoice.html',
|
||||
'' => 'https://www.kimai.org/documentation/',
|
||||
null => 'https://www.kimai.org/documentation/',
|
||||
];
|
||||
|
||||
$sut = $this->getSut($this->localeEn);
|
||||
foreach ($data as $input => $expected) {
|
||||
$result = $sut->documentationLink($input);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ use App\Entity\Project;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Validator\Constraints\Timesheet as TimesheetConstraint;
|
||||
use App\Validator\Constraints\TimesheetValidator;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
|
||||
|
||||
@@ -23,13 +24,16 @@ use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
|
||||
*/
|
||||
class TimesheetValidatorTest extends ConstraintValidatorTestCase
|
||||
{
|
||||
protected function createValidator()
|
||||
protected function createValidator($isGranted = true)
|
||||
{
|
||||
$options = [
|
||||
'allow_future_times' => false
|
||||
];
|
||||
|
||||
return new TimesheetValidator($options);
|
||||
$authMock = $this->getMockBuilder(AuthorizationCheckerInterface::class)->getMock();
|
||||
$authMock->method('isGranted')->willReturn($isGranted);
|
||||
|
||||
return new TimesheetValidator($authMock, $options, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,6 +81,33 @@ class TimesheetValidatorTest extends ConstraintValidatorTestCase
|
||||
->assertRaised();
|
||||
}
|
||||
|
||||
public function testRestartDisallowed()
|
||||
{
|
||||
$this->validator = $this->createValidator(false);
|
||||
$this->validator->initialize($this->context);
|
||||
|
||||
$begin = new \DateTime('-10 hour');
|
||||
$customer = new Customer();
|
||||
$activity = new Activity();
|
||||
$project = new Project();
|
||||
$project->setCustomer($customer);
|
||||
$activity->setProject($project);
|
||||
|
||||
$timesheet = new Timesheet();
|
||||
$timesheet
|
||||
->setBegin($begin)
|
||||
->setActivity($activity)
|
||||
->setProject($project)
|
||||
;
|
||||
|
||||
$this->validator->validate($timesheet, new TimesheetConstraint(['message' => 'myMessage']));
|
||||
|
||||
$this->buildViolation('You are not allowed to start this timesheet record.')
|
||||
->atPath('property.path.end')
|
||||
->setCode(TimesheetConstraint::START_DISALLOWED)
|
||||
->assertRaised();
|
||||
}
|
||||
|
||||
public function testEndBeforeBegin()
|
||||
{
|
||||
$end = new \DateTime('-10 hour');
|
||||
|
||||
Reference in New Issue
Block a user