at the end of the day, it was inevitable
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller\V1;
|
||||
|
||||
use ApiBundle\Controller\AbstractApiController;
|
||||
use ApiBundle\Response\View;
|
||||
use AppBundle\Response\SearchResponseInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\ORM\Tools\Pagination\Paginator;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Class AbstractV1Controller
|
||||
*
|
||||
* @package AppBundle\Controller\V1
|
||||
*
|
||||
* @deprecated
|
||||
* @see AbstractApiController
|
||||
*/
|
||||
abstract class AbstractV1Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Generate proper server response.
|
||||
*
|
||||
* @param mixed $data A data sent to client.
|
||||
* @param integer $code Response http code.
|
||||
* @param array $groups Serialization groups.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
protected function generateResponse(
|
||||
$data = null,
|
||||
$code = null,
|
||||
array $groups = []
|
||||
) {
|
||||
return new View($data, $groups, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $data A data for pagination.
|
||||
* @param integer $page A requested page, starts from 1.
|
||||
* @param integer $limit Required numbers of data per page.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function paginate($data, $page, $limit)
|
||||
{
|
||||
if ($data instanceof SearchResponseInterface) {
|
||||
//
|
||||
// Response from index or cache already paginated so we just return
|
||||
// values.
|
||||
//
|
||||
return [
|
||||
'data' => $data->getDocuments(),
|
||||
'count' => count($data),
|
||||
'totalCount' => $data->getTotalCount(),
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
];
|
||||
} elseif ($data instanceof QueryBuilder) {
|
||||
$data
|
||||
->setMaxResults($limit)
|
||||
->setFirstResult(($page - 1) * $limit);
|
||||
|
||||
$paginator = new Paginator($data);
|
||||
$data = iterator_to_array($paginator);
|
||||
|
||||
return [
|
||||
'data' => $data,
|
||||
'count' => count($data),
|
||||
'totalCount' => $paginator->count(),
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
];
|
||||
}
|
||||
|
||||
return [];// TODO add code for over paginated data.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a NotFoundHttpException.
|
||||
*
|
||||
* This will result in a 404 response code. Usage example:
|
||||
*
|
||||
* throw $this->createNotFoundException('Page not found!');
|
||||
*
|
||||
* @param string $message A message.
|
||||
* @param \Exception|null $previous The previous exception.
|
||||
*
|
||||
* @return NotFoundHttpException
|
||||
*/
|
||||
protected function createNotFoundException($message = 'Not Found', \Exception $previous = null)
|
||||
{
|
||||
return new NotFoundHttpException($message, $previous);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller\V1;
|
||||
|
||||
use ApiBundle\Controller\AbstractApiController;
|
||||
use ApiBundle\Entity\ManageableEntityInterface;
|
||||
use ApiBundle\Form\EntitiesBatchType;
|
||||
use ApiBundle\Security\AccessChecker\AccessCheckerInterface;
|
||||
use ApiBundle\Security\Inspector\InspectorInterface;
|
||||
use AppBundle\Controller\Traits\AccessCheckerTrait;
|
||||
use AppBundle\Controller\Traits\FormFactoryAwareTrait;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Form\FormFactoryInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Class AbstractV1CrudController
|
||||
*
|
||||
* @package AppBundle\Controller\V1
|
||||
*
|
||||
* @deprecated
|
||||
* @see AbstractApiController
|
||||
*/
|
||||
abstract class AbstractV1CrudController extends AbstractV1Controller
|
||||
{
|
||||
|
||||
use
|
||||
FormFactoryAwareTrait,
|
||||
AccessCheckerTrait;
|
||||
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
protected $em;
|
||||
|
||||
/**
|
||||
* Entity fqcn.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* AbstractV1CrudController constructor.
|
||||
*
|
||||
* @param FormFactoryInterface $formFactory A FormFactoryInterface instance.
|
||||
* @param AccessCheckerInterface $accessChecker A AccessCheckerInterface instance.
|
||||
* @param EntityManagerInterface $em A EntityManagerInterface instance.
|
||||
* @param string $entity A used entity name.
|
||||
*/
|
||||
public function __construct(
|
||||
FormFactoryInterface $formFactory,
|
||||
AccessCheckerInterface $accessChecker,
|
||||
EntityManagerInterface $em,
|
||||
$entity
|
||||
) {
|
||||
$this->formFactory = $formFactory;
|
||||
$this->accessChecker = $accessChecker;
|
||||
$this->em = $em;
|
||||
$this->entity = $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new entity.
|
||||
*
|
||||
* @param Request $request A Request instance.
|
||||
* @param ManageableEntityInterface $entity A ManageableEntityInterface
|
||||
* instance.
|
||||
*
|
||||
* @return \ApiBundle\Entity\ManageableEntityInterface|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
protected function createEntity(Request $request, ManageableEntityInterface $entity)
|
||||
{
|
||||
$form = $this->createForm($entity->getCreateFormClass(), $entity);
|
||||
|
||||
// Submit data into form.
|
||||
$form->submit($request->request->all());
|
||||
if ($form->isValid()) {
|
||||
// Check that current user can create this entity.
|
||||
// If user don't have rights to create this entity we should send all
|
||||
// founded restrictions to client.
|
||||
$reasons = $this->checkAccess(InspectorInterface::CREATE, $entity);
|
||||
if (count($reasons) > 0) {
|
||||
// User don't have rights to create this entity so send all
|
||||
// founded restriction reasons to client.
|
||||
return $this->generateResponse($reasons, 403);
|
||||
}
|
||||
|
||||
$this->em->persist($entity);
|
||||
$this->em->flush();
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
// Client send invalid data.
|
||||
return $this->generateResponse($form, 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about single entity.
|
||||
*
|
||||
* @param integer|ManageableEntityInterface|null $id A entity id.
|
||||
*
|
||||
* @return \ApiBundle\Entity\ManageableEntityInterface|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
protected function getEntity($id)
|
||||
{
|
||||
$foundedEntity = $id;
|
||||
if (is_numeric($id)) {
|
||||
$repository = $this->em->getRepository($this->entity);
|
||||
|
||||
$foundedEntity = $repository->find($id);
|
||||
}
|
||||
|
||||
if ($foundedEntity === null) {
|
||||
$name = \app\c\getShortName($this->entity);
|
||||
// Remove 'Abstract' prefix if it exists.
|
||||
if (strpos($name, 'Abstract') !== false) {
|
||||
$name = substr($name, 8);
|
||||
}
|
||||
|
||||
return $this->generateResponse("Can't find {$name} with id {$id}.", 404);
|
||||
}
|
||||
|
||||
// Check that current user can read this entity.
|
||||
// If user don't have rights to read this entity we should send all
|
||||
// founded restrictions to client.
|
||||
$reasons = $this->checkAccess(InspectorInterface::READ, $foundedEntity);
|
||||
if (count($reasons) > 0) {
|
||||
return $this->generateResponse($reasons, 403);
|
||||
}
|
||||
|
||||
return $foundedEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update entity.
|
||||
*
|
||||
* @param Request $request A Request instance.
|
||||
* @param integer|ManageableEntityInterface|null $entity A entity id.
|
||||
*
|
||||
* @return \ApiBundle\Entity\ManageableEntityInterface|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
protected function putEntity(Request $request, $entity)
|
||||
{
|
||||
$foundedEntity = $entity;
|
||||
if (is_numeric($entity)) {
|
||||
$repository = $this->em->getRepository($this->entity);
|
||||
/** @var \ApiBundle\Entity\ManageableEntityInterface $entity */
|
||||
$foundedEntity = $repository->find($entity);
|
||||
}
|
||||
|
||||
if ($foundedEntity === null) {
|
||||
$name = \app\c\getShortName($this->entity);
|
||||
// Remove 'Abstract' prefix if it exists.
|
||||
if (strpos($name, 'Abstract') !== false) {
|
||||
$name = substr($name, 8);
|
||||
}
|
||||
|
||||
return $this->generateResponse("Can't find {$name} with id {$entity}.", 404);
|
||||
}
|
||||
|
||||
$form = $this->createForm($foundedEntity->getUpdateFormClass(), $foundedEntity, [
|
||||
'method' => 'PUT',
|
||||
]);
|
||||
$form->submit($request->request->all());
|
||||
if ($form->isValid()) {
|
||||
// Check that current user can update this entity.
|
||||
// If user don't have rights to update this entity we should send all
|
||||
// founded restrictions to client.
|
||||
$reasons = $this->checkAccess(InspectorInterface::UPDATE, $foundedEntity);
|
||||
if (count($reasons) > 0) {
|
||||
return $this->generateResponse($reasons, 403);
|
||||
}
|
||||
|
||||
$this->em->persist($foundedEntity);
|
||||
$this->em->flush();
|
||||
|
||||
return $foundedEntity;
|
||||
}
|
||||
|
||||
return $this->generateResponse($form, 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete entity.
|
||||
*
|
||||
* @param integer|ManageableEntityInterface|null $entity A entity id.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
protected function deleteEntity($entity)
|
||||
{
|
||||
$foundedEntity = $entity;
|
||||
if (is_numeric($entity)) {
|
||||
$repository = $this->em->getRepository($this->entity);
|
||||
/** @var \ApiBundle\Entity\ManageableEntityInterface $entity */
|
||||
$foundedEntity = $repository->find($entity);
|
||||
}
|
||||
|
||||
if ($foundedEntity === null) {
|
||||
$name = \app\c\getShortName($this->entity);
|
||||
// Remove 'Abstract' prefix if it exists.
|
||||
if (strpos($name, 'Abstract') !== false) {
|
||||
$name = substr($name, 8);
|
||||
}
|
||||
|
||||
return $this->generateResponse("Can't find {$name} with id {$entity}.", 404);
|
||||
}
|
||||
// Check that current user can delete this entity.
|
||||
// If user don't have rights to delete this entity we should send all
|
||||
// founded restrictions to client.
|
||||
$reasons = $this->checkAccess(InspectorInterface::DELETE, $foundedEntity);
|
||||
if (count($reasons) > 0) {
|
||||
return $this->generateResponse($reasons, 403);
|
||||
}
|
||||
|
||||
$this->em->remove($foundedEntity);
|
||||
$this->em->flush();
|
||||
|
||||
return $this->generateResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request A Request instance.
|
||||
* @param string|callable $permission A requested permission.
|
||||
* @param string $formClass Form class fqcn.
|
||||
* @param callable $processor Function which process founded entities.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
protected function batchProcessing(
|
||||
Request $request,
|
||||
$permission,
|
||||
$formClass,
|
||||
callable $processor
|
||||
) {
|
||||
$this->checkFormClass($formClass);
|
||||
|
||||
$form = $this->createForm($formClass, null, [ 'class' => $this->entity ]);
|
||||
|
||||
$form->submit($request->request->all());
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$data = $form->getData();
|
||||
|
||||
if (is_callable($permission)) {
|
||||
$permission = call_user_func_array($permission, $data);
|
||||
}
|
||||
|
||||
if (! is_string($permission)) {
|
||||
throw new \InvalidArgumentException('$permission should be string or callable');
|
||||
}
|
||||
|
||||
$reasons = $this->checkAccess($permission, $data['entities']);
|
||||
if (count($reasons) > 0) {
|
||||
return $this->generateResponse($reasons, 403);
|
||||
}
|
||||
|
||||
$response = call_user_func_array($processor, $data);
|
||||
if ($response === null) {
|
||||
$response = $this->generateResponse();
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
return $this->generateResponse($form, 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $formClass Form class fqcn.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function checkFormClass($formClass)
|
||||
{
|
||||
if (! is_string($formClass) || ! class_exists($formClass)) {
|
||||
throw new \InvalidArgumentException('$formClass should be fqcn');
|
||||
}
|
||||
|
||||
if (($formClass !== EntitiesBatchType::class)
|
||||
&& ! in_array(EntitiesBatchType::class, class_parents($formClass), true)) {
|
||||
throw new \InvalidArgumentException('Invalid form class '. $formClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller\V1;
|
||||
|
||||
use ApiBundle\Controller\AbstractCRUDController;
|
||||
use ApiBundle\Controller\Annotation\Roles;
|
||||
use ApiDocBundle\Controller\Annotation\AppApiDoc;
|
||||
use AppBundle\Exception\NotAllowedException;
|
||||
use CacheBundle\DTO\AnalyticDTO;
|
||||
use CacheBundle\Entity\Analytic\Analytic;
|
||||
use CacheBundle\Form\AnalyticType;
|
||||
use CacheBundle\Service\Factory\Analytic\AnalyticFactoryInterface;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use ApiBundle\Security\Inspector\InspectorInterface;
|
||||
use CacheBundle\Repository\AnalyticRepository;
|
||||
|
||||
/**
|
||||
* Class AnalyticController
|
||||
* @package AppBundle\Controller\V1
|
||||
*
|
||||
* @Route("/analysis", service="app.controller.analytic")
|
||||
*/
|
||||
class AnalyticController extends AbstractCRUDController
|
||||
{
|
||||
|
||||
/**
|
||||
* @var AnalyticFactoryInterface
|
||||
*/
|
||||
private $analyticFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Create new analytic entity.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(
|
||||
* methods={ "POST" }
|
||||
* )
|
||||
* @AppApiDoc(
|
||||
* section="Analytic",
|
||||
* resource=false,
|
||||
* input={
|
||||
* "class"="CacheBundle\Form\AnalyticType"
|
||||
* },
|
||||
* output={
|
||||
* "class"="CacheBundle\Entity\Analytic\Analytic",
|
||||
* "groups"={ "analytic", "id" }
|
||||
* },
|
||||
* statusCodes={
|
||||
* 200="Analytics successfully created.",
|
||||
* 400="Invalid data provided.",
|
||||
* 403="You don't have permissions to create analytics."
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A Http Request instance.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function postAction(Request $request)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
$this->analyticFactory = $this->get('cache.analytic_factory');
|
||||
|
||||
$form = $this->createForm(AnalyticType::class)
|
||||
->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
/** @var AnalyticDTO $dto */
|
||||
$dto = $form->getData();
|
||||
|
||||
try {
|
||||
$analytic = $this->analyticFactory->createAnalytic($dto, $user);
|
||||
} catch (NotAllowedException $exception) {
|
||||
return $this->generateResponse('You not allowed to make analytics');
|
||||
}
|
||||
|
||||
$this->getManager()->persist($analytic);
|
||||
$this->getManager()->flush();
|
||||
|
||||
return $this->generateResponse($analytic, 200, ['id', 'analytic']);
|
||||
}
|
||||
|
||||
return $this->generateResponse($form, 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get specified analytic by id.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(
|
||||
* "/{id}",
|
||||
* requirements={ "id"="\d+" },
|
||||
* methods={ "GET" }
|
||||
* )
|
||||
* @AppApiDoc(
|
||||
* resource=true,
|
||||
* section="Analytic",
|
||||
* output={
|
||||
* "class"="CacheBundle\Entity\Analytic\Analytic",
|
||||
* "groups"={"id"}
|
||||
* },
|
||||
* statusCodes={
|
||||
* 200="Analytics successfully returned.",
|
||||
* 403="You don't have permissions to view this analytics.",
|
||||
* 404="Can't find analytic by specified id."
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param integer $id Analytic entity id.
|
||||
*
|
||||
* @return \CacheBundle\Entity\Analytic\Analytic|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function getAction($id)
|
||||
{
|
||||
return parent::getEntity($id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete specified analytic.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(
|
||||
* "/{id}",
|
||||
* requirements={ "id"="\d+" },
|
||||
* methods={ "DELETE" }
|
||||
* )
|
||||
* @AppApiDoc(
|
||||
* resource=true,
|
||||
* section="Analytic",
|
||||
* statusCodes={
|
||||
* 204="Analytic successfully deleted.",
|
||||
* 403="You don't have permissions to delete this analytic.",
|
||||
* 404="Can't find analytic by specified id."
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param integer $id A Analytic entity id.
|
||||
*
|
||||
* @return array|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function deleteAction($id)
|
||||
{
|
||||
$repository = $this->getManager()->getRepository($this->entity);
|
||||
/** @var Analytic $analytic */
|
||||
$analytic = $repository->find($id);
|
||||
|
||||
if (!$analytic instanceof Analytic) {
|
||||
return $this->generateResponse("Can't find analytic with id {$id}.", 404);
|
||||
}
|
||||
$reasons = $this->checkAccess(InspectorInterface::DELETE, $analytic);
|
||||
if (count($reasons) > 0) {
|
||||
return $this->generateResponse($reasons, 403);
|
||||
}
|
||||
$analyticContext = $analytic->getContext();
|
||||
|
||||
if (isset($analyticContext)) {
|
||||
($analyticContext->getAnalytics()->count() == 1) ? $this->getManager()->remove($analyticContext) : "";
|
||||
}
|
||||
|
||||
$this->getManager()->remove($analytic);
|
||||
$this->getManager()->flush();
|
||||
|
||||
return $this->generateResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update analytic.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route("/{id}", methods={ "PUT" }, requirements={ "id"="\d+" })
|
||||
* @AppApiDoc(
|
||||
* section="Analytic",
|
||||
* resource=true,
|
||||
* input={
|
||||
* "class"="CacheBundle\Form\AnalyticType",
|
||||
* "name"=false
|
||||
* },
|
||||
* output={
|
||||
* "class"="CacheBundle\Entity\Analytic\Analytic",
|
||||
* "groups"={ "analytic", "id" }
|
||||
* },
|
||||
* statusCodes={
|
||||
* 200="Analytics successfully updated.",
|
||||
* 400="Invalid data provided."
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A Request instance.
|
||||
* @param integer $id Analytic entity id.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function putAction(Request $request, $id)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
$this->analyticFactory = $this->get('cache.analytic_factory');
|
||||
|
||||
/** @var AnalyticRepository $analyticRepository */
|
||||
$repository = $this->getManager()->getRepository($this->entity);
|
||||
/** @var Analytic $analytic */
|
||||
$analytic = $repository->find($id);
|
||||
|
||||
if (!$analytic instanceof Analytic) {
|
||||
return $this->generateResponse("Can't find analytic with id {$id}.", 404);
|
||||
}
|
||||
$feeds = $analytic->getContext()->getFeeds();
|
||||
$feedsId = [];
|
||||
foreach ($feeds as $feedsVal) {
|
||||
$feedsId[] = $feedsVal->getId();
|
||||
}
|
||||
|
||||
$analyticDto = new AnalyticDTO($feedsId, null, $analytic->getContext()->getFilters(), $analytic->getContext()->getRawFilters());
|
||||
$form = $this->createForm(AnalyticType::class, $analyticDto);
|
||||
$form->submit($request->request->all());
|
||||
if ($form->isValid()) {
|
||||
/** @var AnalyticDTO $dto */
|
||||
$dto = $form->getData();
|
||||
|
||||
try {
|
||||
$analyticContext = $analytic->getContext();
|
||||
if (isset($analyticContext)) {
|
||||
($analyticContext->getAnalytics()->count() == 1) ? $this->getManager()->remove($analyticContext) : "";
|
||||
}
|
||||
$analytic = $this->analyticFactory->updateAnalytic($dto, $user, $analytic);
|
||||
|
||||
} catch (NotAllowedException $exception) {
|
||||
return $this->generateResponse('You not allowed to update analytics');
|
||||
}
|
||||
|
||||
$this->getManager()->persist($analytic);
|
||||
$this->getManager()->flush();
|
||||
|
||||
return $this->generateResponse($analytic, 200, ['id', 'analytic']);
|
||||
}
|
||||
|
||||
return $this->generateResponse($form, 400);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get list of categories for current user.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(methods={ "GET" })
|
||||
* @AppApiDoc(
|
||||
* section="Analytic",
|
||||
* output={
|
||||
* "class"="Pagination<CacheBundle\Entity\Analytic\Analytic>",
|
||||
* "groups"={ "analytic", "id","context" }
|
||||
* },
|
||||
* statusCodes={
|
||||
* 200="List of analytic successfully returned."
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function listAction(Request $request)
|
||||
{
|
||||
/** @var AnalyticRepository $repository */
|
||||
$repository = $this->getManager()->getRepository(Analytic::class);
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
$pagination = $this->paginate(
|
||||
$request,
|
||||
$repository->getList($user->getId())
|
||||
);
|
||||
|
||||
// Simulate pagination serialization.
|
||||
return $this->generateResponse([
|
||||
$pagination
|
||||
], 200, [
|
||||
'analytic',
|
||||
'id',
|
||||
'context'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller\V1;
|
||||
|
||||
use ApiBundle\Controller\AbstractCRUDController;
|
||||
use ApiBundle\Controller\Annotation\Roles;
|
||||
use CacheBundle\Entity\Analytic\Analytic;
|
||||
use DateInterval;
|
||||
use DatePeriod;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use CacheBundle\Repository\AnalyticRepository;
|
||||
use CacheBundle\Entity\Document;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Class AnalyticGraphController
|
||||
* @package AppBundle\Controller\V1
|
||||
*
|
||||
* @Route(service="app.controller.analytic-graph")
|
||||
*/
|
||||
class AnalyticGraphController extends AbstractCRUDController
|
||||
{
|
||||
|
||||
/**
|
||||
* Get data for influence list
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(
|
||||
* "/influencer/{id}",
|
||||
* requirements={
|
||||
* "id": "\d+",
|
||||
* },
|
||||
* methods={ "POST" }
|
||||
* )
|
||||
*
|
||||
* @param Request $request
|
||||
* @param $id
|
||||
*
|
||||
* @return array|\ApiBundle\Response\ViewInterface
|
||||
*
|
||||
*/
|
||||
public function getInfluenceAction(Request $request, $id)
|
||||
{
|
||||
$isAuthorType = $request->request->get('isAuthorType', false);
|
||||
$groupByField = 'source_hashcode';
|
||||
if ($isAuthorType === true) {
|
||||
$groupByField = 'author_name';
|
||||
}
|
||||
|
||||
/** @var AnalyticRepository $analyticRepository */
|
||||
$repository = $this->getManager()->getRepository($this->entity);
|
||||
/** @var Analytic $analytic */
|
||||
$analytic = $repository->find($id);
|
||||
|
||||
if (!$analytic instanceof Analytic) {
|
||||
return $this->generateResponse("Can't find analytic with id {$id}.", 404);
|
||||
}
|
||||
$analyticContext = $analytic->getContext();
|
||||
$feeds = $analyticContext->getFeeds();
|
||||
$queryId = [];
|
||||
$clipFeedId = [];
|
||||
foreach ($feeds as $feedsVal) {
|
||||
if ($feedsVal->getSubType() == 'query_feed') {
|
||||
$queryId[] = $feedsVal->getQuery()->getId();
|
||||
} else {
|
||||
$clipFeedId[] = $feedsVal->getId();
|
||||
}
|
||||
}
|
||||
$filters = $analyticContext->getFilters();
|
||||
$influenceData = [];
|
||||
if (count($filters) > 0) {
|
||||
if (array_key_exists('date', $filters)) {
|
||||
|
||||
$startDt = $filters['date']->getFilters()[0]->getValue()->format('Y-m-d');
|
||||
$endDt = $filters['date']->getFilters()[1]->getValue()->format('Y-m-d');
|
||||
$repository = $this->getManager()->getRepository(Document::class);
|
||||
$documents = $repository->getByQuery($queryId);
|
||||
$clipDocuments = $repository->getByClip($clipFeedId);
|
||||
|
||||
foreach ($feeds as $key => $feedsVal) {
|
||||
$influenceData[$key]['name'] = $feedsVal->getName();
|
||||
$influenceData[$key]['data'] = [];
|
||||
foreach ($documents as $document) {
|
||||
if ($feedsVal->getSubType() == 'query_feed') {
|
||||
if ($feedsVal->getQuery()->getId() == $document['id']) {
|
||||
$publishDate = substr($document['data']['published'], 0, 10);
|
||||
$publishDate = date('Y-m-d', strtotime($publishDate));
|
||||
if (($publishDate >= $startDt) && ($publishDate <= $endDt)) {
|
||||
if (array_key_exists($groupByField, $document['data'])) {
|
||||
$engagementCount = 0;
|
||||
if (array_key_exists("likes", $document['data'])) {
|
||||
$engagementCount = $document['data']['likes'];
|
||||
}
|
||||
if (array_key_exists("dislikes", $document['data'])) {
|
||||
$engagementCount += $document['data']['dislikes'];
|
||||
}
|
||||
if (array_key_exists("comments", $document['data'])) {
|
||||
$engagementCount += $document['data']['comments'];
|
||||
}
|
||||
if (array_key_exists("shares", $document['data'])) {
|
||||
$engagementCount += $document['data']['shares'];
|
||||
}
|
||||
$tempInfluenceData = $influenceData[$key]['data'];
|
||||
if (count($tempInfluenceData) > 0) {
|
||||
$sourceHashCodeKey = array_search($document['data'][$groupByField], array_column($tempInfluenceData, $groupByField));
|
||||
if ($sourceHashCodeKey === false) {
|
||||
$tempData = [$groupByField => $document['data'][$groupByField], 'influence' => $document['data']['source_link'],
|
||||
'source_type' => $document['data']['source_publisher_type'], 'engagement' => $engagementCount, 'totalSentiment' => 0];
|
||||
if (array_key_exists("sentiment", $document['data'])) {
|
||||
$sentiment = 1;
|
||||
$tempData['totalSentiment'] = $sentiment;
|
||||
$tempData[$document['data']['sentiment']] = $sentiment;
|
||||
}
|
||||
array_push($tempInfluenceData, $tempData);
|
||||
$influenceData[$key]['data'] = $tempInfluenceData;
|
||||
} else {
|
||||
if (array_key_exists("sentiment", $document['data'])) {
|
||||
$influenceData[$key]['data'][$sourceHashCodeKey]['totalSentiment'] += 1;
|
||||
if (array_key_exists($document['data']['sentiment'], $influenceData[$key]['data'][$sourceHashCodeKey])) {
|
||||
$influenceData[$key]['data'][$sourceHashCodeKey][$document['data']['sentiment']] += 1;
|
||||
} else {
|
||||
$influenceData[$key]['data'][$sourceHashCodeKey][$document['data']['sentiment']] = 1;
|
||||
}
|
||||
|
||||
}
|
||||
$influenceData[$key]['data'][$sourceHashCodeKey]['engagement'] += $engagementCount;
|
||||
}
|
||||
} else {
|
||||
$tempData = [$groupByField => $document['data'][$groupByField], 'influence' => $document['data']['source_link'],
|
||||
'source_type' => $document['data']['source_publisher_type'], 'engagement' => $engagementCount, 'totalSentiment' => 0];
|
||||
if (array_key_exists("sentiment", $document['data'])) {
|
||||
$sentiment = 1;
|
||||
$tempData['totalSentiment'] = $sentiment;
|
||||
$tempData[$document['data']['sentiment']] = $sentiment;
|
||||
}
|
||||
$influenceData[$key]['data'][0] = $tempData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($clipDocuments as $clipDocument) {
|
||||
if ($feedsVal->getSubType() == 'clip_feed') {
|
||||
if ($feedsVal->getId() == $clipDocument['clipFeedId']) {
|
||||
$publishDate = substr($clipDocument['data']['published'], 0, 10);
|
||||
$publishDate = date('Y-m-d', strtotime($publishDate));
|
||||
if (($publishDate >= $startDt) && ($publishDate <= $endDt)) {
|
||||
if (array_key_exists($groupByField, $clipDocument['data'])) {
|
||||
$engagementCount = 0;
|
||||
if (array_key_exists("likes", $clipDocument['data'])) {
|
||||
$engagementCount = $clipDocument['data']['likes'];
|
||||
}
|
||||
if (array_key_exists("dislikes", $clipDocument['data'])) {
|
||||
$engagementCount += $clipDocument['data']['dislikes'];
|
||||
}
|
||||
if (array_key_exists("comments", $clipDocument['data'])) {
|
||||
$engagementCount += $clipDocument['data']['comments'];
|
||||
}
|
||||
if (array_key_exists("shares", $clipDocument['data'])) {
|
||||
$engagementCount += $clipDocument['data']['shares'];
|
||||
}
|
||||
$tempInfluenceData = $influenceData[$key]['data'];
|
||||
if (count($tempInfluenceData) > 0) {
|
||||
$sourceHashCodeKey = array_search($clipDocument['data'][$groupByField], array_column($tempInfluenceData, $groupByField));
|
||||
if ($sourceHashCodeKey === false) {
|
||||
$tempData = [$groupByField => $clipDocument['data'][$groupByField], 'influence' => $clipDocument['data']['source_link'],
|
||||
'source_type' => $clipDocument['data']['source_publisher_type'], 'engagement' => $engagementCount, 'totalSentiment' => 0];
|
||||
if (array_key_exists("sentiment", $clipDocument['data'])) {
|
||||
$sentiment = 1;
|
||||
$tempData['totalSentiment'] = $sentiment;
|
||||
$tempData[$clipDocument['data']['sentiment']] = $sentiment;
|
||||
}
|
||||
array_push($tempInfluenceData, $tempData);
|
||||
$influenceData[$key]['data'] = $tempInfluenceData;
|
||||
} else {
|
||||
if (array_key_exists("sentiment", $clipDocument['data'])) {
|
||||
$influenceData[$key]['data'][$sourceHashCodeKey]['totalSentiment'] += 1;
|
||||
if (array_key_exists($clipDocument['data']['sentiment'], $influenceData[$key]['data'][$sourceHashCodeKey])) {
|
||||
$influenceData[$key]['data'][$sourceHashCodeKey][$clipDocument['data']['sentiment']] += 1;
|
||||
} else {
|
||||
$influenceData[$key]['data'][$sourceHashCodeKey][$clipDocument['data']['sentiment']] = 1;
|
||||
}
|
||||
}
|
||||
$influenceData[$key]['data'][$sourceHashCodeKey]['engagement'] += $engagementCount;
|
||||
}
|
||||
} else {
|
||||
|
||||
$tempData = [$groupByField => $clipDocument['data'][$groupByField], 'influence' => $clipDocument['data']['source_link'],
|
||||
'source_type' => $clipDocument['data']['source_publisher_type'], 'engagement' => $engagementCount, 'totalSentiment' => 0];
|
||||
if (array_key_exists("sentiment", $clipDocument['data'])) {
|
||||
$sentiment = 1;
|
||||
$tempData['totalSentiment'] = $sentiment;
|
||||
$tempData[$clipDocument['data']['sentiment']] = $sentiment;
|
||||
}
|
||||
$influenceData[$key]['data'][0] = $tempData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($influenceData as $key => $influenceDataVal) {
|
||||
usort($influenceData[$key]['data'], function ($a, $b) {
|
||||
return $b['totalSentiment'] <=> $a['totalSentiment'];
|
||||
});
|
||||
}
|
||||
|
||||
foreach ($influenceData as $key => $dataVal) {
|
||||
$influenceData[$key]['data'] = array_slice($dataVal['data'], 0, 10);
|
||||
}
|
||||
|
||||
return $this->generateResponse([
|
||||
'data' => $influenceData
|
||||
], 200, []);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $filters
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getDuration($filters)
|
||||
{
|
||||
$duration = [];
|
||||
if (count($filters) > 0) {
|
||||
if (array_key_exists('date', $filters)) {
|
||||
$period = new DatePeriod(
|
||||
$filters['date']->getFilters()[0]->getValue(),
|
||||
new DateInterval('P1D'),
|
||||
$filters['date']->getFilters()[1]->getValue()
|
||||
);
|
||||
foreach ($period as $key => $value) {
|
||||
$duration[$value->format('Y-m-d')] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $duration;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,329 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller\V1;
|
||||
|
||||
use ApiBundle\Controller\AbstractCRUDController;
|
||||
use ApiBundle\Controller\Annotation\Roles;
|
||||
use ApiBundle\Response\ViewInterface;
|
||||
use ApiBundle\Security\Inspector\InspectorInterface;
|
||||
use ApiDocBundle\Controller\Annotation\AppApiDoc;
|
||||
use CacheBundle\Entity\Category;
|
||||
use CacheBundle\Repository\CategoryRepository;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Validator\ConstraintViolationInterface;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use UserBundle\Enum\AppLimitEnum;
|
||||
|
||||
/**
|
||||
* Class CategoryController
|
||||
* @package AppBundle\Controller\V1
|
||||
*
|
||||
* @Route("/categories", service="app.controller.category")
|
||||
*/
|
||||
class CategoryController extends AbstractCRUDController
|
||||
{
|
||||
|
||||
/**
|
||||
* Move specified feed to another category.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(
|
||||
* "/{movedId}/move_to/{destinationId}",
|
||||
* requirements={
|
||||
* "movedId": "\d+",
|
||||
* "destinationId": "\d+"
|
||||
* },
|
||||
* methods={ "POST" }
|
||||
* )
|
||||
* @AppApiDoc(
|
||||
* resource=true,
|
||||
* section="Category",
|
||||
* output={
|
||||
* "class"="Pagination<CacheBundle\Entity\Category>",
|
||||
* "groups"={ "id", "category_tree", "feed_tree" }
|
||||
* },
|
||||
* statusCodes={
|
||||
* 200="List of updated categories successfully returned.",
|
||||
* 400="Invalid data provided.",
|
||||
* 403="You don't have permissions to move this category.",
|
||||
* 404="Can't find moved or destination category."
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param integer $movedId A moved Category entity id.
|
||||
* @param integer $destinationId A Category entity id where the category is
|
||||
* moved.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface|\Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function moveAction($movedId, $destinationId)
|
||||
{
|
||||
$movedId = (integer) $movedId;
|
||||
$destinationId = (integer) $destinationId;
|
||||
$userId = \app\op\invokeIf($this->getCurrentUser(), 'getId');
|
||||
|
||||
/** @var CategoryRepository $repository */
|
||||
$repository = $this->getManager()->getRepository(Category::class);
|
||||
|
||||
$moved = $repository->get($movedId, $userId);
|
||||
if (! $moved instanceof Category) {
|
||||
return $this->generateResponse("Can't find category with id {$movedId}.", 404);
|
||||
}
|
||||
|
||||
//
|
||||
// Check that user don't try to move internal category.
|
||||
//
|
||||
if ($moved->isInternal()) {
|
||||
return $this->generateResponse('Can\'t move internal category.', 403);
|
||||
}
|
||||
|
||||
//
|
||||
// We should don't make any changes if client try to move category into
|
||||
// the same category.
|
||||
//
|
||||
|
||||
if ($moved->getParent()->getId() !== $destinationId) {
|
||||
$destination = $repository->get($destinationId, $userId, [
|
||||
Category::TYPE_CUSTOM,
|
||||
Category::TYPE_MY_CONTENT,
|
||||
]);
|
||||
if (! $destination instanceof Category) {
|
||||
return $this->generateResponse("Can't find category with id {$destinationId}.", 404);
|
||||
}
|
||||
|
||||
//
|
||||
// All ok, now we need to validate destination category id.
|
||||
//
|
||||
$moved->setParent($destination);
|
||||
|
||||
/** @var ValidatorInterface $validator */
|
||||
$validator = $this->get('validator');
|
||||
$errors = $validator->validate($moved);
|
||||
|
||||
if (count($errors) > 0) {
|
||||
//
|
||||
// Get all violation errors and send it to client.
|
||||
//
|
||||
$errors = array_map(function (ConstraintViolationInterface $violation) {
|
||||
return $violation->getMessage();
|
||||
}, iterator_to_array($errors));
|
||||
|
||||
return $this->generateResponse($errors, 400);
|
||||
}
|
||||
|
||||
//
|
||||
// Validation passed, update entity.
|
||||
//
|
||||
$this->getManager()->persist($moved);
|
||||
$this->getManager()->flush();
|
||||
}
|
||||
|
||||
return $this->forward('app.controller.category:listAction');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new category for current user.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(methods={ "POST" })
|
||||
* @AppApiDoc(
|
||||
* resource=true,
|
||||
* section="Category",
|
||||
* input={
|
||||
* "class"="CacheBundle\Form\CategoryType",
|
||||
* "name"=false
|
||||
* },
|
||||
* output={
|
||||
* "class"="CacheBundle\Entity\Category",
|
||||
* "groups"={ "id", "category" }
|
||||
* },
|
||||
* statusCodes={
|
||||
* 200="Category successfully created.",
|
||||
* 400="Invalid data provided.",
|
||||
* 403="You don't have permissions to create category."
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A Request instance.
|
||||
*
|
||||
* @return \CacheBundle\Entity\Category|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function createAction(Request $request)
|
||||
{
|
||||
return parent::createEntity($request, new Category($this->getCurrentUser()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of categories for current user.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(methods={ "GET" })
|
||||
* @AppApiDoc(
|
||||
* section="Category",
|
||||
* output={
|
||||
* "class"="Pagination<CacheBundle\Entity\Category>",
|
||||
* "groups"={ "id", "category_tree", "feed_tree" }
|
||||
* },
|
||||
* statusCodes={
|
||||
* 200="List of categories successfully returned."
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @return ViewInterface
|
||||
*/
|
||||
public function listAction()
|
||||
{
|
||||
/** @var CategoryRepository $repository */
|
||||
$repository = $this->getManager()->getRepository(Category::class);
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
$categories = $repository->getList($user->getId());
|
||||
$count = count($categories);
|
||||
|
||||
// Simulate pagination serialization.
|
||||
return $this->generateResponse([
|
||||
'data' => $categories,
|
||||
'count' => $count,
|
||||
'totalCount' => $count,
|
||||
'page' => 1,
|
||||
'limit' => $count,
|
||||
], 200, [
|
||||
'id',
|
||||
'category_tree',
|
||||
'feed_tree',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get specified category by id.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(
|
||||
* "/{id}",
|
||||
* requirements={ "id"="\d+" },
|
||||
* methods={ "GET" }
|
||||
* )
|
||||
* @AppApiDoc(
|
||||
* resource=true,
|
||||
* section="Category",
|
||||
* output={
|
||||
* "class"="CacheBundle\Entity\Category",
|
||||
* "groups"={ "id", "category", "feed_tree" }
|
||||
* },
|
||||
* statusCodes={
|
||||
* 200="Category successfully returned.",
|
||||
* 403="You don't have permissions to view this category.",
|
||||
* 404="Can't find category by specified id."
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param integer $id A Category entity id.
|
||||
*
|
||||
* @return \CacheBundle\Entity\Category|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function getAction($id)
|
||||
{
|
||||
return parent::getEntity($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update specified category.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(
|
||||
* "/{id}",
|
||||
* requirements={ "id"="\d+" },
|
||||
* methods={ "PUT" }
|
||||
* )
|
||||
* @AppApiDoc(
|
||||
* resource=true,
|
||||
* section="Category",
|
||||
* input={
|
||||
* "class"="CacheBundle\Form\CategoryType",
|
||||
* "name"=false
|
||||
* },
|
||||
* output={
|
||||
* "class"="CacheBundle\Entity\Category",
|
||||
* "groups"={ "id", "category" }
|
||||
* },
|
||||
* statusCodes={
|
||||
* 200="Category successfully updated.",
|
||||
* 400="Invalid data provided.",
|
||||
* 403="You don't have permissions to update this category.",
|
||||
* 404="Can't find category by specified id."
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A Request instance.
|
||||
* @param integer $id A Category entity id.
|
||||
*
|
||||
* @return \CacheBundle\Entity\Category|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function putAction(Request $request, $id)
|
||||
{
|
||||
return parent::putEntity($request, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete specified category.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(
|
||||
* "/{id}",
|
||||
* requirements={ "id"="\d+" },
|
||||
* methods={ "DELETE" }
|
||||
* )
|
||||
* @AppApiDoc(
|
||||
* resource=true,
|
||||
* section="Category",
|
||||
* statusCodes={
|
||||
* 204="Category successfully deleted.",
|
||||
* 403="You don't have permissions to delete this category.",
|
||||
* 404="Can't find category by specified id."
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param integer $id A Category entity id.
|
||||
*
|
||||
* @return array|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function deleteAction($id)
|
||||
{
|
||||
/** @var CategoryRepository $repository */
|
||||
$repository = $this->getManager()->getRepository($this->entity);
|
||||
$category = $repository->find($id);
|
||||
|
||||
if ($category === null) {
|
||||
return $this->generateResponse("Can't find category with id {$id}.", 404);
|
||||
}
|
||||
|
||||
$reasons = $this->checkAccess(InspectorInterface::DELETE, $category);
|
||||
if (count($reasons) > 0) {
|
||||
return $this->generateResponse($reasons, 403);
|
||||
}
|
||||
|
||||
//
|
||||
// Update restriction limit for current user only if deleted category has
|
||||
// some feeds.
|
||||
//
|
||||
$feedCount = $repository->computeFeedCounts($id);
|
||||
if ($feedCount > 0) {
|
||||
$user = $this->getCurrentUser();
|
||||
$user->releaseLimit(AppLimitEnum::feeds(), $feedCount);
|
||||
|
||||
$this->getManager()->persist($user);
|
||||
}
|
||||
|
||||
$this->getManager()->remove($category);
|
||||
$this->getManager()->flush();
|
||||
|
||||
return $this->generateResponse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller\V1;
|
||||
|
||||
use ApiBundle\Controller\Annotation\Roles;
|
||||
use ApiBundle\Security\Inspector\InspectorInterface;
|
||||
use ApiDocBundle\Controller\Annotation\AppApiDoc;
|
||||
use CacheBundle\Entity\Comment;
|
||||
use CacheBundle\Entity\Document;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Class CommentController
|
||||
* @package AppBundle\Controller\V1
|
||||
*
|
||||
* @Route("/comments", service="app.controller.comment")
|
||||
*/
|
||||
class CommentController extends AbstractV1CrudController
|
||||
{
|
||||
|
||||
/**
|
||||
* Update specified comment.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(
|
||||
* "/{commentId}",
|
||||
* requirements={ "commentId"="\d+" },
|
||||
* methods={ "PUT" }
|
||||
* )
|
||||
* @AppApiDoc(
|
||||
* section="Comment",
|
||||
* resource=false,input={
|
||||
* "class"="CacheBundle\Form\CommentType",
|
||||
* "name"=false
|
||||
* },
|
||||
* output={
|
||||
* "class"="CacheBundle\Entity\Comment",
|
||||
* "groups"={ "comment", "id" }
|
||||
* },
|
||||
* statusCodes={
|
||||
* 200="Comment successfully updated.",
|
||||
* 400="Invalid data provided.",
|
||||
* 403="You don't have permissions to update this comment.",
|
||||
* 404="Can't find comment by specified id."
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A Request instance.
|
||||
* @param integer $commentId A one of comment entity id.
|
||||
*
|
||||
* @return \ApiBundle\Entity\ManageableEntityInterface|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function putAction(Request $request, $commentId)
|
||||
{
|
||||
return parent::putEntity($request, $commentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete specified comment.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(
|
||||
* "/{commentId}",
|
||||
* requirements={ "commentId"="\d+" },
|
||||
* methods={ "DELETE" }
|
||||
* )
|
||||
* @AppApiDoc(
|
||||
* section="Comment",
|
||||
* resource=false,
|
||||
* statusCodes={
|
||||
* 204="Comment successfully deleted.",
|
||||
* 403="You don't have permissions to delete this comment.",
|
||||
* 404="Can't find comment by specified id."
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param integer $commentId A Comment entity id.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function deleteAction($commentId)
|
||||
{
|
||||
$entity = $this->em->getRepository(Comment::class)->find($commentId);
|
||||
|
||||
if ($entity === null) {
|
||||
return $this->generateResponse("Can't find comment with id {$commentId}.", 404);
|
||||
}
|
||||
|
||||
$reasons = $this->checkAccess(InspectorInterface::DELETE, $entity);
|
||||
if (count($reasons) > 0) {
|
||||
return $this->generateResponse($reasons, 403);
|
||||
}
|
||||
|
||||
$this->em->getRepository(Document::class)
|
||||
->createQueryBuilder('Document')
|
||||
->update()
|
||||
->set('Document.commentsCount', 'Document.commentsCount - 1')
|
||||
->where('Document.id = :id')
|
||||
->setParameter('id', \app\op\invokeIf($entity->getDocument(), 'getId'))
|
||||
->getQuery()
|
||||
->execute();
|
||||
|
||||
$this->em->remove($entity);
|
||||
$this->em->flush();
|
||||
|
||||
return $this->generateResponse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller\V1;
|
||||
|
||||
use ApiBundle\Controller\Annotation\Roles;
|
||||
use ApiBundle\Security\AccessChecker\AccessCheckerInterface;
|
||||
use ApiBundle\Security\Inspector\InspectorInterface;
|
||||
use ApiDocBundle\Controller\Annotation\AppApiDoc;
|
||||
use AppBundle\Controller\Traits\AccessCheckerTrait;
|
||||
use AppBundle\Controller\Traits\FormFactoryAwareTrait;
|
||||
use AppBundle\Controller\Traits\TokenStorageAwareTrait;
|
||||
use AppBundle\Entity\EmailedDocument;
|
||||
use AppBundle\Form\EmailedDocumentType;
|
||||
use CacheBundle\Comment\Manager\CommentManagerInterface;
|
||||
use CacheBundle\Entity\Comment;
|
||||
use CacheBundle\Entity\Document;
|
||||
use CacheBundle\Repository\CommentRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Tools\Pagination\Paginator;
|
||||
use OldSound\RabbitMqBundle\RabbitMq\ProducerInterface;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Component\Form\FormFactoryInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
|
||||
/**
|
||||
* Class DocumentController
|
||||
* @package AppBundle\Controller\V1
|
||||
*
|
||||
* @Route("/documents", service="app.controller.document")
|
||||
*/
|
||||
class DocumentController extends AbstractV1Controller
|
||||
{
|
||||
|
||||
use
|
||||
TokenStorageAwareTrait,
|
||||
FormFactoryAwareTrait,
|
||||
AccessCheckerTrait;
|
||||
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @var CommentManagerInterface
|
||||
*/
|
||||
private $commentManager;
|
||||
|
||||
/**
|
||||
* @var ProducerInterface
|
||||
*/
|
||||
private $emailProducer;
|
||||
|
||||
/**
|
||||
* DocumentController constructor.
|
||||
*
|
||||
* @param TokenStorageInterface $tokenStorage A TokenStorageInterface
|
||||
* instance.
|
||||
* @param FormFactoryInterface $formFactory A FormFactoryInterface
|
||||
* instance.
|
||||
* @param AccessCheckerInterface $accessChecker A AccessCheckerInterface
|
||||
* instance.
|
||||
* @param EntityManagerInterface $em A EntityManagerInterface
|
||||
* instance.
|
||||
* @param CommentManagerInterface $commentManager A CommentManagerInterface
|
||||
* instance.
|
||||
* @param ProducerInterface $emailProducer A producer interface for
|
||||
* emailing documents.
|
||||
*/
|
||||
public function __construct(
|
||||
TokenStorageInterface $tokenStorage,
|
||||
FormFactoryInterface $formFactory,
|
||||
AccessCheckerInterface $accessChecker,
|
||||
EntityManagerInterface $em,
|
||||
CommentManagerInterface $commentManager,
|
||||
ProducerInterface $emailProducer
|
||||
) {
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->formFactory = $formFactory;
|
||||
$this->accessChecker = $accessChecker;
|
||||
$this->em = $em;
|
||||
$this->commentManager = $commentManager;
|
||||
$this->emailProducer = $emailProducer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new comment for specified document.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(
|
||||
* "/{documentId}/comments",
|
||||
* requirements={ "documentId"="\d+" },
|
||||
* methods={ "POST" }
|
||||
* )
|
||||
* @AppApiDoc(
|
||||
* section="Document",
|
||||
* resource=true,
|
||||
* input={
|
||||
* "class"="CacheBundle\Form\CommentType",
|
||||
* "name"=false
|
||||
* },
|
||||
* output={
|
||||
* "class"="CacheBundle\Entity\Comment",
|
||||
* "groups"={ "comment", "id" }
|
||||
* },
|
||||
* statusCodes={
|
||||
* 200="Comment successfully saved.",
|
||||
* 400="Invalid data provided."
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A Request instance.
|
||||
* @param integer $documentId Commented Document entity id.
|
||||
*
|
||||
* @return \ApiBundle\Entity\ManageableEntityInterface|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function createCommentAction(Request $request, $documentId)
|
||||
{
|
||||
$document = $this->em->getRepository(Document::class)->find($documentId);
|
||||
|
||||
if (! $document instanceof Document) {
|
||||
return $this->generateResponse([[
|
||||
'message' => 'Document not found',
|
||||
'transKey' => 'commentDocumentInvalidDocument',
|
||||
'type' => 'error',
|
||||
'parameters' => [ 'current' => $documentId ],
|
||||
], ], 404);
|
||||
}
|
||||
|
||||
$comment = new Comment($this->getCurrentUser(), '');
|
||||
|
||||
$form = $this->createForm($comment->getCreateFormClass(), $comment);
|
||||
|
||||
// Submit data into form.
|
||||
$form->submit($request->request->all());
|
||||
if ($form->isValid()) {
|
||||
//
|
||||
// Check that current user can create this entity.
|
||||
// If user don't have rights to create this entity we should send all
|
||||
// founded restrictions to client.
|
||||
//
|
||||
$reasons = $this->checkAccess(InspectorInterface::CREATE, $comment);
|
||||
if (count($reasons) > 0) {
|
||||
//
|
||||
// User don't have rights to create this entity so send all
|
||||
// founded restriction reasons to client.
|
||||
//
|
||||
return $this->generateResponse($reasons, 403);
|
||||
}
|
||||
|
||||
$this->commentManager->addComment($comment, $document);
|
||||
|
||||
$this->em->persist($comment);
|
||||
$this->em->flush();
|
||||
|
||||
return $comment;
|
||||
}
|
||||
|
||||
// Client send invalid data.
|
||||
return $this->generateResponse($form, 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of comments for specified document.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(
|
||||
* "/{documentId}/comments",
|
||||
* requirements={ "documentId"="\d+" },
|
||||
* methods={ "GET" }
|
||||
* )
|
||||
* @AppApiDoc(
|
||||
* section="Document",
|
||||
* resource=true,
|
||||
* filters={
|
||||
* {
|
||||
* "name"="offset",
|
||||
* "dataType"="integer",
|
||||
* "description"="Offset from beginning of collection, start from 1",
|
||||
* "requirements"="\d+",
|
||||
* "default"="1"
|
||||
* },
|
||||
* {
|
||||
* "name"="limit",
|
||||
* "dataType"="integer",
|
||||
* "description"="Max entities per page, default 10",
|
||||
* "requirements"="\d+",
|
||||
* "default"="10"
|
||||
* },
|
||||
* },
|
||||
* output={
|
||||
* "class"="Paginated<CacheBundle\Entity\Comment>",
|
||||
* "groups"={ "comment", "id" }
|
||||
* },
|
||||
* statusCodes={
|
||||
* 200="List of comments returned.",
|
||||
* 404="Invalid document id."
|
||||
* }
|
||||
* )
|
||||
* @param Request $request A Request instance.
|
||||
* @param integer $documentId A Document entity id.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function getCommentsAction(Request $request, $documentId)
|
||||
{
|
||||
$document = $this->em->getRepository(Document::class)->find($documentId);
|
||||
|
||||
if (! $document instanceof Document) {
|
||||
return $this->generateResponse([[
|
||||
'message' => 'Document not found',
|
||||
'transKey' => 'getDocumentCommentsInvalidDocument',
|
||||
'type' => 'error',
|
||||
'parameters' => [ 'current' => $documentId ],
|
||||
], ], 404);
|
||||
}
|
||||
|
||||
/** @var CommentRepository $repository */
|
||||
$repository = $this->em->getRepository(Comment::class);
|
||||
$qb = $repository->getListForDocument($documentId);
|
||||
|
||||
$offset = $request->query->getInt('offset', CommentManagerInterface::NEW_COMMENT_POOL_SIZE);
|
||||
$limit = $request->query->getInt('limit', 10);
|
||||
|
||||
$qb
|
||||
->setFirstResult($offset)
|
||||
->setMaxResults($limit);
|
||||
|
||||
return $this->generateResponse(new Paginator($qb), 200, [ 'id', 'comment' ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send specified documents content to recipients.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route(
|
||||
* "/email",
|
||||
* methods={ "POST" }
|
||||
* )
|
||||
* @AppApiDoc(
|
||||
* section="Document",
|
||||
* resource=true,
|
||||
* input={
|
||||
* "class"="AppBundle\Form\EmailedDocumentType",
|
||||
* "name"=false
|
||||
* },
|
||||
* statusCodes={
|
||||
* 204="Email's sent.",
|
||||
* 400="Invalid data."
|
||||
* }
|
||||
* )
|
||||
* @param Request $request A Request instance.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function emailAction(Request $request)
|
||||
{
|
||||
$emailedDocument = new EmailedDocument();
|
||||
$form = $this->createForm(EmailedDocumentType::class, $emailedDocument);
|
||||
|
||||
$form->submit($request->request->all());
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$this->em->persist($emailedDocument);
|
||||
$this->em->flush();
|
||||
|
||||
$this->emailProducer->publish($emailedDocument->getId());
|
||||
|
||||
return $this->generateResponse();
|
||||
}
|
||||
|
||||
return $this->generateResponse($form, 400);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller\V1;
|
||||
|
||||
use ApiBundle\Controller\Annotation\Roles;
|
||||
use AppBundle\Controller\Traits\FormFactoryAwareTrait;
|
||||
use AppBundle\Controller\Traits\TokenStorageAwareTrait;
|
||||
use AppBundle\Exception\LimitExceedException;
|
||||
use AppBundle\Form\SearchRequest\SimpleQuerySearchRequestType;
|
||||
use AppBundle\Manager\SimpleQuery\SimpleQueryManagerInterface;
|
||||
use AppBundle\Manager\Source\SourceManagerInterface;
|
||||
use CacheBundle\Document\Extractor\DocumentContentExtractorInterface;
|
||||
use Common\Enum\FieldNameEnum;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use IndexBundle\Model\ArticleDocumentInterface;
|
||||
use IndexBundle\SearchRequest\SearchRequestBuilderInterface;
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Component\Form\FormFactoryInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use UserBundle\Enum\AppLimitEnum;
|
||||
use UserBundle\Enum\ThemeOptionExtractEnum;
|
||||
|
||||
/**
|
||||
* Class QueryController
|
||||
* @package AppBundle\Controller\V1
|
||||
*
|
||||
* @Route("/query", service="app.controller.query")
|
||||
*/
|
||||
class QueryController extends AbstractV1Controller
|
||||
{
|
||||
|
||||
use
|
||||
FormFactoryAwareTrait,
|
||||
TokenStorageAwareTrait;
|
||||
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @var SourceManagerInterface
|
||||
*/
|
||||
private $sourceManager;
|
||||
|
||||
/**
|
||||
* @var SimpleQueryManagerInterface
|
||||
*/
|
||||
private $queryManager;
|
||||
|
||||
/**
|
||||
* @var DocumentContentExtractorInterface
|
||||
*/
|
||||
private $extractor;
|
||||
|
||||
/**
|
||||
* QueryController constructor.
|
||||
*
|
||||
* @param FormFactoryInterface $formFactory A
|
||||
* FormFactoryInterface
|
||||
* instance.
|
||||
* @param EntityManagerInterface $em A
|
||||
* RestrictionsRepositoryInterface
|
||||
* instance.
|
||||
* @param TokenStorageInterface $tokenStorage A
|
||||
* TokenStorageInterface
|
||||
* instance.
|
||||
* @param SourceManagerInterface $sourceManager A
|
||||
* SourceManagerInterface
|
||||
* instance.
|
||||
* @param SimpleQueryManagerInterface $queryManager A
|
||||
* SimpleQueryManagerInterface
|
||||
* instance.
|
||||
* @param DocumentContentExtractorInterface $extractor A
|
||||
* DocumentContentExtractorInterface
|
||||
* instance.
|
||||
*/
|
||||
public function __construct(
|
||||
FormFactoryInterface $formFactory,
|
||||
EntityManagerInterface $em,
|
||||
TokenStorageInterface $tokenStorage,
|
||||
SourceManagerInterface $sourceManager,
|
||||
SimpleQueryManagerInterface $queryManager,
|
||||
DocumentContentExtractorInterface $extractor
|
||||
) {
|
||||
$this->formFactory = $formFactory;
|
||||
$this->em = $em;
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->sourceManager = $sourceManager;
|
||||
$this->queryManager = $queryManager;
|
||||
$this->extractor = $extractor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make simple search without saving query in database.
|
||||
* Fetched documents are cached but not indexed.
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @Route("/search", methods={ "POST" })
|
||||
* @ApiDoc(
|
||||
* resource="Search",
|
||||
* section="Query",
|
||||
* input={
|
||||
* "class"="AppBundle\Form\SearchRequest\SimpleQuerySearchRequestType",
|
||||
* "name"=false
|
||||
* },
|
||||
* output={
|
||||
* "class"="",
|
||||
* "data"={
|
||||
* "documents"={
|
||||
* "class"="Pagination<CacheBundle\Entity\Document>",
|
||||
* "groups"={ "document" }
|
||||
* },
|
||||
* "advancedFilters"={
|
||||
* "dataType"="array",
|
||||
* "required"=true,
|
||||
* "readonly"=true,
|
||||
* "description"="Array of advanced filters values for this search request."
|
||||
* },
|
||||
* "stats"={
|
||||
* "dataType"="object",
|
||||
* "required"=true,
|
||||
* "readonly"=true,
|
||||
* "description"="Internal statistics, showed only in staging and local developers machine.",
|
||||
* "children"={
|
||||
* "totalOnPage"={
|
||||
* "dataType"="integer",
|
||||
* "required"=true,
|
||||
* "readonly"=true,
|
||||
* "description"="Total founded document on current page."
|
||||
* },
|
||||
* "newDocuments"={
|
||||
* "dataType"="integer",
|
||||
* "required"=true,
|
||||
* "readonly"=true,
|
||||
* "description"="Number of documents that were not in our database."
|
||||
* },
|
||||
* "alreadyExistsDocuments"={
|
||||
* "dataType"="integer",
|
||||
* "required"=true,
|
||||
* "readonly"=true,
|
||||
* "description"="Number of documents that already in our database."
|
||||
* },
|
||||
* "fromCache"={
|
||||
* "dataType"="boolean",
|
||||
* "required"=true,
|
||||
* "readonly"=true,
|
||||
* "description"="Flag, all documents fetched from our internal cache if set."
|
||||
* },
|
||||
* "expiresAt"={
|
||||
* "dataType"="datetime",
|
||||
* "required"=true,
|
||||
* "readonly"=true,
|
||||
* "description"="When this query is expired."
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* },
|
||||
* statusCodes={
|
||||
* 200="Search completed.",
|
||||
* 400="Invalid data provided"
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A Request instance.
|
||||
*
|
||||
* @return array|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function searchAction(Request $request)
|
||||
{
|
||||
$form = $this->createForm(SimpleQuerySearchRequestType::class);
|
||||
|
||||
$form->submit($request->request->all());
|
||||
if ($form->isValid()) {
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
try {
|
||||
$user->useLimit(AppLimitEnum::searches());
|
||||
} catch (LimitExceedException $exception) {
|
||||
return $this->generateResponse([
|
||||
'failedRestriction' => AppLimitEnum::SEARCHES,
|
||||
'restrictions' => $user->getRestrictions(),
|
||||
], 402);
|
||||
}
|
||||
|
||||
$this->em->persist($user);
|
||||
$this->em->flush();
|
||||
|
||||
/** @var SearchRequestBuilderInterface $builder */
|
||||
$builder = $form->getData();
|
||||
|
||||
$searchRequest = $builder
|
||||
->setFields([
|
||||
FieldNameEnum::TITLE,
|
||||
FieldNameEnum::MAIN,
|
||||
])
|
||||
->addSort(FieldNameEnum::PUBLISHED, 'desc')
|
||||
->build();
|
||||
|
||||
$response = $this->queryManager->searchAndCache(
|
||||
$searchRequest,
|
||||
$request->request->get('filters', []),
|
||||
$request->request->get('advancedFilters', [])
|
||||
);
|
||||
|
||||
$query = $response->getQuery();
|
||||
|
||||
$response->mapDocuments(function (ArticleDocumentInterface $document) use ($query) {
|
||||
return $document->mapNormalizedData(function (array $data) use ($query) {
|
||||
$result = $this->extractor->extract(
|
||||
$data['content'],
|
||||
$query->getRaw(),
|
||||
ThemeOptionExtractEnum::start(),
|
||||
true
|
||||
);
|
||||
|
||||
$data['content'] = $result->getText() . (
|
||||
mb_strlen($data['content']) > $result->getLength()
|
||||
? '...'
|
||||
: ''
|
||||
);
|
||||
|
||||
return $data;
|
||||
});
|
||||
});
|
||||
|
||||
$result = [
|
||||
'documents' => $this->paginate($response, $builder->getPage(), $builder->getLimit()),
|
||||
'advancedFilters' => $searchRequest->getAvailableAdvancedFilters() ?: (object) [],
|
||||
];
|
||||
|
||||
//
|
||||
// Return internal statistic.
|
||||
//
|
||||
$result['stats'] = [
|
||||
'newDocuments' => $response->getUniqueCount(),
|
||||
'alreadyExistsDocuments' => $response->count() - $response->getUniqueCount(),
|
||||
'fromCache' => $response->isFromCache(),
|
||||
'expiresAt' => $query->getExpirationDate()->format('c'),
|
||||
];
|
||||
|
||||
//
|
||||
// Return meta information about query.
|
||||
//
|
||||
$sources = $this->sourceManager->getSourcesForQuery($query, [ 'id', 'title', 'type' ]);
|
||||
$sourceLists = $this->sourceManager->getSourceListsForQuery($query, [ 'id', 'name' ]);
|
||||
|
||||
$result['meta'] = [
|
||||
'type' => 'query',
|
||||
'status' => 'synced',
|
||||
'search' => [
|
||||
'query' => $query->getRaw(),
|
||||
'filters' => $query->getRawFilters() ?: (object) [],
|
||||
'advancedFilters' => $query->getRawAdvancedFilters() ?: (object) [],
|
||||
],
|
||||
'sources' => $sources,
|
||||
'sourceLists' => $sourceLists,
|
||||
];
|
||||
|
||||
return $this->generateResponse($result);
|
||||
}
|
||||
|
||||
return $this->generateResponse($form, 400);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller\V1;
|
||||
|
||||
use AppBundle\Controller\Traits\FormFactoryAwareTrait;
|
||||
use AppBundle\Controller\Traits\TokenStorageAwareTrait;
|
||||
use AppBundle\Manager\Source\SourceManagerInterface;
|
||||
use CacheBundle\Entity\SourceList;
|
||||
use CacheBundle\Form\Sources\SourceSearchType;
|
||||
use CacheBundle\Repository\SourceListRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use IndexBundle\Model\SourceDocument;
|
||||
use IndexBundle\SearchRequest\SearchRequestBuilder;
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Component\Form\FormFactoryInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use ApiBundle\Controller\Annotation\Roles;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
|
||||
/**
|
||||
* Class SourceIndexController
|
||||
* @package AppBundle\Controller\V1
|
||||
*
|
||||
* @Route("/source-index", service="app.controller.source-index")
|
||||
*/
|
||||
class SourceIndexController extends AbstractV1Controller
|
||||
{
|
||||
|
||||
use
|
||||
TokenStorageAwareTrait,
|
||||
FormFactoryAwareTrait;
|
||||
|
||||
/**
|
||||
* @var SourceManagerInterface
|
||||
*/
|
||||
private $sourceManager;
|
||||
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* SourceIndexController constructor.
|
||||
*
|
||||
* @param TokenStorageInterface $tokenStorage A TokenStorageInterface
|
||||
* instance.
|
||||
* @param FormFactoryInterface $formFactory A FormFactoryInterface
|
||||
* instance.
|
||||
* @param SourceManagerInterface $sourceManager A SourceManagerInterface
|
||||
* instance.
|
||||
* @param EntityManagerInterface $em A EntityManagerInterface
|
||||
* instance.
|
||||
*/
|
||||
public function __construct(
|
||||
TokenStorageInterface $tokenStorage,
|
||||
FormFactoryInterface $formFactory,
|
||||
SourceManagerInterface $sourceManager,
|
||||
EntityManagerInterface $em
|
||||
) {
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->formFactory = $formFactory;
|
||||
$this->sourceManager = $sourceManager;
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetch all sources from our cache.
|
||||
*
|
||||
* @Route("/", methods={ "POST" })
|
||||
*
|
||||
* @ApiDoc(
|
||||
* resource=true,
|
||||
* section="Source Index",
|
||||
* input={
|
||||
* "class"="CacheBundle\Form\Sources\SourceSearchType",
|
||||
* "name"=false
|
||||
* },
|
||||
* output={
|
||||
* "class"="Pagination<IndexBundle\Model\SourceDocument>",
|
||||
* "groups"={ "id", "source" }
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A Request instance.
|
||||
*
|
||||
* @return \Knp\Component\Pager\Pagination\PaginationInterface|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function listAction(Request $request)
|
||||
{
|
||||
$form = $this->createForm(SourceSearchType::class);
|
||||
|
||||
$form->submit($request->request->all());
|
||||
|
||||
if ($form->isValid()) {
|
||||
/** @var SearchRequestBuilder $searchRequestBuilder */
|
||||
$searchRequestBuilder = $form->getData();
|
||||
$searchRequestBuilder->setUser($this->getCurrentUser());
|
||||
|
||||
$response = $this->sourceManager->find($searchRequestBuilder);
|
||||
|
||||
$advancedFilters = $this->sourceManager->getAvailableFilters($searchRequestBuilder);
|
||||
|
||||
$sort = $searchRequestBuilder->getSorts();
|
||||
$sort = [
|
||||
'field' => array_search(key($sort), SourceSearchType::$fields),
|
||||
'direction' => current($sort),
|
||||
];
|
||||
|
||||
return $this->generateResponse([
|
||||
'sources' => $this->paginate($response, $searchRequestBuilder->getPage(), $searchRequestBuilder->getLimit()),
|
||||
'advancedFilters' => $advancedFilters ?: (object) [],
|
||||
'meta' => [
|
||||
'query' => $request->request->get('query'),
|
||||
'advancedFilters' => $request->request->get('advancedFilters', [])?: (object) [],
|
||||
'sort' => $sort,
|
||||
],
|
||||
], 200, [ 'id', 'source' ]);
|
||||
}
|
||||
|
||||
return $this->generateResponse($form, 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace source lists for specified source.
|
||||
*
|
||||
* @Route("/{id}/list", methods={ "POST" })
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @ApiDoc(
|
||||
* resource=true,
|
||||
* section="Source Index",
|
||||
* parameters={
|
||||
* "sourceList"={
|
||||
* "name"="sourceLists",
|
||||
* "dataType"="array",
|
||||
* "description"="Array of source lists ids."
|
||||
* }
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A Request instance.
|
||||
* @param integer $id A Source entity id.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function replaceListAction(Request $request, $id)
|
||||
{
|
||||
if (count($this->sourceManager->getIndex()->has($id)) > 0) {
|
||||
return $this->generateResponse([ [
|
||||
'message' => "Can't find source with id {$id}",
|
||||
'transKey' => 'replaceSourceUnknown',
|
||||
'type' => 'error',
|
||||
'parameters' => [ 'current' => $id ],
|
||||
], ], 404);
|
||||
}
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
$sourceLists = $request->request->get('sourceLists');
|
||||
|
||||
if (! is_array($sourceLists)) {
|
||||
return $this->generateResponse([[
|
||||
'message' => 'sourceLists: This value should not be empty.',
|
||||
'transKey' => 'replaceSourceListsEmpty',
|
||||
'type' => 'error',
|
||||
'parameters' => [ 'current' => null ],
|
||||
], ], 400);
|
||||
}
|
||||
|
||||
/** @var SourceListRepository $repository */
|
||||
$repository = $this->em->getRepository(SourceList::class);
|
||||
$foundedIds = $repository->sanitizeIds($sourceLists, $user->getId());
|
||||
|
||||
if (count($foundedIds) !== count($sourceLists)) {
|
||||
//
|
||||
// Some of provided id is not found or not owned by current user.
|
||||
//
|
||||
return $this->generateResponse([ [
|
||||
'message' => 'sourceLists: This value is invalid.',
|
||||
'transKey' => 'replaceSourceListInvalid',
|
||||
'type' => 'error',
|
||||
'parameters' => [
|
||||
'current' => $sourceLists,
|
||||
'invalid' => array_diff($sourceLists, $foundedIds),
|
||||
],
|
||||
], ], 400);
|
||||
}
|
||||
|
||||
$this->sourceManager->replaceRelation($id, $foundedIds);
|
||||
|
||||
return $this->generateResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Sources to Sources lists
|
||||
*
|
||||
* @Route("/add-to-sources-list", methods={ "POST" })
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @ApiDoc(
|
||||
* resource=true,
|
||||
* section="Source Index",
|
||||
* parameters={
|
||||
* "sources"={
|
||||
* "name"="sources",
|
||||
* "dataType"="integer",
|
||||
* "actualType"="collection",
|
||||
* "required"=true,
|
||||
* "description"="Array of Source id."
|
||||
* },
|
||||
* "sourceLists"={
|
||||
* "name"="sourceLists",
|
||||
* "dataType"="integer",
|
||||
* "actualType"="collection",
|
||||
* "required"=true,
|
||||
* "description"="Array of Sources Lists id."
|
||||
* },
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A Request instance.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function addToSourceListAction(Request $request)
|
||||
{
|
||||
$sources = (array) $request->request->get('sources', []);
|
||||
$sourceLists = (array) $request->request->get('sourceLists', []);
|
||||
|
||||
//
|
||||
// Check that all fields are provided.
|
||||
//
|
||||
if (count($sources) === 0) {
|
||||
return $this->generateResponse(
|
||||
[
|
||||
[
|
||||
'message' => 'Sources should be selected.',
|
||||
'transKey' => 'sourceToListsSourcesEmpty',
|
||||
'type' => 'error',
|
||||
'parameters' => [
|
||||
'current' => $sources,
|
||||
],
|
||||
],
|
||||
],
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
if (count($sourceLists) === 0) {
|
||||
return $this->generateResponse(
|
||||
[
|
||||
[
|
||||
'message' => 'Source lists should be selected.',
|
||||
'transKey' => 'sourceToListsSourceListsEmpty',
|
||||
'type' => 'error',
|
||||
'parameters' => [
|
||||
'current' => $sourceLists,
|
||||
],
|
||||
],
|
||||
],
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
|
||||
//
|
||||
// Validate specified sources and source lists ids.
|
||||
//
|
||||
/** @var SourceListRepository $repository */
|
||||
$repository = $this->em->getRepository('CacheBundle:SourceList');
|
||||
|
||||
$existsSources = $this->sourceManager->getIndex()->get($sources, 'id');
|
||||
$existsSources = array_map(function (SourceDocument $document) {
|
||||
return $document['id'];
|
||||
}, $existsSources);
|
||||
if (count($sources) !== count($existsSources)) {
|
||||
return $this->generateResponse(
|
||||
[
|
||||
[
|
||||
'message' => 'sources: This value is invalid.',
|
||||
'transKey' => 'sourceToListsSourcesInvalid',
|
||||
'type' => 'error',
|
||||
'parameters' => $sources,
|
||||
],
|
||||
],
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
$existsSourceLists = $repository->sanitizeIds($sourceLists, $user->getId());
|
||||
if (count($sourceLists) !== count($existsSourceLists)) {
|
||||
return $this->generateResponse(
|
||||
[
|
||||
[
|
||||
'message' => 'sourceLists: This value is invalid.',
|
||||
'transKey' => 'sourceToListsSourceListsInvalid',
|
||||
'type' => 'error',
|
||||
'parameters' => $sourceLists,
|
||||
],
|
||||
],
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
$this->sourceManager->bindSourcesToLists($user, $sources, $sourceLists);
|
||||
|
||||
return $this->generateResponse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,486 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller\V1;
|
||||
|
||||
use ApiBundle\Controller\AbstractApiController;
|
||||
use ApiBundle\Security\Inspector\InspectorInterface;
|
||||
use AppBundle\AppBundleServices;
|
||||
use AppBundle\Manager\Source\SourceManagerInterface;
|
||||
use CacheBundle\CacheBundleServices;
|
||||
use CacheBundle\Entity\SourceList;
|
||||
use CacheBundle\Entity\SourceToSourceList;
|
||||
use CacheBundle\Form\Sources\SourceListSearchType;
|
||||
use CacheBundle\Form\Sources\SourceListType;
|
||||
use CacheBundle\Form\Sources\SourceSearchType;
|
||||
use CacheBundle\Repository\SourceListRepository;
|
||||
use CacheBundle\Security\Inspector\SourceListInspector;
|
||||
use IndexBundle\SearchRequest\SearchRequestBuilder;
|
||||
use Knp\Component\Pager\PaginatorInterface;
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use ApiBundle\Controller\Annotation\Roles;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
|
||||
/**
|
||||
* Class SourceIndexController
|
||||
* @package AppBundle\Controller\V1
|
||||
*
|
||||
* @Route("/source-list", service="app.controller.source-list")
|
||||
*/
|
||||
class SourceListController extends AbstractApiController
|
||||
{
|
||||
|
||||
/**
|
||||
* Get list of sources for the user
|
||||
*
|
||||
* @Route("/list", methods={ "POST" })
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @ApiDoc(
|
||||
* resource=true,
|
||||
* section="Source List",
|
||||
* input={
|
||||
* "class"="CacheBundle\Form\Sources\SourceListSearchType",
|
||||
* "name"=false
|
||||
* },
|
||||
* output={
|
||||
* "class"="Pagination<CacheBundle\Entity\SourceList>",
|
||||
* "groups"={ "id", "source_list" }
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A Request instance.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function indexAction(Request $request)
|
||||
{
|
||||
$form = $this->createForm(SourceListSearchType::class);
|
||||
$form->submit($request->request->all());
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$data = $form->getData();
|
||||
|
||||
$page = (int) $data['page'];
|
||||
$limit = (int) $data['limit'];
|
||||
$onlyShared = (boolean) $data['onlyShared'];
|
||||
|
||||
$user = $this->getCurrentUser();
|
||||
$em = $this->getManager();
|
||||
|
||||
/** @var SourceListRepository $sourceListRepository */
|
||||
$sourceListRepository = $em->getRepository(SourceList::class);
|
||||
/** @var PaginatorInterface $paginator */
|
||||
$paginator = $this->get('knp_paginator');
|
||||
|
||||
$qb = $sourceListRepository->getSourcesListsQB($user->getId(), $data['sort'], $onlyShared);
|
||||
$pagination = $paginator->paginate(
|
||||
$qb,
|
||||
$page,
|
||||
$limit
|
||||
);
|
||||
|
||||
$sort = $data['sort'] ;
|
||||
$sort = [
|
||||
'field' => array_search(key($sort), SourceListSearchType::$fields),
|
||||
'direction' => current($sort),
|
||||
];
|
||||
|
||||
/** @var NormalizerInterface $normalizer */
|
||||
$normalizer = $this->get('serializer');
|
||||
$result = $normalizer->normalize($pagination, null, ['id', 'source_list']);
|
||||
$result['sort'] = $sort;
|
||||
|
||||
return $this->generateResponse($result, 200);
|
||||
}
|
||||
|
||||
return $this->generateResponse($form, 400);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a source list
|
||||
*
|
||||
* @Route("/", methods={ "POST" })
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @ApiDoc(
|
||||
* resource=true,
|
||||
* section="Source List",
|
||||
* input={
|
||||
* "class"="CacheBundle\Form\Sources\SourceListType",
|
||||
* "name"=false
|
||||
* },
|
||||
* output={
|
||||
* "class"="CacheBundle\Entity\SourceList",
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A Request entity instance.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function createAction(Request $request)
|
||||
{
|
||||
$sourceList = new SourceList();
|
||||
$sourceList->setUser($this->getCurrentUser());
|
||||
|
||||
$form = $this->createForm(SourceListType::class, $sourceList);
|
||||
|
||||
$form->submit($request->request->all());
|
||||
if ($form->isValid()) {
|
||||
$em = $this->getManager();
|
||||
$em->persist($sourceList);
|
||||
$em->flush();
|
||||
|
||||
return $this->generateResponse($sourceList, 200, [
|
||||
'source_list',
|
||||
'id',
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->generateResponse($form, 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename a source list
|
||||
*
|
||||
* @Route(
|
||||
* "/{id}",
|
||||
* requirements={ "id": "\d+" },
|
||||
* methods={ "PUT" }
|
||||
* )
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @ApiDoc(
|
||||
* resource=true,
|
||||
* section="Source List",
|
||||
* parameters={
|
||||
* "name"={
|
||||
* "name"="name",
|
||||
* "dataType"="string",
|
||||
* "required"="true",
|
||||
* "description"="A new name of the source list"
|
||||
* }
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A HTTP Request instance.
|
||||
* @param SourceList $sourceList A updated SourceList instance.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function updateAction(Request $request, SourceList $sourceList)
|
||||
{
|
||||
$form = $this->createForm(SourceListType::class, $sourceList);
|
||||
|
||||
$form->submit($request->request->all());
|
||||
if ($form->isValid()) {
|
||||
$em = $this->getManager();
|
||||
|
||||
$reasons = $this->checkAccess(InspectorInterface::UPDATE, $sourceList);
|
||||
if (count($reasons) > 0) {
|
||||
return $this->generateResponse($reasons, 403);
|
||||
}
|
||||
|
||||
$sourceList->setUpdatedBy($this->getCurrentUser());
|
||||
|
||||
$em->persist($sourceList);
|
||||
$em->flush();
|
||||
|
||||
return $this->generateResponse($sourceList, 200, [
|
||||
'source_list',
|
||||
'id',
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->generateResponse($form, 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a source list
|
||||
*
|
||||
* @Route("/{id}",
|
||||
* requirements={ "id": "\d+" },
|
||||
* methods={ "DELETE" }
|
||||
* )
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @ApiDoc(
|
||||
* resource=true,
|
||||
* section="Source List",
|
||||
* parameters={
|
||||
* "id"={
|
||||
* "name"="id",
|
||||
* "dataType"="integer",
|
||||
* "required"="true",
|
||||
* "description"="Id of the source list which changing"
|
||||
* }
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param SourceList $sourceList A deleted SourceList instance.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function deleteAction(SourceList $sourceList)
|
||||
{
|
||||
$reasons = $this->checkAccess(InspectorInterface::DELETE, $sourceList);
|
||||
if (count($reasons) > 0) {
|
||||
return $this->generateResponse($reasons, 403);
|
||||
}
|
||||
|
||||
//
|
||||
// Remove this source list from all sources which is contains in it.
|
||||
//
|
||||
/** @var SourceManagerInterface $sourceManager */
|
||||
$sourceManager = $this->container->get(CacheBundleServices::SOURCE_CACHE);
|
||||
$sourceManager->unbindSourcesFromLists($sourceList->getId());
|
||||
|
||||
$em = $this->getManager();
|
||||
$em->remove($sourceList);
|
||||
$em->flush();
|
||||
|
||||
return $this->generateResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of sources for specified source list.
|
||||
*
|
||||
* @Route("/{id}/sources/search",
|
||||
* requirements={ "id": "\d+" },
|
||||
* methods={ "POST" }
|
||||
* )
|
||||
*
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @ApiDoc(
|
||||
* resource="Sources of specified source list",
|
||||
* section="Source List",
|
||||
* input={
|
||||
* "class"="CacheBundle\Form\Sources\SourceSearchType",
|
||||
* "name"=false
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A Request instance.
|
||||
* @param integer $id A SourceList entity id.
|
||||
*
|
||||
* @return \Knp\Component\Pager\Pagination\PaginationInterface|\ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function sourcesAction(Request $request, $id)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
/** @var SourceListRepository $repository */
|
||||
$repository = $this->getManager()->getRepository('CacheBundle:SourceList');
|
||||
$sourceList = $repository->getSourcesLists($id, $user->getId());
|
||||
|
||||
if ($sourceList === null) {
|
||||
return $this->generateResponse("Can't find source list with id $id", 404);
|
||||
}
|
||||
|
||||
$form = $this->createForm(SourceSearchType::class);
|
||||
$form->submit($request->request->all());
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
/** @var SearchRequestBuilder $searchRequestBuilder */
|
||||
$searchRequestBuilder = $form->getData();
|
||||
/** @var SourceManagerInterface $manager */
|
||||
$manager = $this->get(AppBundleServices::SOURCE_MANAGER);
|
||||
$searchRequestBuilder->setUser($user);
|
||||
|
||||
$response = $manager->find($searchRequestBuilder, $sourceList);
|
||||
|
||||
/** @var PaginatorInterface $paginator */
|
||||
$paginator = $this->get('knp_paginator');
|
||||
$pagination = $paginator->paginate(
|
||||
$response,
|
||||
$searchRequestBuilder->getPage(),
|
||||
$searchRequestBuilder->getLimit()
|
||||
);
|
||||
|
||||
$sort = $searchRequestBuilder->getSorts();
|
||||
$sort = [
|
||||
'field' => array_search(key($sort), SourceSearchType::$fields),
|
||||
'direction' => current($sort),
|
||||
];
|
||||
|
||||
return $this->generateResponse([
|
||||
'sources' => $pagination,
|
||||
'filters' => $request->request->get('filters', (object) []),
|
||||
'sort' => $sort,
|
||||
], 200, [ 'id', 'source' ]);
|
||||
}
|
||||
|
||||
return $this->generateResponse($form, 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone current list.
|
||||
*
|
||||
* @Route("/{id}/clone",
|
||||
* requirements={ "id": "\d+" },
|
||||
* methods={ "POST" }
|
||||
* )
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @ApiDoc(
|
||||
* resource="Clone specified source list",
|
||||
* section="Source List",
|
||||
* parameters={
|
||||
* {
|
||||
* "name"="name",
|
||||
* "dataType"="string",
|
||||
* "required"="true"
|
||||
* }
|
||||
* },
|
||||
* output={
|
||||
* "class"="CacheBundle\Entity\SourceList",
|
||||
* "groups"={ "id", "source_list" }
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @param Request $request A Request instance.
|
||||
* @param integer $id A SourceList entity id.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function cloneAction(Request $request, $id)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
/** @var SourceListRepository $repository */
|
||||
$repository = $this->getManager()->getRepository('CacheBundle:SourceList');
|
||||
$sourceList = $repository->getSourcesLists($id, $user->getId());
|
||||
$em = $this->getManager();
|
||||
|
||||
$name = $request->request->get('name');
|
||||
|
||||
if ($name === null) {
|
||||
return $this->generateResponse('Required field \'name\' is not provided or empty.');
|
||||
}
|
||||
|
||||
if ($sourceList === null) {
|
||||
return $this->generateResponse("Can't find source list with id $id", 404);
|
||||
}
|
||||
|
||||
$clone = $sourceList->cloneList();
|
||||
$clone->setName($name);
|
||||
/** @var SourceManagerInterface $sourceManager */
|
||||
$sourceManager = $this->get(CacheBundleServices::SOURCE_CACHE);
|
||||
|
||||
$sources = $sourceList->getSources()->map(function (SourceToSourceList $source) {
|
||||
return $source->getSource();
|
||||
})->toArray();
|
||||
|
||||
$em->persist($clone);
|
||||
$em->flush();
|
||||
|
||||
//
|
||||
// We should add and original id 'cause otherwise he lost his binding.
|
||||
//
|
||||
$sourceManager->bindSourcesToLists($user, $sources, [ $sourceList->getId(), $clone->getId() ]);
|
||||
|
||||
return $this->generateResponse($clone, 200, [
|
||||
'source_list',
|
||||
'id',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Share specified source list.
|
||||
*
|
||||
* @Route("/{id}/share",
|
||||
* requirements={ "id": "\d+" },
|
||||
* methods={ "POST" }
|
||||
* )
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @ApiDoc(
|
||||
* resource="Sharing",
|
||||
* section="Source List"
|
||||
* )
|
||||
*
|
||||
* @param string $id A SourceList entity id.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function shareAction($id)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
$em = $this->getManager();
|
||||
|
||||
/** @var SourceListRepository $repository */
|
||||
$repository = $em->getRepository('CacheBundle:SourceList');
|
||||
$sourceList = $repository->getSourcesLists($id, $user->getId());
|
||||
|
||||
if ($sourceList === null) {
|
||||
return $this->generateResponse("Can't find source list with id $id", 404);
|
||||
}
|
||||
|
||||
$reasons = $this->checkAccess(SourceListInspector::SHARE, $sourceList);
|
||||
if (count($reasons) > 0) {
|
||||
return $this->generateResponse($reasons, 403);
|
||||
}
|
||||
|
||||
if (! $sourceList->getIsGlobal()) {
|
||||
$sourceList
|
||||
->setUpdatedBy($this->getCurrentUser())
|
||||
->setIsGlobal(true);
|
||||
$em->persist($sourceList);
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
return $this->generateResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unshare specified source list.
|
||||
*
|
||||
* @Route("/{id}/unshare",
|
||||
* requirements={ "id": "\d+" },
|
||||
* methods={ "POST" }
|
||||
* )
|
||||
* @Roles("ROLE_SUBSCRIBER")
|
||||
*
|
||||
* @ApiDoc(
|
||||
* resource="Sharing",
|
||||
* section="Source List"
|
||||
* )
|
||||
*
|
||||
* @param string $id A SourceList entity id.
|
||||
*
|
||||
* @return \ApiBundle\Response\ViewInterface
|
||||
*/
|
||||
public function unshareAction($id)
|
||||
{
|
||||
$user = $this->getCurrentUser();
|
||||
$em = $this->getManager();
|
||||
|
||||
/** @var SourceListRepository $repository */
|
||||
$repository = $em->getRepository('CacheBundle:SourceList');
|
||||
$sourceList = $repository->getSourcesLists($id, $user->getId());
|
||||
|
||||
if ($sourceList === null) {
|
||||
return $this->generateResponse("Can't find source list with id $id", 404);
|
||||
}
|
||||
|
||||
$reasons = $this->checkAccess(SourceListInspector::UNSHARE, $sourceList);
|
||||
if (count($reasons) > 0) {
|
||||
return $this->generateResponse($reasons, 403);
|
||||
}
|
||||
|
||||
if ($sourceList->getIsGlobal()) {
|
||||
$sourceList
|
||||
->setUpdatedBy($this->getCurrentUser())
|
||||
->setIsGlobal(false);
|
||||
$em->persist($sourceList);
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
return $this->generateResponse();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user