Release 2.14 (#4710)
- show "link has expired message" in password reset screen - added date objects as hydrator variables - for custom date formats in invoice templates - show meta-fields with null values (e.g. booleans with `false` where hidden) - fix permission check: allow to remove `view_own_timesheet` but still record times - prevent error 500 if customer country is empty - fix API 500 error if project does not exist when creating new timesheet - fix tags are not created in remote-search mode - do not check "export items" by default - fix daterange query, if user an request locale are different - added logging for invalid SAML responses (see various discussions)
This commit is contained in:
@@ -465,7 +465,9 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
||||
'hourlyRate' => 127,
|
||||
'billable' => false
|
||||
];
|
||||
$this->request($client, '/api/timesheets', 'POST', [], json_encode($data));
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets', 'POST', [], $json);
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$content = $client->getResponse()->getContent();
|
||||
@@ -494,7 +496,9 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
||||
'hourlyRate' => 127,
|
||||
'billable' => true
|
||||
];
|
||||
$this->request($client, '/api/timesheets?full=true', 'POST', [], json_encode($data));
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets?full=true', 'POST', [], $json);
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$content = $client->getResponse()->getContent();
|
||||
@@ -526,7 +530,9 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
||||
'end' => ($dateTime->createDateTime())->format('Y-m-d H:m:0'),
|
||||
'description' => 'foo',
|
||||
];
|
||||
$this->request($client, '/api/timesheets', 'POST', [], json_encode($data));
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets', 'POST', [], $json);
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$content = $client->getResponse()->getContent();
|
||||
@@ -571,7 +577,60 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
||||
'end' => (new \DateTime())->format('Y-m-d H:m:s'),
|
||||
'description' => 'foo',
|
||||
];
|
||||
$this->request($client, '/api/timesheets', 'POST', [], json_encode($data));
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets', 'POST', [], $json);
|
||||
$this->assertApiCallValidationError($client->getResponse(), ['project']);
|
||||
}
|
||||
|
||||
public function testPostActionWithUnknownActivity(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
|
||||
|
||||
$em = $this->getEntityManager();
|
||||
$customer = new Customer('foo-bar-1');
|
||||
$customer->setVisible(false);
|
||||
$customer->setCountry('DE');
|
||||
$customer->setTimezone('Europe/Berlin');
|
||||
$em->persist($customer);
|
||||
$project = new Project();
|
||||
$project->setName('foo-bar-2');
|
||||
$project->setVisible(true);
|
||||
$project->setCustomer($customer);
|
||||
$em->persist($project);
|
||||
|
||||
$data = [
|
||||
'begin' => (new \DateTime('- 8 hours'))->format('Y-m-d H:m:s'),
|
||||
'end' => (new \DateTime())->format('Y-m-d H:m:s'),
|
||||
'project' => $project->getId(),
|
||||
'activity' => 99,
|
||||
];
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets', 'POST', [], $json);
|
||||
$this->assertApiCallValidationError($client->getResponse(), ['project']);
|
||||
}
|
||||
|
||||
public function testPostActionWithNonExistingProject(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
|
||||
|
||||
$em = $this->getEntityManager();
|
||||
$activity = new Activity();
|
||||
$activity->setName('foo-bar-3');
|
||||
$activity->setVisible(true);
|
||||
$em->persist($activity);
|
||||
$em->flush();
|
||||
|
||||
$data = [
|
||||
'begin' => (new \DateTime('- 8 hours'))->format('Y-m-d H:m:s'),
|
||||
'end' => (new \DateTime())->format('Y-m-d H:m:s'),
|
||||
'project' => 99,
|
||||
'activity' => $activity->getId(),
|
||||
];
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets', 'POST', [], $json);
|
||||
$this->assertApiCallValidationError($client->getResponse(), ['project']);
|
||||
}
|
||||
|
||||
@@ -605,7 +664,9 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
||||
'end' => (new \DateTime())->format('Y-m-d H:m'),
|
||||
'description' => 'foo',
|
||||
];
|
||||
$this->request($client, '/api/timesheets', 'POST', [], json_encode($data));
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets', 'POST', [], $json);
|
||||
$this->assertApiCallValidationError($client->getResponse(), ['activity']);
|
||||
}
|
||||
|
||||
@@ -635,7 +696,9 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
||||
'end' => (new \DateTime())->format('Y-m-d H:m'),
|
||||
'description' => 'foo',
|
||||
];
|
||||
$this->request($client, '/api/timesheets', 'POST', [], json_encode($data));
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets', 'POST', [], $json);
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$content = $client->getResponse()->getContent();
|
||||
@@ -674,7 +737,9 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
||||
'description' => 'foo',
|
||||
'billable' => true,
|
||||
];
|
||||
$this->request($client, '/api/timesheets', 'POST', [], json_encode($data));
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets', 'POST', [], $json);
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$content = $client->getResponse()->getContent();
|
||||
@@ -700,7 +765,9 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
||||
'description' => 'foo',
|
||||
'billable' => false,
|
||||
];
|
||||
$this->request($client, '/api/timesheets/' . $timesheets[0]->getId(), 'PATCH', [], json_encode($data));
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets/' . $timesheets[0]->getId(), 'PATCH', [], $json);
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$content = $client->getResponse()->getContent();
|
||||
@@ -739,7 +806,9 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
||||
'description' => 'foo',
|
||||
'exported' => true,
|
||||
];
|
||||
$this->request($client, '/api/timesheets/' . $timesheets[0]->getId(), 'PATCH', [], json_encode($data));
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets/' . $timesheets[0]->getId(), 'PATCH', [], $json);
|
||||
$response = $client->getResponse();
|
||||
$this->assertApiResponseAccessDenied($response);
|
||||
}
|
||||
@@ -761,7 +830,9 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
||||
'end' => (new \DateTime('- 1 hours'))->format('Y-m-d H:m'),
|
||||
'description' => 'foo',
|
||||
];
|
||||
$this->request($client, '/api/timesheets/' . $timesheets[0]->getId(), 'PATCH', [], json_encode($data));
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets/' . $timesheets[0]->getId(), 'PATCH', [], $json);
|
||||
|
||||
$response = $client->getResponse();
|
||||
self::assertEquals(400, $response->getStatusCode());
|
||||
@@ -1066,7 +1137,9 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
||||
'description' => 'foo',
|
||||
'tags' => ['another', 'testing', 'bar']
|
||||
];
|
||||
$this->request($client, '/api/timesheets/' . $id, 'PATCH', [], json_encode($data));
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets/' . $id, 'PATCH', [], $json);
|
||||
|
||||
$this->request($client, '/api/timesheets/' . $id . '/restart', 'PATCH');
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
@@ -1100,7 +1173,9 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
||||
'description' => 'foo',
|
||||
'tags' => ['another', 'testing', 'bar']
|
||||
];
|
||||
$this->request($client, '/api/timesheets/' . $id, 'PATCH', [], json_encode($data));
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets/' . $id, 'PATCH', [], $json);
|
||||
|
||||
$begin = new \DateTime('2019-11-27 13:55:00');
|
||||
$this->request($client, '/api/timesheets/' . $id . '/restart', 'PATCH', ['begin' => $begin->format(BaseApiController::DATE_FORMAT_PHP)]);
|
||||
@@ -1211,7 +1286,9 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
||||
'fixedRate' => 2016,
|
||||
'hourlyRate' => 127
|
||||
];
|
||||
$this->request($client, '/api/timesheets', 'POST', [], json_encode($data));
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets', 'POST', [], $json);
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
$content = $client->getResponse()->getContent();
|
||||
@@ -1343,7 +1420,9 @@ class TimesheetControllerTest extends APIControllerBaseTest
|
||||
'name' => 'metatestmock',
|
||||
'value' => 'another,testing,bar'
|
||||
];
|
||||
$this->request($client, '/api/timesheets/' . $id . '/meta', 'PATCH', [], json_encode($data));
|
||||
$json = json_encode($data);
|
||||
self::assertIsString($json);
|
||||
$this->request($client, '/api/timesheets/' . $id . '/meta', 'PATCH', [], $json);
|
||||
|
||||
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class TagArrayToStringTransformerTest extends TestCase
|
||||
|
||||
$repository = $this->getMockBuilder(TagRepository::class)->disableOriginalConstructor()->getMock();
|
||||
|
||||
$sut = new TagArrayToStringTransformer($repository);
|
||||
$sut = new TagArrayToStringTransformer($repository, true);
|
||||
|
||||
$this->assertEquals('', $sut->transform([]));
|
||||
$this->assertEquals('', $sut->transform(null));
|
||||
@@ -45,10 +45,12 @@ class TagArrayToStringTransformerTest extends TestCase
|
||||
(new Tag())->setName('bar'),
|
||||
];
|
||||
|
||||
$repository = $this->getMockBuilder(TagRepository::class)->onlyMethods(['findBy'])->disableOriginalConstructor()->getMock();
|
||||
$repository = $this->getMockBuilder(TagRepository::class)
|
||||
->onlyMethods(['findBy', 'saveTag'])
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$repository->expects($this->once())->method('findBy')->willReturn($results);
|
||||
|
||||
$sut = new TagArrayToStringTransformer($repository);
|
||||
$sut = new TagArrayToStringTransformer($repository, true);
|
||||
|
||||
$this->assertEquals([], $sut->reverseTransform(''));
|
||||
$this->assertEquals([], $sut->reverseTransform(null));
|
||||
|
||||
@@ -34,7 +34,9 @@ class InvoiceModelDefaultHydratorTest extends TestCase
|
||||
{
|
||||
$keys = [
|
||||
'invoice.due_date',
|
||||
'invoice.due_date_process',
|
||||
'invoice.date',
|
||||
'invoice.date_process',
|
||||
'invoice.number',
|
||||
'invoice.currency',
|
||||
'invoice.currency_symbol',
|
||||
@@ -47,7 +49,9 @@ class InvoiceModelDefaultHydratorTest extends TestCase
|
||||
'invoice.total_time',
|
||||
'invoice.duration_decimal',
|
||||
'invoice.first',
|
||||
'invoice.first_process',
|
||||
'invoice.last',
|
||||
'invoice.last_process',
|
||||
'invoice.total',
|
||||
'invoice.total_nc',
|
||||
'invoice.total_plain',
|
||||
@@ -68,11 +72,13 @@ class InvoiceModelDefaultHydratorTest extends TestCase
|
||||
'query.month_number',
|
||||
'query.year',
|
||||
'query.begin',
|
||||
'query.begin_process',
|
||||
'query.begin_day',
|
||||
'query.begin_month',
|
||||
'query.begin_month_number',
|
||||
'query.begin_year',
|
||||
'query.end',
|
||||
'query.end_process',
|
||||
'query.end_day',
|
||||
'query.end_month',
|
||||
'query.end_month_number',
|
||||
|
||||
@@ -79,7 +79,9 @@ class DebugRendererTest extends TestCase
|
||||
{
|
||||
$keys = [
|
||||
'invoice.due_date',
|
||||
'invoice.due_date_process',
|
||||
'invoice.date',
|
||||
'invoice.date_process',
|
||||
'invoice.number',
|
||||
'invoice.currency',
|
||||
'invoice.currency_symbol',
|
||||
@@ -92,7 +94,9 @@ class DebugRendererTest extends TestCase
|
||||
'invoice.total_time',
|
||||
'invoice.duration_decimal',
|
||||
'invoice.first',
|
||||
'invoice.first_process',
|
||||
'invoice.last',
|
||||
'invoice.last_process',
|
||||
'invoice.total',
|
||||
'invoice.total_nc',
|
||||
'invoice.total_plain',
|
||||
@@ -113,11 +117,13 @@ class DebugRendererTest extends TestCase
|
||||
'query.month_number',
|
||||
'query.year',
|
||||
'query.begin',
|
||||
'query.begin_process',
|
||||
'query.begin_day',
|
||||
'query.begin_month',
|
||||
'query.begin_month_number',
|
||||
'query.begin_year',
|
||||
'query.end',
|
||||
'query.end_process',
|
||||
'query.end_day',
|
||||
'query.end_month',
|
||||
'query.end_month_number',
|
||||
|
||||
@@ -38,10 +38,10 @@ class ExportQueryTest extends TimesheetQueryTest
|
||||
|
||||
public function assertMarkAsExported(ExportQuery $sut): void
|
||||
{
|
||||
$this->assertTrue($sut->isMarkAsExported());
|
||||
|
||||
$sut->setMarkAsExported(false);
|
||||
$this->assertFalse($sut->isMarkAsExported());
|
||||
|
||||
$sut->setMarkAsExported(true);
|
||||
$this->assertTrue($sut->isMarkAsExported());
|
||||
}
|
||||
|
||||
public function assertRenderer(ExportQuery $sut): void
|
||||
|
||||
@@ -17,6 +17,7 @@ use App\Saml\SamlProvider;
|
||||
use App\Tests\Configuration\TestConfigLoader;
|
||||
use App\Tests\Mocks\SystemConfigurationFactory;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
|
||||
@@ -57,7 +58,7 @@ class SamlProviderTest extends TestCase
|
||||
$userProvider->method('loadUserByIdentifier')->willReturn(new User());
|
||||
}
|
||||
|
||||
$provider = new SamlProvider($repository, $userProvider, $samlConfig);
|
||||
$provider = new SamlProvider($repository, $userProvider, $samlConfig, $this->createMock(LoggerInterface::class));
|
||||
|
||||
return $provider;
|
||||
}
|
||||
@@ -107,7 +108,7 @@ class SamlProviderTest extends TestCase
|
||||
public function testAuthenticateThrowsAuthenticationException(): void
|
||||
{
|
||||
$this->expectException(AuthenticationException::class);
|
||||
$this->expectExceptionMessage('Failed creating or hydrating user "foo1@example.com": Missing user attribute: Email');
|
||||
$this->expectExceptionMessage('Failed creating or hydrating user "foo1@example.com": Missing SAML attribute in response: Email');
|
||||
|
||||
$user = new User();
|
||||
$user->setAuth(User::AUTH_SAML);
|
||||
|
||||
@@ -502,11 +502,6 @@ parameters:
|
||||
count: 6
|
||||
path: API/TimesheetControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#5 \\$content of method App\\\\Tests\\\\API\\\\APIControllerBaseTest\\:\\:request\\(\\) expects string\\|null, string\\|false given\\.$#"
|
||||
count: 14
|
||||
path: API/TimesheetControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'enabled' on mixed\\.$#"
|
||||
count: 1
|
||||
|
||||
Reference in New Issue
Block a user