partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

commit dfbb47740cd458c60dad551a8ae827d5ee806cda
parent 54a422994e1eabd596394dd14f5314aea36af963
Author: Felicitus <felicitus@felicitus.org>
Date:   Wed,  9 Dec 2015 21:01:35 +0100

Added configurable limits for parts and users

Diffstat:
Mapp/config/config_partkeepr.yml | 13+++++++++++++
Mapp/config/parameters.php.dist | 11+++++++++++
Msrc/PartKeepr/AuthBundle/Action/DeleteUserAction.php | 12+++++++++++-
Msrc/PartKeepr/AuthBundle/Action/PostUserAction.php | 5+++++
Msrc/PartKeepr/AuthBundle/Action/PutUserAction.php | 8++++++++
Asrc/PartKeepr/AuthBundle/Exceptions/UserLimitReachedException.php | 15+++++++++++++++
Msrc/PartKeepr/AuthBundle/Resources/config/actions.xml | 1+
Msrc/PartKeepr/AuthBundle/Resources/config/services.xml | 1+
Msrc/PartKeepr/AuthBundle/Services/UserService.php | 56+++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/PartKeepr/PartBundle/Action/PostAction.php | 54++++++++++++++----------------------------------------
Msrc/PartKeepr/PartBundle/Entity/Part.php | 1+
Asrc/PartKeepr/PartBundle/Exceptions/PartLimitExceededException.php | 13+++++++++++++
Msrc/PartKeepr/PartBundle/Resources/config/actions.xml | 4++++
Msrc/PartKeepr/PartBundle/Resources/config/services.xml | 5+++++
Asrc/PartKeepr/PartBundle/Services/PartService.php | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/PartKeepr/SetupBundle/Controller/SetupController.php | 8++++++--
16 files changed, 220 insertions(+), 44 deletions(-)

