Release 2.8.0 (#4508)
This commit is contained in:
2
.github/workflows/lockfiles.yaml
vendored
2
.github/workflows/lockfiles.yaml
vendored
@@ -19,5 +19,5 @@ jobs:
|
|||||||
uses: xalvarez/prevent-file-change-action@v1
|
uses: xalvarez/prevent-file-change-action@v1
|
||||||
with:
|
with:
|
||||||
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
pattern: .*.lock
|
pattern: .*\.lock$
|
||||||
trustedAuthors: kevinpapst, dependabot
|
trustedAuthors: kevinpapst, dependabot
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
"onelogin/php-saml": "^4.0",
|
"onelogin/php-saml": "^4.0",
|
||||||
"pagerfanta/pagerfanta": "^3.0",
|
"pagerfanta/pagerfanta": "^3.0",
|
||||||
"phpoffice/phpspreadsheet": "^1.16",
|
"phpoffice/phpspreadsheet": "^1.16",
|
||||||
"phpoffice/phpword": "^1.0",
|
"phpoffice/phpword": "1.1.*",
|
||||||
"psr/container": "^2.0",
|
"psr/container": "^2.0",
|
||||||
"psr/log": "^3.0",
|
"psr/log": "^3.0",
|
||||||
"scheb/2fa-backup-code": "^6.2",
|
"scheb/2fa-backup-code": "^6.2",
|
||||||
@@ -174,6 +174,7 @@
|
|||||||
"bin/console lint:container",
|
"bin/console lint:container",
|
||||||
"bin/console lint:yaml config --parse-tags",
|
"bin/console lint:yaml config --parse-tags",
|
||||||
"bin/console lint:twig templates --show-deprecations",
|
"bin/console lint:twig templates --show-deprecations",
|
||||||
|
"bin/console doctrine:schema:validate --skip-sync -vvv --no-interaction",
|
||||||
"bin/console lint:xliff translations"
|
"bin/console lint:xliff translations"
|
||||||
],
|
],
|
||||||
"tests": "vendor/bin/phpunit tests/",
|
"tests": "vendor/bin/phpunit tests/",
|
||||||
|
|||||||
560
composer.lock
generated
560
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,12 @@
|
|||||||
framework:
|
framework:
|
||||||
# Deprecations for 7.0
|
# Deprecations for 7.0
|
||||||
handle_all_throwables: true
|
handle_all_throwables: true
|
||||||
# cannot be disabled, because of https://github.com/nelmio/NelmioApiDocBundle/pull/2164
|
|
||||||
annotations:
|
annotations:
|
||||||
enabled: true
|
enabled: false
|
||||||
|
|
||||||
|
serializer:
|
||||||
|
enable_attributes: true
|
||||||
|
|
||||||
# ---------------------------
|
# ---------------------------
|
||||||
|
|
||||||
exceptions:
|
exceptions:
|
||||||
@@ -32,6 +35,7 @@ framework:
|
|||||||
|
|
||||||
validation:
|
validation:
|
||||||
email_validation_mode: html5
|
email_validation_mode: html5
|
||||||
|
enable_attributes: true
|
||||||
|
|
||||||
when@dev:
|
when@dev:
|
||||||
framework:
|
framework:
|
||||||
|
|||||||
@@ -15,14 +15,13 @@ use App\Entity\Customer;
|
|||||||
use App\Entity\Project;
|
use App\Entity\Project;
|
||||||
use App\Entity\Timesheet;
|
use App\Entity\Timesheet;
|
||||||
use App\Event\PageActionsEvent;
|
use App\Event\PageActionsEvent;
|
||||||
use FOS\RestBundle\Controller\Annotations as Rest;
|
|
||||||
use FOS\RestBundle\View\View;
|
use FOS\RestBundle\View\View;
|
||||||
use FOS\RestBundle\View\ViewHandlerInterface;
|
use FOS\RestBundle\View\ViewHandlerInterface;
|
||||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||||
use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity;
|
use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity;
|
||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OA;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
@@ -73,7 +72,7 @@ final class ActionsController extends BaseApiController
|
|||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet ID to fetch', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet ID to fetch', required: true)]
|
||||||
#[OA\Parameter(name: 'view', in: 'path', description: 'View to display the actions at (e.g. index, custom)', required: true)]
|
#[OA\Parameter(name: 'view', in: 'path', description: 'View to display the actions at (e.g. index, custom)', required: true)]
|
||||||
#[OA\Parameter(name: 'locale', in: 'path', description: 'Language to translate the action title to (e.g. de, en)', required: true)]
|
#[OA\Parameter(name: 'locale', in: 'path', description: 'Language to translate the action title to (e.g. de, en)', required: true)]
|
||||||
#[Rest\Get(path: '/timesheet/{id}/{view}/{locale}', name: 'get_timesheet_actions', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/timesheet/{id}/{view}/{locale}', name: 'get_timesheet_actions', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function getTimesheetActions(Timesheet $timesheet, string $view, string $locale): Response
|
public function getTimesheetActions(Timesheet $timesheet, string $view, string $locale): Response
|
||||||
@@ -93,7 +92,7 @@ final class ActionsController extends BaseApiController
|
|||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Activity ID to fetch', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Activity ID to fetch', required: true)]
|
||||||
#[OA\Parameter(name: 'view', in: 'path', description: 'View to display the actions at (e.g. index, custom)', required: true)]
|
#[OA\Parameter(name: 'view', in: 'path', description: 'View to display the actions at (e.g. index, custom)', required: true)]
|
||||||
#[OA\Parameter(name: 'locale', in: 'path', description: 'Language to translate the action title to (e.g. de, en)', required: true)]
|
#[OA\Parameter(name: 'locale', in: 'path', description: 'Language to translate the action title to (e.g. de, en)', required: true)]
|
||||||
#[Rest\Get(path: '/activity/{id}/{view}/{locale}', name: 'get_activity_actions', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/activity/{id}/{view}/{locale}', name: 'get_activity_actions', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function getActivityActions(Activity $activity, string $view, string $locale): Response
|
public function getActivityActions(Activity $activity, string $view, string $locale): Response
|
||||||
@@ -113,7 +112,7 @@ final class ActionsController extends BaseApiController
|
|||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Project ID to fetch', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Project ID to fetch', required: true)]
|
||||||
#[OA\Parameter(name: 'view', in: 'path', description: 'View to display the actions at (e.g. index, custom)', required: true)]
|
#[OA\Parameter(name: 'view', in: 'path', description: 'View to display the actions at (e.g. index, custom)', required: true)]
|
||||||
#[OA\Parameter(name: 'locale', in: 'path', description: 'Language to translate the action title to (e.g. de, en)', required: true)]
|
#[OA\Parameter(name: 'locale', in: 'path', description: 'Language to translate the action title to (e.g. de, en)', required: true)]
|
||||||
#[Rest\Get(path: '/project/{id}/{view}/{locale}', name: 'get_project_actions', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/project/{id}/{view}/{locale}', name: 'get_project_actions', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function getProjectActions(Project $project, string $view, string $locale): Response
|
public function getProjectActions(Project $project, string $view, string $locale): Response
|
||||||
@@ -133,7 +132,7 @@ final class ActionsController extends BaseApiController
|
|||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Customer ID to fetch', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Customer ID to fetch', required: true)]
|
||||||
#[OA\Parameter(name: 'view', in: 'path', description: 'View to display the actions at (e.g. index, custom)', required: true)]
|
#[OA\Parameter(name: 'view', in: 'path', description: 'View to display the actions at (e.g. index, custom)', required: true)]
|
||||||
#[OA\Parameter(name: 'locale', in: 'path', description: 'Language to translate the action title to (e.g. de, en)', required: true)]
|
#[OA\Parameter(name: 'locale', in: 'path', description: 'Language to translate the action title to (e.g. de, en)', required: true)]
|
||||||
#[Rest\Get(path: '/customer/{id}/{view}/{locale}', name: 'get_customer_actions', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/customer/{id}/{view}/{locale}', name: 'get_customer_actions', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function getCustomerActions(Customer $customer, string $view, string $locale): Response
|
public function getCustomerActions(Customer $customer, string $view, string $locale): Response
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ use Psr\EventDispatcher\EventDispatcherInterface;
|
|||||||
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
|
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
#[Route(path: '/activities')]
|
#[Route(path: '/activities')]
|
||||||
@@ -55,7 +55,7 @@ final class ActivityController extends BaseApiController
|
|||||||
* Returns a collection of activities (which are visible to the user)
|
* Returns a collection of activities (which are visible to the user)
|
||||||
*/
|
*/
|
||||||
#[OA\Response(response: 200, description: 'Returns a collection of activities', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/ActivityCollection')))]
|
#[OA\Response(response: 200, description: 'Returns a collection of activities', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/ActivityCollection')))]
|
||||||
#[Rest\Get(path: '', name: 'get_activities')]
|
#[Route(methods: ['GET'], path: '', name: 'get_activities')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\QueryParam(name: 'project', requirements: '\d+', strict: true, nullable: true, description: 'Project ID to filter activities')]
|
#[Rest\QueryParam(name: 'project', requirements: '\d+', strict: true, nullable: true, description: 'Project ID to filter activities')]
|
||||||
@@ -125,7 +125,7 @@ final class ActivityController extends BaseApiController
|
|||||||
*/
|
*/
|
||||||
#[OA\Response(response: 200, description: 'Returns one activity entity', content: new OA\JsonContent(ref: '#/components/schemas/ActivityEntity'))]
|
#[OA\Response(response: 200, description: 'Returns one activity entity', content: new OA\JsonContent(ref: '#/components/schemas/ActivityEntity'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Activity ID to fetch', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Activity ID to fetch', required: true)]
|
||||||
#[Rest\Get(path: '/{id}', name: 'get_activity', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/{id}', name: 'get_activity', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function getAction(Activity $activity): Response
|
public function getAction(Activity $activity): Response
|
||||||
@@ -141,7 +141,7 @@ final class ActivityController extends BaseApiController
|
|||||||
*/
|
*/
|
||||||
#[OA\Post(description: 'Creates a new activity and returns it afterwards', responses: [new OA\Response(response: 200, description: 'Returns the new created activity', content: new OA\JsonContent(ref: '#/components/schemas/ActivityEntity'))])]
|
#[OA\Post(description: 'Creates a new activity and returns it afterwards', responses: [new OA\Response(response: 200, description: 'Returns the new created activity', content: new OA\JsonContent(ref: '#/components/schemas/ActivityEntity'))])]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ActivityEditForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ActivityEditForm'))]
|
||||||
#[Rest\Post(path: '', name: 'post_activity')]
|
#[Route(methods: ['POST'], path: '', name: 'post_activity')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function postAction(Request $request): Response
|
public function postAction(Request $request): Response
|
||||||
@@ -184,7 +184,7 @@ final class ActivityController extends BaseApiController
|
|||||||
#[OA\Patch(description: 'Update an existing activity, you can pass all or just a subset of all attributes', responses: [new OA\Response(response: 200, description: 'Returns the updated activity', content: new OA\JsonContent(ref: '#/components/schemas/ActivityEntity'))])]
|
#[OA\Patch(description: 'Update an existing activity, you can pass all or just a subset of all attributes', responses: [new OA\Response(response: 200, description: 'Returns the updated activity', content: new OA\JsonContent(ref: '#/components/schemas/ActivityEntity'))])]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ActivityEditForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ActivityEditForm'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Activity ID to update', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Activity ID to update', required: true)]
|
||||||
#[Rest\Patch(path: '/{id}', name: 'patch_activity', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['PATCH'], path: '/{id}', name: 'patch_activity', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function patchAction(Request $request, Activity $activity): Response
|
public function patchAction(Request $request, Activity $activity): Response
|
||||||
@@ -221,7 +221,7 @@ final class ActivityController extends BaseApiController
|
|||||||
#[IsGranted('edit', 'activity')]
|
#[IsGranted('edit', 'activity')]
|
||||||
#[OA\Response(response: 200, description: 'Sets the value of an existing/configured meta-field. You cannot create unknown meta-fields, if the given name is not a configured meta-field, this will return an exception.', content: new OA\JsonContent(ref: '#/components/schemas/ActivityEntity'))]
|
#[OA\Response(response: 200, description: 'Sets the value of an existing/configured meta-field. You cannot create unknown meta-fields, if the given name is not a configured meta-field, this will return an exception.', content: new OA\JsonContent(ref: '#/components/schemas/ActivityEntity'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Activity record ID to set the meta-field value for', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Activity record ID to set the meta-field value for', required: true)]
|
||||||
#[Rest\Patch(path: '/{id}/meta', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['PATCH'], path: '/{id}/meta', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\RequestParam(name: 'name', strict: true, nullable: false, description: 'The meta-field name')]
|
#[Rest\RequestParam(name: 'name', strict: true, nullable: false, description: 'The meta-field name')]
|
||||||
@@ -254,7 +254,7 @@ final class ActivityController extends BaseApiController
|
|||||||
#[IsGranted('edit', 'activity')]
|
#[IsGranted('edit', 'activity')]
|
||||||
#[OA\Response(response: 200, description: 'Returns a collection of activity rate entities', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/ActivityRate')))]
|
#[OA\Response(response: 200, description: 'Returns a collection of activity rate entities', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/ActivityRate')))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'The activity whose rates will be returned', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'The activity whose rates will be returned', required: true)]
|
||||||
#[Rest\Get(path: '/{id}/rates', name: 'get_activity_rates', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/{id}/rates', name: 'get_activity_rates', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function getRatesAction(Activity $activity): Response
|
public function getRatesAction(Activity $activity): Response
|
||||||
@@ -276,7 +276,7 @@ final class ActivityController extends BaseApiController
|
|||||||
#[OA\Parameter(name: 'rateId', in: 'path', description: 'The rate to remove', required: true)]
|
#[OA\Parameter(name: 'rateId', in: 'path', description: 'The rate to remove', required: true)]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\Delete(path: '/{id}/rates/{rateId}', name: 'delete_activity_rate', requirements: ['id' => '\d+', 'rateId' => '\d+'])]
|
#[Route(methods: ['DELETE'], path: '/{id}/rates/{rateId}', name: 'delete_activity_rate', requirements: ['id' => '\d+', 'rateId' => '\d+'])]
|
||||||
public function deleteRateAction(Activity $activity, #[MapEntity(mapping: ['rateId' => 'id'])] ActivityRate $rate): Response
|
public function deleteRateAction(Activity $activity, #[MapEntity(mapping: ['rateId' => 'id'])] ActivityRate $rate): Response
|
||||||
{
|
{
|
||||||
if ($rate->getActivity() !== $activity) {
|
if ($rate->getActivity() !== $activity) {
|
||||||
@@ -297,7 +297,7 @@ final class ActivityController extends BaseApiController
|
|||||||
#[OA\Post(responses: [new OA\Response(response: 200, description: 'Returns the new created rate', content: new OA\JsonContent(ref: '#/components/schemas/ActivityRate'))])]
|
#[OA\Post(responses: [new OA\Response(response: 200, description: 'Returns the new created rate', content: new OA\JsonContent(ref: '#/components/schemas/ActivityRate'))])]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'The activity to add the rate for', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'The activity to add the rate for', required: true)]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ActivityRateForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ActivityRateForm'))]
|
||||||
#[Rest\Post(path: '/{id}/rates', name: 'post_activity_rate', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['POST'], path: '/{id}/rates', name: 'post_activity_rate', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function postRateAction(Activity $activity, Request $request): Response
|
public function postRateAction(Activity $activity, Request $request): Response
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ namespace App\API;
|
|||||||
|
|
||||||
use App\API\Model\TimesheetConfig;
|
use App\API\Model\TimesheetConfig;
|
||||||
use App\Configuration\SystemConfiguration;
|
use App\Configuration\SystemConfiguration;
|
||||||
use FOS\RestBundle\Controller\Annotations as Rest;
|
|
||||||
use FOS\RestBundle\View\View;
|
use FOS\RestBundle\View\View;
|
||||||
use FOS\RestBundle\View\ViewHandlerInterface;
|
use FOS\RestBundle\View\ViewHandlerInterface;
|
||||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||||
use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity;
|
use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity;
|
||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OA;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
#[IsGranted('IS_AUTHENTICATED_REMEMBERED')]
|
#[IsGranted('IS_AUTHENTICATED_REMEMBERED')]
|
||||||
@@ -32,7 +32,7 @@ final class ConfigurationController extends BaseApiController
|
|||||||
* Returns the timesheet configuration
|
* Returns the timesheet configuration
|
||||||
*/
|
*/
|
||||||
#[OA\Response(response: 200, description: 'Returns the instance specific timesheet configuration', content: new OA\JsonContent(ref: new Model(type: TimesheetConfig::class)))]
|
#[OA\Response(response: 200, description: 'Returns the instance specific timesheet configuration', content: new OA\JsonContent(ref: new Model(type: TimesheetConfig::class)))]
|
||||||
#[Rest\Get(path: '/config/timesheet')]
|
#[Route(methods: ['GET'], path: '/config/timesheet')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function timesheetConfigAction(SystemConfiguration $configuration): Response
|
public function timesheetConfigAction(SystemConfiguration $configuration): Response
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ use Psr\EventDispatcher\EventDispatcherInterface;
|
|||||||
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
|
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
#[Route(path: '/customers')]
|
#[Route(path: '/customers')]
|
||||||
@@ -55,7 +55,7 @@ final class CustomerController extends BaseApiController
|
|||||||
* Returns a collection of customers (which are visible to the user)
|
* Returns a collection of customers (which are visible to the user)
|
||||||
*/
|
*/
|
||||||
#[OA\Response(response: 200, description: 'Returns a collection of customers', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/CustomerCollection')))]
|
#[OA\Response(response: 200, description: 'Returns a collection of customers', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/CustomerCollection')))]
|
||||||
#[Rest\Get(path: '', name: 'get_customers')]
|
#[Route(methods: ['GET'], path: '', name: 'get_customers')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\QueryParam(name: 'visible', requirements: '1|2|3', default: 1, strict: true, nullable: true, description: 'Visibility status to filter customers: 1=visible, 2=hidden, 3=both')]
|
#[Rest\QueryParam(name: 'visible', requirements: '1|2|3', default: 1, strict: true, nullable: true, description: 'Visibility status to filter customers: 1=visible, 2=hidden, 3=both')]
|
||||||
@@ -102,7 +102,7 @@ final class CustomerController extends BaseApiController
|
|||||||
* Returns one customer
|
* Returns one customer
|
||||||
*/
|
*/
|
||||||
#[OA\Response(response: 200, description: 'Returns one customer entity', content: new OA\JsonContent(ref: '#/components/schemas/CustomerEntity'))]
|
#[OA\Response(response: 200, description: 'Returns one customer entity', content: new OA\JsonContent(ref: '#/components/schemas/CustomerEntity'))]
|
||||||
#[Rest\Get(path: '/{id}', name: 'get_customer', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/{id}', name: 'get_customer', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function getAction(Customer $customer): Response
|
public function getAction(Customer $customer): Response
|
||||||
@@ -118,7 +118,7 @@ final class CustomerController extends BaseApiController
|
|||||||
*/
|
*/
|
||||||
#[OA\Post(description: 'Creates a new customer and returns it afterwards', responses: [new OA\Response(response: 200, description: 'Returns the new created customer', content: new OA\JsonContent(ref: '#/components/schemas/CustomerEntity'))])]
|
#[OA\Post(description: 'Creates a new customer and returns it afterwards', responses: [new OA\Response(response: 200, description: 'Returns the new created customer', content: new OA\JsonContent(ref: '#/components/schemas/CustomerEntity'))])]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/CustomerEditForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/CustomerEditForm'))]
|
||||||
#[Rest\Post(path: '', name: 'post_customer')]
|
#[Route(methods: ['POST'], path: '', name: 'post_customer')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function postAction(Request $request, CustomerService $customerService): Response
|
public function postAction(Request $request, CustomerService $customerService): Response
|
||||||
@@ -161,7 +161,7 @@ final class CustomerController extends BaseApiController
|
|||||||
#[OA\Patch(description: 'Update an existing customer, you can pass all or just a subset of all attributes', responses: [new OA\Response(response: 200, description: 'Returns the updated customer', content: new OA\JsonContent(ref: '#/components/schemas/CustomerEntity'))])]
|
#[OA\Patch(description: 'Update an existing customer, you can pass all or just a subset of all attributes', responses: [new OA\Response(response: 200, description: 'Returns the updated customer', content: new OA\JsonContent(ref: '#/components/schemas/CustomerEntity'))])]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/CustomerEditForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/CustomerEditForm'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Customer ID to update', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Customer ID to update', required: true)]
|
||||||
#[Rest\Patch(path: '/{id}', name: 'patch_customer', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['PATCH'], path: '/{id}', name: 'patch_customer', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function patchAction(Request $request, Customer $customer): Response
|
public function patchAction(Request $request, Customer $customer): Response
|
||||||
@@ -198,7 +198,7 @@ final class CustomerController extends BaseApiController
|
|||||||
#[IsGranted('edit', 'customer')]
|
#[IsGranted('edit', 'customer')]
|
||||||
#[OA\Response(response: 200, description: 'Sets the value of an existing/configured meta-field. You cannot create unknown meta-fields, if the given name is not a configured meta-field, this will return an exception.', content: new OA\JsonContent(ref: '#/components/schemas/CustomerEntity'))]
|
#[OA\Response(response: 200, description: 'Sets the value of an existing/configured meta-field. You cannot create unknown meta-fields, if the given name is not a configured meta-field, this will return an exception.', content: new OA\JsonContent(ref: '#/components/schemas/CustomerEntity'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Customer record ID to set the meta-field value for', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Customer record ID to set the meta-field value for', required: true)]
|
||||||
#[Rest\Patch(path: '/{id}/meta', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['PATCH'], path: '/{id}/meta', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\RequestParam(name: 'name', strict: true, nullable: false, description: 'The meta-field name')]
|
#[Rest\RequestParam(name: 'name', strict: true, nullable: false, description: 'The meta-field name')]
|
||||||
@@ -231,7 +231,7 @@ final class CustomerController extends BaseApiController
|
|||||||
#[IsGranted('edit', 'customer')]
|
#[IsGranted('edit', 'customer')]
|
||||||
#[OA\Response(response: 200, description: 'Returns a collection of customer rate entities', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/CustomerRate')))]
|
#[OA\Response(response: 200, description: 'Returns a collection of customer rate entities', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/CustomerRate')))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'The customer whose rates will be returned', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'The customer whose rates will be returned', required: true)]
|
||||||
#[Rest\Get(path: '/{id}/rates', name: 'get_customer_rates', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/{id}/rates', name: 'get_customer_rates', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function getRatesAction(Customer $customer): Response
|
public function getRatesAction(Customer $customer): Response
|
||||||
@@ -253,7 +253,7 @@ final class CustomerController extends BaseApiController
|
|||||||
#[OA\Parameter(name: 'rateId', in: 'path', description: 'The rate to remove', required: true)]
|
#[OA\Parameter(name: 'rateId', in: 'path', description: 'The rate to remove', required: true)]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\Delete(path: '/{id}/rates/{rateId}', name: 'delete_customer_rate', requirements: ['id' => '\d+', 'rateId' => '\d+'])]
|
#[Route(methods: ['DELETE'], path: '/{id}/rates/{rateId}', name: 'delete_customer_rate', requirements: ['id' => '\d+', 'rateId' => '\d+'])]
|
||||||
public function deleteRateAction(Customer $customer, #[MapEntity(mapping: ['rateId' => 'id'])] CustomerRate $rate): Response
|
public function deleteRateAction(Customer $customer, #[MapEntity(mapping: ['rateId' => 'id'])] CustomerRate $rate): Response
|
||||||
{
|
{
|
||||||
if ($rate->getCustomer() !== $customer) {
|
if ($rate->getCustomer() !== $customer) {
|
||||||
@@ -274,7 +274,7 @@ final class CustomerController extends BaseApiController
|
|||||||
#[OA\Post(responses: [new OA\Response(response: 200, description: 'Returns the new created rate', content: new OA\JsonContent(ref: '#/components/schemas/CustomerRate'))])]
|
#[OA\Post(responses: [new OA\Response(response: 200, description: 'Returns the new created rate', content: new OA\JsonContent(ref: '#/components/schemas/CustomerRate'))])]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'The customer to add the rate for', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'The customer to add the rate for', required: true)]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/CustomerRateForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/CustomerRateForm'))]
|
||||||
#[Rest\Post(path: '/{id}/rates', name: 'post_customer_rate', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['POST'], path: '/{id}/rates', name: 'post_customer_rate', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function postRateAction(Customer $customer, Request $request): Response
|
public function postRateAction(Customer $customer, Request $request): Response
|
||||||
|
|||||||
@@ -48,15 +48,15 @@ final class CalendarEvent
|
|||||||
*/
|
*/
|
||||||
#[Serializer\Expose]
|
#[Serializer\Expose]
|
||||||
#[Serializer\Groups(['Default'])]
|
#[Serializer\Groups(['Default'])]
|
||||||
#[Serializer\Type(name: 'DateTime')]
|
#[Serializer\Type(name: 'DateTimeImmutable')]
|
||||||
private \DateTimeInterface $start; // @phpstan-ignore-line
|
private \DateTimeImmutable $start; // @phpstan-ignore-line
|
||||||
/**
|
/**
|
||||||
* Calendar entry end date
|
* Calendar entry end date
|
||||||
*/
|
*/
|
||||||
#[Serializer\Expose]
|
#[Serializer\Expose]
|
||||||
#[Serializer\Groups(['Default'])]
|
#[Serializer\Groups(['Default'])]
|
||||||
#[Serializer\Type(name: 'DateTime')]
|
#[Serializer\Type(name: 'DateTimeImmutable')]
|
||||||
private \DateTimeInterface $end; // @phpstan-ignore-line
|
private \DateTimeImmutable $end; // @phpstan-ignore-line
|
||||||
|
|
||||||
public function setTitle(string $title): void
|
public function setTitle(string $title): void
|
||||||
{
|
{
|
||||||
@@ -65,12 +65,12 @@ final class CalendarEvent
|
|||||||
|
|
||||||
public function setStart(\DateTimeInterface $start): void
|
public function setStart(\DateTimeInterface $start): void
|
||||||
{
|
{
|
||||||
$this->start = $start;
|
$this->start = \DateTimeImmutable::createFromInterface($start);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setEnd(\DateTimeInterface $end): void
|
public function setEnd(\DateTimeInterface $end): void
|
||||||
{
|
{
|
||||||
$this->end = $end;
|
$this->end = \DateTimeImmutable::createFromInterface($end);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setColor(?string $color): void
|
public function setColor(?string $color): void
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ use Psr\EventDispatcher\EventDispatcherInterface;
|
|||||||
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
|
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
use Symfony\Component\Validator\Constraints;
|
use Symfony\Component\Validator\Constraints;
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ final class ProjectController extends BaseApiController
|
|||||||
* Returns a collection of projects (which are visible to the user)
|
* Returns a collection of projects (which are visible to the user)
|
||||||
*/
|
*/
|
||||||
#[OA\Response(response: 200, description: 'Returns a collection of projects', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/ProjectCollection')))]
|
#[OA\Response(response: 200, description: 'Returns a collection of projects', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/ProjectCollection')))]
|
||||||
#[Rest\Get(path: '', name: 'get_projects')]
|
#[Route(methods: ['GET'], path: '', name: 'get_projects')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\QueryParam(name: 'customer', requirements: '\d+', strict: true, nullable: true, description: 'Customer ID to filter projects')]
|
#[Rest\QueryParam(name: 'customer', requirements: '\d+', strict: true, nullable: true, description: 'Customer ID to filter projects')]
|
||||||
@@ -156,7 +156,7 @@ final class ProjectController extends BaseApiController
|
|||||||
* Returns one project
|
* Returns one project
|
||||||
*/
|
*/
|
||||||
#[OA\Response(response: 200, description: 'Returns one project entity', content: new OA\JsonContent(ref: '#/components/schemas/ProjectEntity'))]
|
#[OA\Response(response: 200, description: 'Returns one project entity', content: new OA\JsonContent(ref: '#/components/schemas/ProjectEntity'))]
|
||||||
#[Rest\Get(path: '/{id}', name: 'get_project', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/{id}', name: 'get_project', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function getAction(Project $project): Response
|
public function getAction(Project $project): Response
|
||||||
@@ -172,7 +172,7 @@ final class ProjectController extends BaseApiController
|
|||||||
*/
|
*/
|
||||||
#[OA\Post(description: 'Creates a new project and returns it afterwards', responses: [new OA\Response(response: 200, description: 'Returns the new created project', content: new OA\JsonContent(ref: '#/components/schemas/ProjectEntity'))])]
|
#[OA\Post(description: 'Creates a new project and returns it afterwards', responses: [new OA\Response(response: 200, description: 'Returns the new created project', content: new OA\JsonContent(ref: '#/components/schemas/ProjectEntity'))])]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ProjectEditForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ProjectEditForm'))]
|
||||||
#[Rest\Post(path: '', name: 'post_project')]
|
#[Route(methods: ['POST'], path: '', name: 'post_project')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function postAction(Request $request): Response
|
public function postAction(Request $request): Response
|
||||||
@@ -214,7 +214,7 @@ final class ProjectController extends BaseApiController
|
|||||||
#[OA\Patch(description: 'Update an existing project, you can pass all or just a subset of all attributes', responses: [new OA\Response(response: 200, description: 'Returns the updated project', content: new OA\JsonContent(ref: '#/components/schemas/ProjectEntity'))])]
|
#[OA\Patch(description: 'Update an existing project, you can pass all or just a subset of all attributes', responses: [new OA\Response(response: 200, description: 'Returns the updated project', content: new OA\JsonContent(ref: '#/components/schemas/ProjectEntity'))])]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ProjectEditForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ProjectEditForm'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Project ID to update', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Project ID to update', required: true)]
|
||||||
#[Rest\Patch(path: '/{id}', name: 'patch_project', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['PATCH'], path: '/{id}', name: 'patch_project', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function patchAction(Request $request, Project $project): Response
|
public function patchAction(Request $request, Project $project): Response
|
||||||
@@ -253,7 +253,7 @@ final class ProjectController extends BaseApiController
|
|||||||
#[IsGranted('edit', 'project')]
|
#[IsGranted('edit', 'project')]
|
||||||
#[OA\Response(response: 200, description: 'Sets the value of an existing/configured meta-field. You cannot create unknown meta-fields, if the given name is not a configured meta-field, this will return an exception.', content: new OA\JsonContent(ref: '#/components/schemas/ProjectEntity'))]
|
#[OA\Response(response: 200, description: 'Sets the value of an existing/configured meta-field. You cannot create unknown meta-fields, if the given name is not a configured meta-field, this will return an exception.', content: new OA\JsonContent(ref: '#/components/schemas/ProjectEntity'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Project record ID to set the meta-field value for', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Project record ID to set the meta-field value for', required: true)]
|
||||||
#[Rest\Patch(path: '/{id}/meta', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['PATCH'], path: '/{id}/meta', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\RequestParam(name: 'name', strict: true, nullable: false, description: 'The meta-field name')]
|
#[Rest\RequestParam(name: 'name', strict: true, nullable: false, description: 'The meta-field name')]
|
||||||
@@ -286,7 +286,7 @@ final class ProjectController extends BaseApiController
|
|||||||
#[IsGranted('edit', 'project')]
|
#[IsGranted('edit', 'project')]
|
||||||
#[OA\Response(response: 200, description: 'Returns a collection of project rate entities', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/ProjectRate')))]
|
#[OA\Response(response: 200, description: 'Returns a collection of project rate entities', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/ProjectRate')))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'The project whose rates will be returned', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'The project whose rates will be returned', required: true)]
|
||||||
#[Rest\Get(path: '/{id}/rates', name: 'get_project_rates', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/{id}/rates', name: 'get_project_rates', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function getRatesAction(Project $project): Response
|
public function getRatesAction(Project $project): Response
|
||||||
@@ -308,7 +308,7 @@ final class ProjectController extends BaseApiController
|
|||||||
#[OA\Parameter(name: 'rateId', in: 'path', description: 'The rate to remove', required: true)]
|
#[OA\Parameter(name: 'rateId', in: 'path', description: 'The rate to remove', required: true)]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\Delete(path: '/{id}/rates/{rateId}', name: 'delete_project_rate', requirements: ['id' => '\d+', 'rateId' => '\d+'])]
|
#[Route(methods: ['DELETE'], path: '/{id}/rates/{rateId}', name: 'delete_project_rate', requirements: ['id' => '\d+', 'rateId' => '\d+'])]
|
||||||
public function deleteRateAction(Project $project, #[MapEntity(mapping: ['rateId' => 'id'])] ProjectRate $rate): Response
|
public function deleteRateAction(Project $project, #[MapEntity(mapping: ['rateId' => 'id'])] ProjectRate $rate): Response
|
||||||
{
|
{
|
||||||
if ($rate->getProject() !== $project) {
|
if ($rate->getProject() !== $project) {
|
||||||
@@ -329,7 +329,7 @@ final class ProjectController extends BaseApiController
|
|||||||
#[OA\Post(responses: [new OA\Response(response: 200, description: 'Returns the new created rate', content: new OA\JsonContent(ref: '#/components/schemas/ProjectRate'))])]
|
#[OA\Post(responses: [new OA\Response(response: 200, description: 'Returns the new created rate', content: new OA\JsonContent(ref: '#/components/schemas/ProjectRate'))])]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'The project to add the rate for', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'The project to add the rate for', required: true)]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ProjectRateForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/ProjectRateForm'))]
|
||||||
#[Rest\Post(path: '/{id}/rates', name: 'post_project_rate', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['POST'], path: '/{id}/rates', name: 'post_project_rate', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function postRateAction(Project $project, Request $request): Response
|
public function postRateAction(Project $project, Request $request): Response
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ namespace App\API;
|
|||||||
use App\API\Model\Plugin;
|
use App\API\Model\Plugin;
|
||||||
use App\API\Model\Version;
|
use App\API\Model\Version;
|
||||||
use App\Plugin\PluginManager;
|
use App\Plugin\PluginManager;
|
||||||
use FOS\RestBundle\Controller\Annotations as Rest;
|
|
||||||
use FOS\RestBundle\View\View;
|
use FOS\RestBundle\View\View;
|
||||||
use FOS\RestBundle\View\ViewHandlerInterface;
|
use FOS\RestBundle\View\ViewHandlerInterface;
|
||||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||||
use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity;
|
use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity;
|
||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OA;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
#[IsGranted('IS_AUTHENTICATED_REMEMBERED')]
|
#[IsGranted('IS_AUTHENTICATED_REMEMBERED')]
|
||||||
@@ -33,7 +33,7 @@ final class StatusController extends BaseApiController
|
|||||||
* A testing route for the API
|
* A testing route for the API
|
||||||
*/
|
*/
|
||||||
#[OA\Response(response: 200, description: "A simple route that returns a 'pong', which you can use for testing the API", content: new OA\JsonContent(example: "{'message': 'pong'}"))]
|
#[OA\Response(response: 200, description: "A simple route that returns a 'pong', which you can use for testing the API", content: new OA\JsonContent(example: "{'message': 'pong'}"))]
|
||||||
#[Rest\Get(path: '/ping')]
|
#[Route(methods: ['GET'], path: '/ping')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function pingAction(): Response
|
public function pingAction(): Response
|
||||||
@@ -47,7 +47,7 @@ final class StatusController extends BaseApiController
|
|||||||
* Returns information about the Kimai release
|
* Returns information about the Kimai release
|
||||||
*/
|
*/
|
||||||
#[OA\Response(response: 200, description: 'Returns version information about the current release', content: new OA\JsonContent(ref: new Model(type: Version::class)))]
|
#[OA\Response(response: 200, description: 'Returns version information about the current release', content: new OA\JsonContent(ref: new Model(type: Version::class)))]
|
||||||
#[Rest\Get(path: '/version')]
|
#[Route(methods: ['GET'], path: '/version')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function versionAction(): Response
|
public function versionAction(): Response
|
||||||
@@ -59,7 +59,7 @@ final class StatusController extends BaseApiController
|
|||||||
* Returns information about installed Plugins
|
* Returns information about installed Plugins
|
||||||
*/
|
*/
|
||||||
#[OA\Response(response: 200, description: 'Returns a list of plugin names and versions', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: new Model(type: Plugin::class))))]
|
#[OA\Response(response: 200, description: 'Returns a list of plugin names and versions', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: new Model(type: Plugin::class))))]
|
||||||
#[Rest\Get(path: '/plugins')]
|
#[Route(methods: ['GET'], path: '/plugins')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function pluginAction(PluginManager $pluginManager): Response
|
public function pluginAction(PluginManager $pluginManager): Response
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity;
|
|||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OA;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
#[Route(path: '/tags')]
|
#[Route(path: '/tags')]
|
||||||
@@ -40,7 +40,7 @@ final class TagController extends BaseApiController
|
|||||||
* Fetch all existing tags
|
* Fetch all existing tags
|
||||||
*/
|
*/
|
||||||
#[OA\Response(response: 200, description: 'Returns the collection of all existing tags as string array', content: new OA\JsonContent(type: 'array', items: new OA\Items(type: 'string')))]
|
#[OA\Response(response: 200, description: 'Returns the collection of all existing tags as string array', content: new OA\JsonContent(type: 'array', items: new OA\Items(type: 'string')))]
|
||||||
#[Rest\Get(name: 'get_tags')]
|
#[Route(methods: ['GET'], name: 'get_tags')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\QueryParam(name: 'name', strict: true, nullable: true, description: 'Search term to filter tag list')]
|
#[Rest\QueryParam(name: 'name', strict: true, nullable: true, description: 'Search term to filter tag list')]
|
||||||
@@ -61,7 +61,7 @@ final class TagController extends BaseApiController
|
|||||||
*/
|
*/
|
||||||
#[OA\Post(description: 'Creates a new tag and returns it afterwards', responses: [new OA\Response(response: 200, description: 'Returns the new created tag', content: new OA\JsonContent(ref: '#/components/schemas/TagEntity'))])]
|
#[OA\Post(description: 'Creates a new tag and returns it afterwards', responses: [new OA\Response(response: 200, description: 'Returns the new created tag', content: new OA\JsonContent(ref: '#/components/schemas/TagEntity'))])]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/TagEditForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/TagEditForm'))]
|
||||||
#[Rest\Post(name: 'post_tag')]
|
#[Route(methods: ['POST'], name: 'post_tag')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function postAction(Request $request): Response
|
public function postAction(Request $request): Response
|
||||||
@@ -99,7 +99,7 @@ final class TagController extends BaseApiController
|
|||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Tag ID to delete', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Tag ID to delete', required: true)]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\Delete(path: '/{id}', name: 'delete_tag')]
|
#[Route(methods: ['DELETE'], path: '/{id}', name: 'delete_tag')]
|
||||||
public function deleteAction(Tag $tag): Response
|
public function deleteAction(Tag $tag): Response
|
||||||
{
|
{
|
||||||
$this->repository->deleteTag($tag);
|
$this->repository->deleteTag($tag);
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ use App\Repository\ActivityRepository;
|
|||||||
use App\Repository\CustomerRepository;
|
use App\Repository\CustomerRepository;
|
||||||
use App\Repository\ProjectRepository;
|
use App\Repository\ProjectRepository;
|
||||||
use App\Repository\TeamRepository;
|
use App\Repository\TeamRepository;
|
||||||
use FOS\RestBundle\Controller\Annotations as Rest;
|
|
||||||
use FOS\RestBundle\View\View;
|
use FOS\RestBundle\View\View;
|
||||||
use FOS\RestBundle\View\ViewHandlerInterface;
|
use FOS\RestBundle\View\ViewHandlerInterface;
|
||||||
use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity;
|
use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity;
|
||||||
@@ -28,7 +27,7 @@ use Symfony\Bridge\Doctrine\Attribute\MapEntity;
|
|||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
#[Route(path: '/teams')]
|
#[Route(path: '/teams')]
|
||||||
@@ -49,7 +48,7 @@ final class TeamController extends BaseApiController
|
|||||||
*/
|
*/
|
||||||
#[IsGranted('view_team')]
|
#[IsGranted('view_team')]
|
||||||
#[OA\Response(response: 200, description: 'Returns the collection of teams', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/TeamCollection')))]
|
#[OA\Response(response: 200, description: 'Returns the collection of teams', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/TeamCollection')))]
|
||||||
#[Rest\Get(path: '', name: 'get_teams')]
|
#[Route(methods: ['GET'], path: '', name: 'get_teams')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function cgetAction(): Response
|
public function cgetAction(): Response
|
||||||
@@ -67,7 +66,7 @@ final class TeamController extends BaseApiController
|
|||||||
*/
|
*/
|
||||||
#[IsGranted('view_team')]
|
#[IsGranted('view_team')]
|
||||||
#[OA\Response(response: 200, description: 'Returns one team entity', content: new OA\JsonContent(ref: '#/components/schemas/Team'))]
|
#[OA\Response(response: 200, description: 'Returns one team entity', content: new OA\JsonContent(ref: '#/components/schemas/Team'))]
|
||||||
#[Rest\Get(path: '/{id}', name: 'get_team', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/{id}', name: 'get_team', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function getAction(Team $team): Response
|
public function getAction(Team $team): Response
|
||||||
@@ -86,7 +85,7 @@ final class TeamController extends BaseApiController
|
|||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Team ID to delete', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Team ID to delete', required: true)]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\Delete(path: '/{id}', name: 'delete_team', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['DELETE'], path: '/{id}', name: 'delete_team', requirements: ['id' => '\d+'])]
|
||||||
public function deleteAction(Team $team): Response
|
public function deleteAction(Team $team): Response
|
||||||
{
|
{
|
||||||
$this->repository->deleteTeam($team);
|
$this->repository->deleteTeam($team);
|
||||||
@@ -102,7 +101,7 @@ final class TeamController extends BaseApiController
|
|||||||
#[IsGranted('create_team')]
|
#[IsGranted('create_team')]
|
||||||
#[OA\Post(description: 'Creates a new team and returns it afterwards', responses: [new OA\Response(response: 200, description: 'Returns the new created team', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])]
|
#[OA\Post(description: 'Creates a new team and returns it afterwards', responses: [new OA\Response(response: 200, description: 'Returns the new created team', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/TeamEditForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/TeamEditForm'))]
|
||||||
#[Rest\Post(path: '', name: 'post_team')]
|
#[Route(methods: ['POST'], path: '', name: 'post_team')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function postAction(Request $request): Response
|
public function postAction(Request $request): Response
|
||||||
@@ -134,7 +133,7 @@ final class TeamController extends BaseApiController
|
|||||||
#[OA\Patch(description: 'Update an existing team, you can pass all or just a subset of all attributes (passing members will replace all existing ones)', responses: [new OA\Response(response: 200, description: 'Returns the updated team', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])]
|
#[OA\Patch(description: 'Update an existing team, you can pass all or just a subset of all attributes (passing members will replace all existing ones)', responses: [new OA\Response(response: 200, description: 'Returns the updated team', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/TeamEditForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/TeamEditForm'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Team ID to update', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Team ID to update', required: true)]
|
||||||
#[Rest\Patch(path: '/{id}', name: 'patch_team', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['PATCH'], path: '/{id}', name: 'patch_team', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function patchAction(Request $request, Team $team): Response
|
public function patchAction(Request $request, Team $team): Response
|
||||||
@@ -174,7 +173,7 @@ final class TeamController extends BaseApiController
|
|||||||
#[OA\Post(responses: [new OA\Response(response: 200, description: 'Adds a new user to a team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])]
|
#[OA\Post(responses: [new OA\Response(response: 200, description: 'Adds a new user to a team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'The team which will receive the new member', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'The team which will receive the new member', required: true)]
|
||||||
#[OA\Parameter(name: 'userId', in: 'path', description: 'The team member to add (User ID)', required: true)]
|
#[OA\Parameter(name: 'userId', in: 'path', description: 'The team member to add (User ID)', required: true)]
|
||||||
#[Rest\Post(path: '/{id}/members/{userId}', name: 'post_team_member', requirements: ['id' => '\d+', 'userId' => '\d+'])]
|
#[Route(methods: ['POST'], path: '/{id}/members/{userId}', name: 'post_team_member', requirements: ['id' => '\d+', 'userId' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function postMemberAction(Team $team, #[MapEntity(mapping: ['userId' => 'id'])] User $member): Response
|
public function postMemberAction(Team $team, #[MapEntity(mapping: ['userId' => 'id'])] User $member): Response
|
||||||
@@ -202,7 +201,7 @@ final class TeamController extends BaseApiController
|
|||||||
#[OA\Parameter(name: 'userId', in: 'path', description: 'The team member to remove (User ID)', required: true)]
|
#[OA\Parameter(name: 'userId', in: 'path', description: 'The team member to remove (User ID)', required: true)]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\Delete(path: '/{id}/members/{userId}', name: 'delete_team_member', requirements: ['id' => '\d+', 'userId' => '\d+'])]
|
#[Route(methods: ['DELETE'], path: '/{id}/members/{userId}', name: 'delete_team_member', requirements: ['id' => '\d+', 'userId' => '\d+'])]
|
||||||
public function deleteMemberAction(Team $team, #[MapEntity(mapping: ['userId' => 'id'])] User $member): Response
|
public function deleteMemberAction(Team $team, #[MapEntity(mapping: ['userId' => 'id'])] User $member): Response
|
||||||
{
|
{
|
||||||
if (!$member->isInTeam($team)) {
|
if (!$member->isInTeam($team)) {
|
||||||
@@ -230,7 +229,7 @@ final class TeamController extends BaseApiController
|
|||||||
#[OA\Post(responses: [new OA\Response(response: 200, description: 'Adds a new customer to a team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])]
|
#[OA\Post(responses: [new OA\Response(response: 200, description: 'Adds a new customer to a team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'The team that is granted access', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'The team that is granted access', required: true)]
|
||||||
#[OA\Parameter(name: 'customerId', in: 'path', description: 'The customer to grant acecess to (Customer ID)', required: true)]
|
#[OA\Parameter(name: 'customerId', in: 'path', description: 'The customer to grant acecess to (Customer ID)', required: true)]
|
||||||
#[Rest\Post(path: '/{id}/customers/{customerId}', name: 'post_team_customer', requirements: ['id' => '\d+', 'customerId' => '\d+'])]
|
#[Route(methods: ['POST'], path: '/{id}/customers/{customerId}', name: 'post_team_customer', requirements: ['id' => '\d+', 'customerId' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function postCustomerAction(Team $team, #[MapEntity(mapping: ['customerId' => 'id'])] Customer $customer, CustomerRepository $customerRepository): Response
|
public function postCustomerAction(Team $team, #[MapEntity(mapping: ['customerId' => 'id'])] Customer $customer, CustomerRepository $customerRepository): Response
|
||||||
@@ -257,7 +256,7 @@ final class TeamController extends BaseApiController
|
|||||||
#[OA\Parameter(name: 'customerId', in: 'path', description: 'The customer to remove (Customer ID)', required: true)]
|
#[OA\Parameter(name: 'customerId', in: 'path', description: 'The customer to remove (Customer ID)', required: true)]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\Delete(path: '/{id}/customers/{customerId}', name: 'delete_team_customer', requirements: ['id' => '\d+', 'customerId' => '\d+'])]
|
#[Route(methods: ['DELETE'], path: '/{id}/customers/{customerId}', name: 'delete_team_customer', requirements: ['id' => '\d+', 'customerId' => '\d+'])]
|
||||||
public function deleteCustomerAction(Team $team, #[MapEntity(mapping: ['customerId' => 'id'])] Customer $customer, CustomerRepository $customerRepository): Response
|
public function deleteCustomerAction(Team $team, #[MapEntity(mapping: ['customerId' => 'id'])] Customer $customer, CustomerRepository $customerRepository): Response
|
||||||
{
|
{
|
||||||
if (!$team->hasCustomer($customer)) {
|
if (!$team->hasCustomer($customer)) {
|
||||||
@@ -280,7 +279,7 @@ final class TeamController extends BaseApiController
|
|||||||
#[OA\Post(responses: [new OA\Response(response: 200, description: 'Adds a new project to a team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])]
|
#[OA\Post(responses: [new OA\Response(response: 200, description: 'Adds a new project to a team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'The team that is granted access', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'The team that is granted access', required: true)]
|
||||||
#[OA\Parameter(name: 'projectId', in: 'path', description: 'The project to grant acecess to (Project ID)', required: true)]
|
#[OA\Parameter(name: 'projectId', in: 'path', description: 'The project to grant acecess to (Project ID)', required: true)]
|
||||||
#[Rest\Post(path: '/{id}/projects/{projectId}', name: 'post_team_project', requirements: ['id' => '\d+', 'projectId' => '\d+'])]
|
#[Route(methods: ['POST'], path: '/{id}/projects/{projectId}', name: 'post_team_project', requirements: ['id' => '\d+', 'projectId' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function postProjectAction(Team $team, #[MapEntity(mapping: ['projectId' => 'id'])] Project $project, ProjectRepository $projectRepository): Response
|
public function postProjectAction(Team $team, #[MapEntity(mapping: ['projectId' => 'id'])] Project $project, ProjectRepository $projectRepository): Response
|
||||||
@@ -307,7 +306,7 @@ final class TeamController extends BaseApiController
|
|||||||
#[OA\Parameter(name: 'projectId', in: 'path', description: 'The project to remove (Project ID)', required: true)]
|
#[OA\Parameter(name: 'projectId', in: 'path', description: 'The project to remove (Project ID)', required: true)]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\Delete(path: '/{id}/projects/{projectId}', name: 'delete_team_project', requirements: ['id' => '\d+', 'projectId' => '\d+'])]
|
#[Route(methods: ['DELETE'], path: '/{id}/projects/{projectId}', name: 'delete_team_project', requirements: ['id' => '\d+', 'projectId' => '\d+'])]
|
||||||
public function deleteProjectAction(Team $team, #[MapEntity(mapping: ['projectId' => 'id'])] Project $project, ProjectRepository $projectRepository): Response
|
public function deleteProjectAction(Team $team, #[MapEntity(mapping: ['projectId' => 'id'])] Project $project, ProjectRepository $projectRepository): Response
|
||||||
{
|
{
|
||||||
if (!$team->hasProject($project)) {
|
if (!$team->hasProject($project)) {
|
||||||
@@ -330,7 +329,7 @@ final class TeamController extends BaseApiController
|
|||||||
#[OA\Post(responses: [new OA\Response(response: 200, description: 'Adds a new activity to a team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])]
|
#[OA\Post(responses: [new OA\Response(response: 200, description: 'Adds a new activity to a team.', content: new OA\JsonContent(ref: '#/components/schemas/Team'))])]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'The team that is granted access', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'The team that is granted access', required: true)]
|
||||||
#[OA\Parameter(name: 'activityId', in: 'path', description: 'The activity to grant acecess to (Activity ID)', required: true)]
|
#[OA\Parameter(name: 'activityId', in: 'path', description: 'The activity to grant acecess to (Activity ID)', required: true)]
|
||||||
#[Rest\Post(path: '/{id}/activities/{activityId}', name: 'post_team_activity', requirements: ['id' => '\d+', 'activityId' => '\d+'])]
|
#[Route(methods: ['POST'], path: '/{id}/activities/{activityId}', name: 'post_team_activity', requirements: ['id' => '\d+', 'activityId' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function postActivityAction(Team $team, #[MapEntity(mapping: ['activityId' => 'id'])] Activity $activity, ActivityRepository $activityRepository): Response
|
public function postActivityAction(Team $team, #[MapEntity(mapping: ['activityId' => 'id'])] Activity $activity, ActivityRepository $activityRepository): Response
|
||||||
@@ -357,7 +356,7 @@ final class TeamController extends BaseApiController
|
|||||||
#[OA\Parameter(name: 'activityId', in: 'path', description: 'The activity to remove (Activity ID)', required: true)]
|
#[OA\Parameter(name: 'activityId', in: 'path', description: 'The activity to remove (Activity ID)', required: true)]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\Delete(path: '/{id}/activities/{activityId}', name: 'delete_team_activity', requirements: ['id' => '\d+', 'activityId' => '\d+'])]
|
#[Route(methods: ['DELETE'], path: '/{id}/activities/{activityId}', name: 'delete_team_activity', requirements: ['id' => '\d+', 'activityId' => '\d+'])]
|
||||||
public function deleteActivityAction(Team $team, #[MapEntity(mapping: ['activityId' => 'id'])] Activity $activity, ActivityRepository $activityRepository): Response
|
public function deleteActivityAction(Team $team, #[MapEntity(mapping: ['activityId' => 'id'])] Activity $activity, ActivityRepository $activityRepository): Response
|
||||||
{
|
{
|
||||||
if (!$team->hasActivity($activity)) {
|
if (!$team->hasActivity($activity)) {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ use Symfony\Component\ExpressionLanguage\Expression;
|
|||||||
use Symfony\Component\Form\FormError;
|
use Symfony\Component\Form\FormError;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
use Symfony\Component\Validator\Constraints;
|
use Symfony\Component\Validator\Constraints;
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ final class TimesheetController extends BaseApiController
|
|||||||
*/
|
*/
|
||||||
#[IsGranted(new Expression("is_granted('view_own_timesheet') or is_granted('view_other_timesheet')"))]
|
#[IsGranted(new Expression("is_granted('view_own_timesheet') or is_granted('view_other_timesheet')"))]
|
||||||
#[OA\Response(response: 200, description: 'Returns a collection of timesheet records. The datetime fields are given in the users local time including the timezone offset (ISO-8601).', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/TimesheetCollection')))]
|
#[OA\Response(response: 200, description: 'Returns a collection of timesheet records. The datetime fields are given in the users local time including the timezone offset (ISO-8601).', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/TimesheetCollection')))]
|
||||||
#[Rest\Get(path: '', name: 'get_timesheets')]
|
#[Route(methods: ['GET'], path: '', name: 'get_timesheets')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\QueryParam(name: 'user', requirements: '\d+|all', strict: true, nullable: true, description: "User ID to filter timesheets. Needs permission 'view_other_timesheet', pass 'all' to fetch data for all user (default: current user)")]
|
#[Rest\QueryParam(name: 'user', requirements: '\d+|all', strict: true, nullable: true, description: "User ID to filter timesheets. Needs permission 'view_other_timesheet', pass 'all' to fetch data for all user (default: current user)")]
|
||||||
@@ -273,7 +273,7 @@ final class TimesheetController extends BaseApiController
|
|||||||
#[IsGranted('view', 'timesheet')]
|
#[IsGranted('view', 'timesheet')]
|
||||||
#[OA\Response(response: 200, description: 'Returns one timesheet record. Be aware that the datetime fields are given in the users local time including the timezone offset via ISO 8601.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))]
|
#[OA\Response(response: 200, description: 'Returns one timesheet record. Be aware that the datetime fields are given in the users local time including the timezone offset via ISO 8601.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to fetch', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to fetch', required: true)]
|
||||||
#[Rest\Get(path: '/{id}', name: 'get_timesheet', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/{id}', name: 'get_timesheet', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function getAction(Timesheet $timesheet): Response
|
public function getAction(Timesheet $timesheet): Response
|
||||||
@@ -290,7 +290,7 @@ final class TimesheetController extends BaseApiController
|
|||||||
#[IsGranted('create_own_timesheet')]
|
#[IsGranted('create_own_timesheet')]
|
||||||
#[OA\Post(description: 'Creates a new timesheet record for the current user and returns it afterwards.', responses: [new OA\Response(response: 200, description: 'Returns the new created timesheet', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))])]
|
#[OA\Post(description: 'Creates a new timesheet record for the current user and returns it afterwards.', responses: [new OA\Response(response: 200, description: 'Returns the new created timesheet', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))])]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEditForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEditForm'))]
|
||||||
#[Rest\Post(path: '', name: 'post_timesheet')]
|
#[Route(methods: ['POST'], path: '', name: 'post_timesheet')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\QueryParam(name: 'full', strict: true, nullable: true, description: 'Allows to fetch fully serialized objects including subresources (TimesheetExpanded). Allowed values: true (default: false)')]
|
#[Rest\QueryParam(name: 'full', strict: true, nullable: true, description: 'Allows to fetch fully serialized objects including subresources (TimesheetExpanded). Allowed values: true (default: false)')]
|
||||||
@@ -346,7 +346,7 @@ final class TimesheetController extends BaseApiController
|
|||||||
#[OA\Patch(description: 'Update an existing timesheet record, you can pass all or just a subset of the attributes.', responses: [new OA\Response(response: 200, description: 'Returns the updated timesheet', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))])]
|
#[OA\Patch(description: 'Update an existing timesheet record, you can pass all or just a subset of the attributes.', responses: [new OA\Response(response: 200, description: 'Returns the updated timesheet', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))])]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to update', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to update', required: true)]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEditForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEditForm'))]
|
||||||
#[Rest\Patch(path: '/{id}', name: 'patch_timesheet', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['PATCH'], path: '/{id}', name: 'patch_timesheet', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function patchAction(Request $request, Timesheet $timesheet): Response
|
public function patchAction(Request $request, Timesheet $timesheet): Response
|
||||||
@@ -392,7 +392,7 @@ final class TimesheetController extends BaseApiController
|
|||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to delete', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to delete', required: true)]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\Delete(path: '/{id}', name: 'delete_timesheet', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['DELETE'], path: '/{id}', name: 'delete_timesheet', requirements: ['id' => '\d+'])]
|
||||||
public function deleteAction(Timesheet $timesheet): Response
|
public function deleteAction(Timesheet $timesheet): Response
|
||||||
{
|
{
|
||||||
$this->service->deleteTimesheet($timesheet);
|
$this->service->deleteTimesheet($timesheet);
|
||||||
@@ -407,7 +407,7 @@ final class TimesheetController extends BaseApiController
|
|||||||
*/
|
*/
|
||||||
#[IsGranted('view_own_timesheet')]
|
#[IsGranted('view_own_timesheet')]
|
||||||
#[OA\Response(response: 200, description: 'Returns the collection of recent user activities (always the latest entry of a unique working set grouped by customer, project and activity)', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/TimesheetCollectionExpanded')))]
|
#[OA\Response(response: 200, description: 'Returns the collection of recent user activities (always the latest entry of a unique working set grouped by customer, project and activity)', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/TimesheetCollectionExpanded')))]
|
||||||
#[Rest\Get(path: '/recent', name: 'recent_timesheet')]
|
#[Route(methods: ['GET'], path: '/recent', name: 'recent_timesheet')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\QueryParam(name: 'begin', requirements: [new Constraints\DateTime(format: 'Y-m-d\TH:i:s')], strict: true, nullable: true, description: 'Only records after this date will be included. Default: today - 1 year (format: HTML5)')]
|
#[Rest\QueryParam(name: 'begin', requirements: [new Constraints\DateTime(format: 'Y-m-d\TH:i:s')], strict: true, nullable: true, description: 'Only records after this date will be included. Default: today - 1 year (format: HTML5)')]
|
||||||
@@ -443,7 +443,7 @@ final class TimesheetController extends BaseApiController
|
|||||||
*/
|
*/
|
||||||
#[IsGranted('view_own_timesheet')]
|
#[IsGranted('view_own_timesheet')]
|
||||||
#[OA\Response(response: 200, description: 'Returns the collection of active timesheet records for the current user', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/TimesheetCollectionExpanded')))]
|
#[OA\Response(response: 200, description: 'Returns the collection of active timesheet records for the current user', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/TimesheetCollectionExpanded')))]
|
||||||
#[Rest\Get(path: '/active', name: 'active_timesheet')]
|
#[Route(methods: ['GET'], path: '/active', name: 'active_timesheet')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function activeAction(): Response
|
public function activeAction(): Response
|
||||||
@@ -468,8 +468,8 @@ final class TimesheetController extends BaseApiController
|
|||||||
#[IsGranted('stop', 'timesheet')]
|
#[IsGranted('stop', 'timesheet')]
|
||||||
#[OA\Response(response: 200, description: 'Stops an active timesheet record and returns it afterwards.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))]
|
#[OA\Response(response: 200, description: 'Stops an active timesheet record and returns it afterwards.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to stop', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to stop', required: true)]
|
||||||
#[Rest\Get(path: '/{id}/stop', name: 'stop_timesheet_get', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/{id}/stop', name: 'stop_timesheet_get', requirements: ['id' => '\d+'])]
|
||||||
#[Rest\Patch(path: '/{id}/stop', name: 'stop_timesheet', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['PATCH'], path: '/{id}/stop', name: 'stop_timesheet', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function stopAction(Timesheet $timesheet): Response
|
public function stopAction(Timesheet $timesheet): Response
|
||||||
@@ -488,8 +488,8 @@ final class TimesheetController extends BaseApiController
|
|||||||
#[IsGranted('start', 'timesheet')]
|
#[IsGranted('start', 'timesheet')]
|
||||||
#[OA\Response(response: 200, description: 'Restarts a timesheet record for the same customer, project, activity combination. The current user will be the owner of the new record. Kimai tries to stop running records, which is expected to fail depending on the configured rules. Data will be copied from the original record if requested.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))]
|
#[OA\Response(response: 200, description: 'Restarts a timesheet record for the same customer, project, activity combination. The current user will be the owner of the new record. Kimai tries to stop running records, which is expected to fail depending on the configured rules. Data will be copied from the original record if requested.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to restart', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to restart', required: true)]
|
||||||
#[Rest\Get(path: '/{id}/restart', name: 'restart_timesheet_get', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/{id}/restart', name: 'restart_timesheet_get', requirements: ['id' => '\d+'])]
|
||||||
#[Rest\Patch(path: '/{id}/restart', name: 'restart_timesheet', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['PATCH'], path: '/{id}/restart', name: 'restart_timesheet', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\RequestParam(name: 'copy', requirements: 'all', strict: true, nullable: true, description: 'Whether data should be copied to the new entry. Allowed values: all (default: nothing is copied)')]
|
#[Rest\RequestParam(name: 'copy', requirements: 'all', strict: true, nullable: true, description: 'Whether data should be copied to the new entry. Allowed values: all (default: nothing is copied)')]
|
||||||
@@ -551,7 +551,7 @@ final class TimesheetController extends BaseApiController
|
|||||||
#[IsGranted('duplicate', 'timesheet')]
|
#[IsGranted('duplicate', 'timesheet')]
|
||||||
#[OA\Response(response: 200, description: 'Duplicates a timesheet record, resetting the export state only.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))]
|
#[OA\Response(response: 200, description: 'Duplicates a timesheet record, resetting the export state only.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to duplicate', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to duplicate', required: true)]
|
||||||
#[Rest\Patch(path: '/{id}/duplicate', name: 'duplicate_timesheet', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['PATCH'], path: '/{id}/duplicate', name: 'duplicate_timesheet', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function duplicateAction(Timesheet $timesheet): Response
|
public function duplicateAction(Timesheet $timesheet): Response
|
||||||
@@ -574,7 +574,7 @@ final class TimesheetController extends BaseApiController
|
|||||||
#[IsGranted('edit_export', 'timesheet')]
|
#[IsGranted('edit_export', 'timesheet')]
|
||||||
#[OA\Response(response: 200, description: 'Switches the exported state on the record and therefor locks / unlocks it for further updates. Needs edit_export_*_timesheet permission.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))]
|
#[OA\Response(response: 200, description: 'Switches the exported state on the record and therefor locks / unlocks it for further updates. Needs edit_export_*_timesheet permission.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to switch export state', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to switch export state', required: true)]
|
||||||
#[Rest\Patch(path: '/{id}/export', name: 'export_timesheet', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['PATCH'], path: '/{id}/export', name: 'export_timesheet', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function exportAction(Timesheet $timesheet): Response
|
public function exportAction(Timesheet $timesheet): Response
|
||||||
@@ -599,7 +599,7 @@ final class TimesheetController extends BaseApiController
|
|||||||
#[IsGranted('edit', 'timesheet')]
|
#[IsGranted('edit', 'timesheet')]
|
||||||
#[OA\Response(response: 200, description: 'Sets the value of an existing/configured meta-field. You cannot create unknown meta-fields, if the given name is not a configured meta-field, this will return an exception.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))]
|
#[OA\Response(response: 200, description: 'Sets the value of an existing/configured meta-field. You cannot create unknown meta-fields, if the given name is not a configured meta-field, this will return an exception.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to set the meta-field value for', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to set the meta-field value for', required: true)]
|
||||||
#[Rest\Patch(path: '/{id}/meta', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['PATCH'], path: '/{id}/meta', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\RequestParam(name: 'name', strict: true, nullable: false, description: 'The meta-field name')]
|
#[Rest\RequestParam(name: 'name', strict: true, nullable: false, description: 'The meta-field name')]
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ use Symfony\Component\HttpFoundation\Request;
|
|||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
#[Route(path: '/users')]
|
#[Route(path: '/users')]
|
||||||
@@ -54,7 +54,7 @@ final class UserController extends BaseApiController
|
|||||||
*/
|
*/
|
||||||
#[IsGranted('view_user')]
|
#[IsGranted('view_user')]
|
||||||
#[OA\Response(response: 200, description: 'Returns the collection of users. Required permission: view_user', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/UserCollection')))]
|
#[OA\Response(response: 200, description: 'Returns the collection of users. Required permission: view_user', content: new OA\JsonContent(type: 'array', items: new OA\Items(ref: '#/components/schemas/UserCollection')))]
|
||||||
#[Rest\Get(path: '', name: 'get_users')]
|
#[Route(methods: ['GET'], path: '', name: 'get_users')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
#[Rest\QueryParam(name: 'visible', requirements: '1|2|3', default: 1, strict: true, nullable: true, description: 'Visibility status to filter users: 1=visible, 2=hidden, 3=all')]
|
#[Rest\QueryParam(name: 'visible', requirements: '1|2|3', default: 1, strict: true, nullable: true, description: 'Visibility status to filter users: 1=visible, 2=hidden, 3=all')]
|
||||||
@@ -107,7 +107,7 @@ final class UserController extends BaseApiController
|
|||||||
#[IsGranted('view', 'profile')]
|
#[IsGranted('view', 'profile')]
|
||||||
#[OA\Response(response: 200, description: 'Return one user entity.', content: new OA\JsonContent(ref: '#/components/schemas/UserEntity'))]
|
#[OA\Response(response: 200, description: 'Return one user entity.', content: new OA\JsonContent(ref: '#/components/schemas/UserEntity'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'User ID to fetch', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'User ID to fetch', required: true)]
|
||||||
#[Rest\Get(path: '/{id}', name: 'get_user', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['GET'], path: '/{id}', name: 'get_user', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function getAction(User $profile, EventDispatcherInterface $dispatcher): Response
|
public function getAction(User $profile, EventDispatcherInterface $dispatcher): Response
|
||||||
@@ -126,7 +126,7 @@ final class UserController extends BaseApiController
|
|||||||
* Return the current user entity
|
* Return the current user entity
|
||||||
*/
|
*/
|
||||||
#[OA\Response(response: 200, description: 'Return the current user entity.', content: new OA\JsonContent(ref: '#/components/schemas/UserEntity'))]
|
#[OA\Response(response: 200, description: 'Return the current user entity.', content: new OA\JsonContent(ref: '#/components/schemas/UserEntity'))]
|
||||||
#[Rest\Get(path: '/me', name: 'me_user')]
|
#[Route(methods: ['GET'], path: '/me', name: 'me_user')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function meAction(): Response
|
public function meAction(): Response
|
||||||
@@ -143,7 +143,7 @@ final class UserController extends BaseApiController
|
|||||||
#[IsGranted('create_user')]
|
#[IsGranted('create_user')]
|
||||||
#[OA\Post(description: 'Creates a new user and returns it afterwards')]
|
#[OA\Post(description: 'Creates a new user and returns it afterwards')]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/UserCreateForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/UserCreateForm'))]
|
||||||
#[Rest\Post(path: '', name: 'post_user')]
|
#[Route(methods: ['POST'], path: '', name: 'post_user')]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function postAction(Request $request): Response
|
public function postAction(Request $request): Response
|
||||||
@@ -197,7 +197,7 @@ final class UserController extends BaseApiController
|
|||||||
#[OA\Patch(description: 'Update an existing user, you can pass all or just a subset of all attributes (passing roles will replace all existing ones)', responses: [new OA\Response(response: 200, description: 'Returns the updated user', content: new OA\JsonContent(ref: '#/components/schemas/UserEntity'))])]
|
#[OA\Patch(description: 'Update an existing user, you can pass all or just a subset of all attributes (passing roles will replace all existing ones)', responses: [new OA\Response(response: 200, description: 'Returns the updated user', content: new OA\JsonContent(ref: '#/components/schemas/UserEntity'))])]
|
||||||
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/UserEditForm'))]
|
#[OA\RequestBody(required: true, content: new OA\JsonContent(ref: '#/components/schemas/UserEditForm'))]
|
||||||
#[OA\Parameter(name: 'id', in: 'path', description: 'User ID to update', required: true)]
|
#[OA\Parameter(name: 'id', in: 'path', description: 'User ID to update', required: true)]
|
||||||
#[Rest\Patch(path: '/{id}', name: 'patch_user', requirements: ['id' => '\d+'])]
|
#[Route(methods: ['PATCH'], path: '/{id}', name: 'patch_user', requirements: ['id' => '\d+'])]
|
||||||
#[ApiSecurity(name: 'apiUser')]
|
#[ApiSecurity(name: 'apiUser')]
|
||||||
#[ApiSecurity(name: 'apiToken')]
|
#[ApiSecurity(name: 'apiToken')]
|
||||||
public function patchAction(Request $request, User $profile): Response
|
public function patchAction(Request $request, User $profile): Response
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ class Constants
|
|||||||
/**
|
/**
|
||||||
* The current release version
|
* The current release version
|
||||||
*/
|
*/
|
||||||
public const VERSION = '2.7.0';
|
public const VERSION = '2.8.0';
|
||||||
/**
|
/**
|
||||||
* The current release: major * 10000 + minor * 100 + patch
|
* The current release: major * 10000 + minor * 100 + patch
|
||||||
*/
|
*/
|
||||||
public const VERSION_ID = 20700;
|
public const VERSION_ID = 20800;
|
||||||
/**
|
/**
|
||||||
* The software name
|
* The software name
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -159,11 +159,7 @@ abstract class AbstractController extends BaseAbstractController implements Serv
|
|||||||
/**
|
/**
|
||||||
* Adds a fully translated (both $message and all keys in $parameter) flash message to the stack.
|
* Adds a fully translated (both $message and all keys in $parameter) flash message to the stack.
|
||||||
*
|
*
|
||||||
* @param string $type
|
|
||||||
* @param string $message
|
|
||||||
* @param array<string, string> $parameter
|
* @param array<string, string> $parameter
|
||||||
* @return void
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
*/
|
||||||
private function addFlashTranslated(string $type, string $message, array $parameter = []): void
|
private function addFlashTranslated(string $type, string $message, array $parameter = []): void
|
||||||
{
|
{
|
||||||
@@ -183,9 +179,6 @@ abstract class AbstractController extends BaseAbstractController implements Serv
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles exception flash messages for failed update/create actions.
|
* Handles exception flash messages for failed update/create actions.
|
||||||
* @param \Exception $exception
|
|
||||||
* @param FormInterface $form
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
protected function handleFormUpdateException(\Exception $exception, FormInterface $form): void
|
protected function handleFormUpdateException(\Exception $exception, FormInterface $form): void
|
||||||
{
|
{
|
||||||
@@ -262,10 +255,7 @@ abstract class AbstractController extends BaseAbstractController implements Serv
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param FormInterface $form
|
|
||||||
* @param Request $request
|
|
||||||
* @param array<string> $filterParams parameter names, which should not be saved (neither session, nor database)
|
* @param array<string> $filterParams parameter names, which should not be saved (neither session, nor database)
|
||||||
* @return bool
|
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
protected function handleSearch(FormInterface $form, Request $request, array $filterParams = []): bool
|
protected function handleSearch(FormInterface $form, Request $request, array $filterParams = []): bool
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use App\Reporting\CustomerMonthlyProjects\CustomerMonthlyProjects;
|
|||||||
use App\Reporting\CustomerMonthlyProjects\CustomerMonthlyProjectsForm;
|
use App\Reporting\CustomerMonthlyProjects\CustomerMonthlyProjectsForm;
|
||||||
use App\Reporting\CustomerMonthlyProjects\CustomerMonthlyProjectsRepository;
|
use App\Reporting\CustomerMonthlyProjects\CustomerMonthlyProjectsRepository;
|
||||||
use App\Repository\Query\UserQuery;
|
use App\Repository\Query\UserQuery;
|
||||||
|
use App\Repository\Query\VisibilityInterface;
|
||||||
use App\Repository\UserRepository;
|
use App\Repository\UserRepository;
|
||||||
use PhpOffice\PhpSpreadsheet\Reader\Html;
|
use PhpOffice\PhpSpreadsheet\Reader\Html;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
@@ -58,6 +59,7 @@ final class CustomerMonthlyProjectsController extends AbstractController
|
|||||||
$dateTimeFactory = $this->getDateTimeFactory();
|
$dateTimeFactory = $this->getDateTimeFactory();
|
||||||
|
|
||||||
$query = new UserQuery();
|
$query = new UserQuery();
|
||||||
|
$query->setVisibility(VisibilityInterface::SHOW_BOTH);
|
||||||
$query->setSystemAccount(false);
|
$query->setSystemAccount(false);
|
||||||
$query->setCurrentUser($currentUser);
|
$query->setCurrentUser($currentUser);
|
||||||
$allUsers = $userRepository->getUsersForQuery($query);
|
$allUsers = $userRepository->getUsersForQuery($query);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use App\Model\DailyStatistic;
|
|||||||
use App\Reporting\MonthlyUserList\MonthlyUserList;
|
use App\Reporting\MonthlyUserList\MonthlyUserList;
|
||||||
use App\Reporting\MonthlyUserList\MonthlyUserListForm;
|
use App\Reporting\MonthlyUserList\MonthlyUserListForm;
|
||||||
use App\Repository\Query\UserQuery;
|
use App\Repository\Query\UserQuery;
|
||||||
|
use App\Repository\Query\VisibilityInterface;
|
||||||
use App\Repository\UserRepository;
|
use App\Repository\UserRepository;
|
||||||
use App\Timesheet\TimesheetStatisticService;
|
use App\Timesheet\TimesheetStatisticService;
|
||||||
use PhpOffice\PhpSpreadsheet\Reader\Html;
|
use PhpOffice\PhpSpreadsheet\Reader\Html;
|
||||||
@@ -68,6 +69,7 @@ final class ReportUsersMonthController extends AbstractController
|
|||||||
$form->submit($request->query->all(), false);
|
$form->submit($request->query->all(), false);
|
||||||
|
|
||||||
$query = new UserQuery();
|
$query = new UserQuery();
|
||||||
|
$query->setVisibility(VisibilityInterface::SHOW_BOTH);
|
||||||
$query->setSystemAccount(false);
|
$query->setSystemAccount(false);
|
||||||
$query->setCurrentUser($currentUser);
|
$query->setCurrentUser($currentUser);
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use App\Model\DailyStatistic;
|
|||||||
use App\Reporting\WeeklyUserList\WeeklyUserList;
|
use App\Reporting\WeeklyUserList\WeeklyUserList;
|
||||||
use App\Reporting\WeeklyUserList\WeeklyUserListForm;
|
use App\Reporting\WeeklyUserList\WeeklyUserListForm;
|
||||||
use App\Repository\Query\UserQuery;
|
use App\Repository\Query\UserQuery;
|
||||||
|
use App\Repository\Query\VisibilityInterface;
|
||||||
use App\Repository\UserRepository;
|
use App\Repository\UserRepository;
|
||||||
use App\Timesheet\TimesheetStatisticService;
|
use App\Timesheet\TimesheetStatisticService;
|
||||||
use PhpOffice\PhpSpreadsheet\Reader\Html;
|
use PhpOffice\PhpSpreadsheet\Reader\Html;
|
||||||
@@ -68,6 +69,7 @@ final class ReportUsersWeekController extends AbstractController
|
|||||||
$form->submit($request->query->all(), false);
|
$form->submit($request->query->all(), false);
|
||||||
|
|
||||||
$query = new UserQuery();
|
$query = new UserQuery();
|
||||||
|
$query->setVisibility(VisibilityInterface::SHOW_BOTH);
|
||||||
$query->setSystemAccount(false);
|
$query->setSystemAccount(false);
|
||||||
$query->setCurrentUser($currentUser);
|
$query->setCurrentUser($currentUser);
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ use App\Model\MonthlyStatistic;
|
|||||||
use App\Reporting\YearlyUserList\YearlyUserList;
|
use App\Reporting\YearlyUserList\YearlyUserList;
|
||||||
use App\Reporting\YearlyUserList\YearlyUserListForm;
|
use App\Reporting\YearlyUserList\YearlyUserListForm;
|
||||||
use App\Repository\Query\UserQuery;
|
use App\Repository\Query\UserQuery;
|
||||||
|
use App\Repository\Query\VisibilityInterface;
|
||||||
use App\Repository\UserRepository;
|
use App\Repository\UserRepository;
|
||||||
use App\Timesheet\TimesheetStatisticService;
|
use App\Timesheet\TimesheetStatisticService;
|
||||||
use PhpOffice\PhpSpreadsheet\Reader\Html;
|
use PhpOffice\PhpSpreadsheet\Reader\Html;
|
||||||
@@ -75,6 +76,7 @@ final class ReportUsersYearController extends AbstractController
|
|||||||
$form->submit($request->query->all(), false);
|
$form->submit($request->query->all(), false);
|
||||||
|
|
||||||
$query = new UserQuery();
|
$query = new UserQuery();
|
||||||
|
$query->setVisibility(VisibilityInterface::SHOW_BOTH);
|
||||||
$query->setSystemAccount(false);
|
$query->setSystemAccount(false);
|
||||||
$query->setCurrentUser($currentUser);
|
$query->setCurrentUser($currentUser);
|
||||||
|
|
||||||
|
|||||||
@@ -156,9 +156,6 @@
|
|||||||
"kevinpapst/tabler-bundle": {
|
"kevinpapst/tabler-bundle": {
|
||||||
"version": "dev-initial"
|
"version": "dev-initial"
|
||||||
},
|
},
|
||||||
"laminas/laminas-escaper": {
|
|
||||||
"version": "2.7.0"
|
|
||||||
},
|
|
||||||
"league/csv": {
|
"league/csv": {
|
||||||
"version": "9.4.1"
|
"version": "9.4.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -38,19 +38,6 @@
|
|||||||
{% set usersTotalDuration = 0 %}
|
{% set usersTotalDuration = 0 %}
|
||||||
{% set usersTotalInternalRate = 0 %}
|
{% set usersTotalInternalRate = 0 %}
|
||||||
{% set usersTotalRate = 0 %}
|
{% set usersTotalRate = 0 %}
|
||||||
<tr class="user">
|
|
||||||
{% if with_avatar %}
|
|
||||||
<td class="w-avatar">
|
|
||||||
{% from "macros/widgets.html.twig" import user_avatar %}
|
|
||||||
{{ user_avatar(userPeriod.user) }}
|
|
||||||
</td>
|
|
||||||
{% endif %}
|
|
||||||
<td class="text-nowrap"{% block user_column_cell_attribute %}{% endblock %}>
|
|
||||||
{{ userPeriod.user.displayName }}
|
|
||||||
</td>
|
|
||||||
{% if showAccountNumber %}
|
|
||||||
<td>{{ userPeriod.user.accountNumber }}</td>
|
|
||||||
{% endif %}
|
|
||||||
{% for period in attribute(userPeriod, period_attribute) %}
|
{% for period in attribute(userPeriod, period_attribute) %}
|
||||||
{% if period.totalDuration > 0 %}
|
{% if period.totalDuration > 0 %}
|
||||||
{% set usersTotalDuration = usersTotalDuration + period.totalDuration %}
|
{% set usersTotalDuration = usersTotalDuration + period.totalDuration %}
|
||||||
@@ -69,6 +56,20 @@
|
|||||||
{% set totalsInternalRate = totalsInternalRate|merge({(reportDateKey): (totalsInternalRate[reportDateKey] + period.totalInternalRate)}) %}
|
{% set totalsInternalRate = totalsInternalRate|merge({(reportDateKey): (totalsInternalRate[reportDateKey] + period.totalInternalRate)}) %}
|
||||||
{% set totalsRate = totalsRate|merge({(reportDateKey): (totalsRate[reportDateKey] + period.totalRate)}) %}
|
{% set totalsRate = totalsRate|merge({(reportDateKey): (totalsRate[reportDateKey] + period.totalRate)}) %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% if userPeriod.user.enabled or usersTotalDuration > 0 %}
|
||||||
|
<tr class="user">
|
||||||
|
{% if with_avatar %}
|
||||||
|
<td class="w-avatar">
|
||||||
|
{% from "macros/widgets.html.twig" import user_avatar %}
|
||||||
|
{{ user_avatar(userPeriod.user) }}
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
<td class="text-nowrap"{% block user_column_cell_attribute %}{% endblock %}>
|
||||||
|
{{ userPeriod.user.displayName }}
|
||||||
|
</td>
|
||||||
|
{% if showAccountNumber %}
|
||||||
|
<td>{{ userPeriod.user.accountNumber }}</td>
|
||||||
|
{% endif %}
|
||||||
<td class="text-nowrap text-center total{% block user_total_cell_class %}{% endblock %}"{% block user_total_cell_attribute %}{% endblock %}>
|
<td class="text-nowrap text-center total{% block user_total_cell_class %}{% endblock %}"{% block user_total_cell_attribute %}{% endblock %}>
|
||||||
{% if dataType == 'rate' %}
|
{% if dataType == 'rate' %}
|
||||||
{% block total_rate_user %}{% endblock %}
|
{% block total_rate_user %}{% endblock %}
|
||||||
@@ -92,6 +93,7 @@
|
|||||||
</td>
|
</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot>
|
<tfoot>
|
||||||
|
|||||||
@@ -1689,6 +1689,10 @@
|
|||||||
<source>days</source>
|
<source>days</source>
|
||||||
<target>Tage</target>
|
<target>Tage</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="Ga4bvUX" resname="unpaid_vacation">
|
||||||
|
<source>unpaid_vacation</source>
|
||||||
|
<target>Unbezahlter Urlaub</target>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@@ -1689,6 +1689,10 @@
|
|||||||
<source>days</source>
|
<source>days</source>
|
||||||
<target>Days</target>
|
<target>Days</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="Ga4bvUX" resname="unpaid_vacation">
|
||||||
|
<source>unpaid_vacation</source>
|
||||||
|
<target>Unpaid holidays</target>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@@ -148,7 +148,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="c2B6.lW" resname="You can book a maximum of {{ value }} days at once.">
|
<trans-unit id="c2B6.lW" resname="You can book a maximum of {{ value }} days at once.">
|
||||||
<source>You can book a maximum of {{ value }} days at once.</source>
|
<source>You can book a maximum of {{ value }} days at once.</source>
|
||||||
<target>Sie können maximal {{ value }} Tage auf einmal buchen.</target>
|
<target>Sie können maximal {{ value }} Tage auf einmal buchen, aktuell sind {{ selected }} ausgewählt.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="BztgSSP" resname="The period of absence must not extend beyond the turn of the year.">
|
<trans-unit id="BztgSSP" resname="The period of absence must not extend beyond the turn of the year.">
|
||||||
<source>The period of absence must not extend beyond the turn of the year.</source>
|
<source>The period of absence must not extend beyond the turn of the year.</source>
|
||||||
|
|||||||
@@ -148,7 +148,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="c2B6.lW" resname="You can book a maximum of {{ value }} days at once.">
|
<trans-unit id="c2B6.lW" resname="You can book a maximum of {{ value }} days at once.">
|
||||||
<source>You can book a maximum of {{ value }} days at once.</source>
|
<source>You can book a maximum of {{ value }} days at once.</source>
|
||||||
<target>You can book a maximum of {{ value }} days at once.</target>
|
<target>You can book a maximum of {{ value }} days at once, you currently selected {{ selected }}.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="BztgSSP" resname="The period of absence must not extend beyond the turn of the year.">
|
<trans-unit id="BztgSSP" resname="The period of absence must not extend beyond the turn of the year.">
|
||||||
<source>The period of absence must not extend beyond the turn of the year.</source>
|
<source>The period of absence must not extend beyond the turn of the year.</source>
|
||||||
|
|||||||
Reference in New Issue
Block a user