diff --git a/app/config/config_partkeepr.yml b/app/config/config_partkeepr.yml @@ -266,6 +266,17 @@ services: arguments: - { groups: [ "default" ] } + resource.part.collection_operation.custom_post: + class: "Dunglas\ApiBundle\Api\Operation\Operation" + public: false + factory: [ "@api.operation_factory", "createCollectionOperation" ] + arguments: + - "@resource.part" + - [ "POST" ] + - "/parts" + - "partkeepr.part.post" + - "PartPost" + resource.part.item_operation.get: class: "Dunglas\ApiBundle\Api\Operation\Operation" public: false @@ -324,6 +335,8 @@ services: calls: - method: "initItemOperations" arguments: [ [ "@resource.part.item_operation.get", "@resource.part.item_operation.put", "@resource.part.item_operation.delete", "@resource.part.item_operation.add_stock", "@resource.part.item_operation.remove_stock", "@resource.part.item_operation.set_stock" ] ] + - method: "initCollectionOperations" + arguments: [ [ "@resource.part.collection_operation.get", "@resource.part.collection_operation.custom_post" ] ] - method: "initFilters" arguments: [ [ "@doctrine_reflection_service.search_filter" ] ] - method: "initNormalizationContext" diff --git a/app/config/parameters.php.dist b/app/config/parameters.php.dist @@ -147,3 +147,14 @@ $container->setParameter('partkeepr.maintenance.title', ''); * displayed, or to a string which should occur on the maintenance page. */ $container->setParameter('partkeepr.maintenance.message', ''); + +/** + * Defines a limit for the maximum amount of users allowed. Valid values are false (no limit) or an integer number + */ +$container->setParameter('partkeepr.users.limit', false); + +/** + * Defines a limit for the maximum amount of parts allowed. Valid values are false (no limit) or an integer number + */ +$container->setParameter('partkeepr.parts.limit', false); + diff --git a/src/PartKeepr/AuthBundle/Action/DeleteUserAction.php b/src/PartKeepr/AuthBundle/Action/DeleteUserAction.php @@ -6,6 +6,7 @@ use Dunglas\ApiBundle\Exception\RuntimeException; use Dunglas\ApiBundle\Model\DataProviderInterface; use PartKeepr\AuthBundle\Entity\User; use PartKeepr\AuthBundle\Exceptions\UserProtectedException; +use PartKeepr\AuthBundle\Services\UserService; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -21,9 +22,15 @@ class DeleteUserAction */ private $dataProvider; - public function __construct(DataProviderInterface $dataProvider) + /** + * @var UserService + */ + private $userService; + + public function __construct(DataProviderInterface $dataProvider, UserService $userService) { $this->dataProvider = $dataProvider; + $this->userService = $userService; } /** @@ -51,6 +58,9 @@ class DeleteUserAction throw new UserProtectedException(); } + $this->userService->deleteFOSUser($item); + + return $item; } } diff --git a/src/PartKeepr/AuthBundle/Action/PostUserAction.php b/src/PartKeepr/AuthBundle/Action/PostUserAction.php @@ -7,6 +7,7 @@ use Dunglas\ApiBundle\Api\ResourceInterface; use Dunglas\ApiBundle\Exception\RuntimeException; use Dunglas\ApiBundle\Model\DataProviderInterface; use PartKeepr\AuthBundle\Entity\User; +use PartKeepr\AuthBundle\Exceptions\UserLimitReachedException; use PartKeepr\AuthBundle\Services\UserService; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -50,6 +51,7 @@ class PostUserAction * * @throws NotFoundHttpException * @throws RuntimeException + * @throws UserLimitReachedException */ public function __invoke(Request $request) { @@ -58,6 +60,9 @@ class PostUserAction */ list($resourceType, $format) = $this->extractAttributes($request); + if ($this->userService->checkUserLimit() === true) { + throw new UserLimitReachedException(); + } /** * @var User $data */ diff --git a/src/PartKeepr/AuthBundle/Action/PutUserAction.php b/src/PartKeepr/AuthBundle/Action/PutUserAction.php @@ -7,6 +7,7 @@ use Dunglas\ApiBundle\Api\ResourceInterface; use Dunglas\ApiBundle\Exception\RuntimeException; use Dunglas\ApiBundle\Model\DataProviderInterface; use PartKeepr\AuthBundle\Entity\User; +use PartKeepr\AuthBundle\Exceptions\UserLimitReachedException; use PartKeepr\AuthBundle\Exceptions\UserProtectedException; use PartKeepr\AuthBundle\Services\UserService; use Symfony\Component\HttpFoundation\Request; @@ -53,6 +54,7 @@ class PutUserAction * @throws NotFoundHttpException * @throws RuntimeException * @throws UserProtectedException + * @throws UserLimitReachedException */ public function __invoke(Request $request, $id) { @@ -80,6 +82,12 @@ class PutUserAction $context ); + if ($data->isActive()) { + if ($this->userService->checkUserLimit()) { + throw new UserLimitReachedException(); + } + } + $this->userService->syncData($data); $data->setNewPassword(""); $data->setPassword(""); diff --git a/src/PartKeepr/AuthBundle/Exceptions/UserLimitReachedException.php b/src/PartKeepr/AuthBundle/Exceptions/UserLimitReachedException.php @@ -0,0 +1,15 @@ +<?php +namespace PartKeepr\AuthBundle\Exceptions; + +use PartKeepr\CoreBundle\Exceptions\TranslatableException; + +/** + * Is thrown when the configured user limit is reached + */ +class UserLimitReachedException extends TranslatableException +{ + public function getMessageKey() + { + return "The maximum number of users is reached"; + } +} diff --git a/src/PartKeepr/AuthBundle/Resources/config/actions.xml b/src/PartKeepr/AuthBundle/Resources/config/actions.xml @@ -33,6 +33,7 @@ </service> <service id="partkeepr.user.delete" class="PartKeepr\AuthBundle\Action\DeleteUserAction"> <argument type="service" id="api.data_provider"/> + <argument type="service" id="partkeepr.userservice"/> </service> <service id="partkeepr.auth.login" class="PartKeepr\AuthBundle\Action\LoginAction"> <argument type="service" id="partkeepr.userservice"/> diff --git a/src/PartKeepr/AuthBundle/Resources/config/services.xml b/src/PartKeepr/AuthBundle/Resources/config/services.xml @@ -15,6 +15,7 @@ <argument type="service" id="doctrine.orm.entity_manager"/> <argument type="service" id="fos_user.util.user_manipulator"/> <argument type="service" id="fos_user.user_manager"/> + <argument type="string">%partkeepr.users.limit%</argument> </service> <service id="partkeepr.user_preference_service" class="PartKeepr\AuthBundle\Services\UserPreferenceService"> <argument type="service" id="doctrine.orm.entity_manager"/> diff --git a/src/PartKeepr/AuthBundle/Services/UserService.php b/src/PartKeepr/AuthBundle/Services/UserService.php @@ -32,18 +32,27 @@ class UserService */ private $userManager; + /** + * The maximum number of users allowed + * + * @var int|bool + */ + private $userLimit; + const BUILTIN_PROVIDER = "Builtin"; public function __construct( TokenStorage $tokenStorage, EntityManager $entityManager, UserManipulator $userManipulator, - UserManagerInterface $userManager + UserManagerInterface $userManager, + $userLimit = false ) { $this->tokenStorage = $tokenStorage; $this->entityManager = $entityManager; $this->userManipulator = $userManipulator; $this->userManager = $userManager; + $this->userLimit = $userLimit; } /** @@ -118,6 +127,22 @@ class UserService $FOSUser->setEnabled($user->isActive()); } + /** + * Deletes an user from the FOSUser system + * @param User $user + */ + public function deleteFOSUser (User $user) { + if ($user->getProvider()->getType() !== self::BUILTIN_PROVIDER) { + return; + } + + $FOSUser = $this->userManager->findUserByUsername($user->getUsername()); + + if ($FOSUser !== null) { + $this->userManager->deleteUser($FOSUser); + } + } + public function getProviderByType($type) { $provider = $this->entityManager->getRepository("PartKeeprAuthBundle:UserProvider")->findOneBy(array("type" => $type)); @@ -199,6 +224,7 @@ class UserService /** * Protects a given user against changes. + * * @param User $user */ public function protect(User $user) @@ -209,6 +235,7 @@ class UserService /** * Unprotects a given user against changes. + * * @param User $user */ public function unprotect(User $user) @@ -216,4 +243,31 @@ class UserService $user->setProtected(false); $this->entityManager->flush(); } + + /** + * Returns the number of users present in the system + * @return mixed + */ + public function getUserCount() + { + $dql = "SELECT COUNT(u) FROM PartKeepr\\AuthBundle\\Entity\\FOSUser u WHERE u.enabled = 1"; + $query = $this->entityManager->createQuery($dql); + + return $query->getSingleScalarResult(); + } + + /** + * Checks if the amount of users is exceeded + * @return bool + */ + public function checkUserLimit() + { + if ($this->userLimit !== false) { + if ($this->getUserCount() >= $this->userLimit) { + return true; + } + } + + return false; + } } diff --git a/src/PartKeepr/PartBundle/Action/PostAction.php b/src/PartKeepr/PartBundle/Action/PostAction.php @@ -4,10 +4,10 @@ namespace PartKeepr\PartBundle\Action; use Dunglas\ApiBundle\Action\ActionUtilTrait; -use Dunglas\ApiBundle\Api\IriConverterInterface; use Dunglas\ApiBundle\Api\ResourceInterface; use Dunglas\ApiBundle\Exception\RuntimeException; -use PartKeepr\CategoryBundle\Services\CategoryService; +use PartKeepr\PartBundle\Exceptions\PartLimitExceededException; +use PartKeepr\PartBundle\Services\PartService; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Serializer\SerializerInterface; @@ -16,28 +16,21 @@ class PostAction use ActionUtilTrait; /** - * @var CategoryService - */ - private $categoryService; - - /** - * @var IriConverterInterface + * @var SerializerInterface */ - private $iriConverter; + private $serializer; /** - * @var SerializerInterface + * @var PartService */ - private $serializer; + private $partService; public function __construct( - CategoryService $categoryService, - IriConverterInterface $iriConverter, - SerializerInterface $serializer + SerializerInterface $serializer, + PartService $partService ) { - $this->categoryService = $categoryService; - $this->iriConverter = $iriConverter; $this->serializer = $serializer; + $this->partService = $partService; } /** @@ -48,40 +41,21 @@ class PostAction * @return mixed * * @throws RuntimeException + * @throws PartLimitExceededException */ public function __invoke(Request $request) { /** * @var $resourceType ResourceInterface */ - list($resourceType, $format) = $this->extractAttributes($request); - - $data = $request->getContent(); - - $decodedData = json_decode($data); - - $localTreeExists = false; - if (property_exists($decodedData,"category") && $decodedData->category == "@local-tree-root") { - $localTreeExists = true; - + if ($this->partService->checkPartLimit()) { + throw new PartLimitExceededException(); } - if (property_exists($decodedData,"category") && is_object($decodedData->category) && property_exists($decodedData->category, "@id") && $decodedData->category->{"@id"} == "@local-tree-root") { - $localTreeExists = true; - } - - if ($localTreeExists === true) { - $root = $this->categoryService->getRootNode(); - $iri = $this->iriConverter->getIriFromItem($root); - - $decodedData->category = $iri; - $data = json_encode($decodedData); - } - - + list($resourceType, $format) = $this->extractAttributes($request); return $this->serializer->deserialize( - $data, + $request->getContent(), $resourceType->getEntityClass(), $format, $resourceType->getDenormalizationContext() diff --git a/src/PartKeepr/PartBundle/Entity/Part.php b/src/PartKeepr/PartBundle/Entity/Part.php @@ -231,6 +231,7 @@ class Part extends BaseEntity $this->parameters = new ArrayCollection(); $this->attachments = new ArrayCollection(); $this->stockLevels = new ArrayCollection(); + $this->projectParts = new ArrayCollection(); $this->setCreateDate(new \DateTime()); $this->setNeedsReview(false); } diff --git a/src/PartKeepr/PartBundle/Exceptions/PartLimitExceededException.php b/src/PartKeepr/PartBundle/Exceptions/PartLimitExceededException.php @@ -0,0 +1,13 @@ +<?php +namespace PartKeepr\PartBundle\Exceptions; + + +use PartKeepr\CoreBundle\Exceptions\TranslatableException; + +class PartLimitExceededException extends TranslatableException +{ + public function getMessageKey() + { + return "The maximum number of parts is reached"; + } +} diff --git a/src/PartKeepr/PartBundle/Resources/config/actions.xml b/src/PartKeepr/PartBundle/Resources/config/actions.xml @@ -5,6 +5,10 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> + <service id="partkeepr.part.post" class="PartKeepr\PartBundle\Action\PostAction"> + <argument type="service" id="api.serializer" /> + <argument type="service" id="partkeepr.part_service" /> + </service> <service id="partkeepr.part.add_stock" class="PartKeepr\PartBundle\Action\AddStockAction"> <argument type="service" id="api.data_provider"/> <argument type="service" id="partkeepr.userservice" /> diff --git a/src/PartKeepr/PartBundle/Resources/config/services.xml b/src/PartKeepr/PartBundle/Resources/config/services.xml @@ -12,6 +12,11 @@ <argument type="service" id="doctrine.orm.default_entity_manager" /> <argument>PartKeepr\PartBundle\Entity\PartCategory</argument> </service> + + <service id="partkeepr.part_service" class="PartKeepr\PartBundle\Services\PartService"> + <argument type="service" id="doctrine.orm.default_entity_manager" /> + <argument type="string">%partkeepr.parts.limit%</argument> + </service> </services> </container> diff --git a/src/PartKeepr/PartBundle/Services/PartService.php b/src/PartKeepr/PartBundle/Services/PartService.php @@ -0,0 +1,57 @@ +<?php + + +namespace PartKeepr\PartBundle\Services; + + +use Doctrine\ORM\EntityManager; + +class PartService +{ + /** + * The maximum number of parts allowed + * + * @var int|bool + */ + private $partLimit; + + /** + * @var EntityManager + */ + private $entityManager; + + public function __construct( + EntityManager $entityManager, + $partLimit = false + ) { + $this->entityManager = $entityManager; + $this->partLimit = $partLimit; + } + + /** + * Returns the number of parts present in the system + * @return mixed + */ + public function getPartCount() + { + $dql = "SELECT COUNT(p) FROM PartKeepr\\PartBundle\\Entity\\Part p"; + $query = $this->entityManager->createQuery($dql); + + return $query->getSingleScalarResult(); + } + + /** + * Checks if the amount of parts is exceeded + * @return bool + */ + public function checkPartLimit() + { + if ($this->partLimit !== false) { + if ($this->getPartCount() >= $this->partLimit) { + return true; + } + } + + return false; + } +} diff --git a/src/PartKeepr/SetupBundle/Controller/SetupController.php b/src/PartKeepr/SetupBundle/Controller/SetupController.php @@ -43,6 +43,7 @@ class SetupController extends Controller /** * @Route("/setup/testConnectivity") * @param Request $request + * @return Response */ public function testConnectivityAction(Request $request) { @@ -56,6 +57,7 @@ class SetupController extends Controller /** * @Route("/setup/saveConfig") * @param Request $request + * @return JsonResponse */ public function saveConfigAction(Request $request) { @@ -211,7 +213,9 @@ class SetupController extends Controller "partkeepr.maintenance.title" => "", "partkeepr.maintenance.message" => "", "cache.dunglas" => false, - "cache.doctrine" => "array" + "cache.doctrine" => "array", + "partkeepr.parts.limit" => false, + "partkeepr.users.limit" => false ); if (function_exists("apc_fetch")) { @@ -222,7 +226,7 @@ class SetupController extends Controller $this->applyIf($parameters, $data["values"]); $parameters = array_merge($parameters, $data["values"]); - array_walk_recursive($parameters, function (&$item, $key) { $item = var_export($item, true); }); + array_walk_recursive($parameters, function (&$item) { $item = var_export($item, true); }); ksort($parameters);