mirror of
https://github.com/wallabag/wallabag.git
synced 2025-09-05 18:41:02 +00:00
Move source files directly under src/ directory
This commit is contained in:
parent
804261bc26
commit
a37b385c23
190 changed files with 19 additions and 21 deletions
187
src/Controller/Api/AnnotationRestController.php
Normal file
187
src/Controller/Api/AnnotationRestController.php
Normal file
|
@ -0,0 +1,187 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Controller\Api;
|
||||
|
||||
use Nelmio\ApiDocBundle\Annotation\Operation;
|
||||
use OpenApi\Annotations as OA;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Wallabag\CoreBundle\Entity\Annotation;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
|
||||
class AnnotationRestController extends WallabagRestController
|
||||
{
|
||||
/**
|
||||
* Retrieve annotations for an entry.
|
||||
*
|
||||
* @Operation(
|
||||
* tags={"Annotations"},
|
||||
* summary="Retrieve annotations for an entry.",
|
||||
* @OA\Parameter(
|
||||
* name="entry",
|
||||
* in="path",
|
||||
* description="The entry ID",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="integer",
|
||||
* pattern="\w+",
|
||||
* )
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Returned when successful"
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @Route("/api/annotations/{entry}.{_format}", methods={"GET"}, name="api_get_annotations", defaults={"_format": "json"})
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getAnnotationsAction(Entry $entry)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
|
||||
return $this->forward('Wallabag\CoreBundle\Controller\AnnotationController::getAnnotationsAction', [
|
||||
'entry' => $entry,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new annotation.
|
||||
*
|
||||
* @Operation(
|
||||
* tags={"Annotations"},
|
||||
* summary="Creates a new annotation.",
|
||||
* @OA\Parameter(
|
||||
* name="entry",
|
||||
* in="path",
|
||||
* description="The entry ID",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="integer",
|
||||
* pattern="\w+",
|
||||
* )
|
||||
* ),
|
||||
* @OA\RequestBody(
|
||||
* @OA\JsonContent(
|
||||
* type="object",
|
||||
* required={"text"},
|
||||
* @OA\Property(
|
||||
* property="ranges",
|
||||
* type="array",
|
||||
* description="The range array for the annotation",
|
||||
* @OA\Items(
|
||||
* type="string",
|
||||
* pattern="\w+",
|
||||
* )
|
||||
* ),
|
||||
* @OA\Property(
|
||||
* property="quote",
|
||||
* type="array",
|
||||
* description="The annotated text",
|
||||
* @OA\Items(
|
||||
* type="string",
|
||||
* )
|
||||
* ),
|
||||
* @OA\Property(
|
||||
* property="text",
|
||||
* type="array",
|
||||
* description="Content of annotation",
|
||||
* @OA\Items(
|
||||
* type="string",
|
||||
* )
|
||||
* ),
|
||||
* )
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Returned when successful"
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @Route("/api/annotations/{entry}.{_format}", methods={"POST"}, name="api_post_annotation", defaults={"_format": "json"})
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function postAnnotationAction(Request $request, Entry $entry)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
|
||||
return $this->forward('Wallabag\CoreBundle\Controller\AnnotationController::postAnnotationAction', [
|
||||
'request' => $request,
|
||||
'entry' => $entry,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an annotation.
|
||||
*
|
||||
* @Operation(
|
||||
* tags={"Annotations"},
|
||||
* summary="Updates an annotation.",
|
||||
* @OA\Parameter(
|
||||
* name="annotation",
|
||||
* in="path",
|
||||
* description="The annotation ID",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="string",
|
||||
* pattern="\w+",
|
||||
* )
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Returned when successful"
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @Route("/api/annotations/{annotation}.{_format}", methods={"PUT"}, name="api_put_annotation", defaults={"_format": "json"})
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function putAnnotationAction(int $annotation, Request $request)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
|
||||
return $this->forward('Wallabag\CoreBundle\Controller\AnnotationController::putAnnotationAction', [
|
||||
'annotation' => $annotation,
|
||||
'request' => $request,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an annotation.
|
||||
*
|
||||
* @Operation(
|
||||
* tags={"Annotations"},
|
||||
* summary="Removes an annotation.",
|
||||
* @OA\Parameter(
|
||||
* name="annotation",
|
||||
* in="path",
|
||||
* description="The annotation ID",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="string",
|
||||
* pattern="\w+",
|
||||
* )
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Returned when successful"
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @Route("/api/annotations/{annotation}.{_format}", methods={"DELETE"}, name="api_delete_annotation", defaults={"_format": "json"})
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function deleteAnnotationAction(int $annotation)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
|
||||
return $this->forward('Wallabag\CoreBundle\Controller\AnnotationController::deleteAnnotationAction', [
|
||||
'annotation' => $annotation,
|
||||
]);
|
||||
}
|
||||
}
|
44
src/Controller/Api/ConfigRestController.php
Normal file
44
src/Controller/Api/ConfigRestController.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Controller\Api;
|
||||
|
||||
use JMS\Serializer\SerializationContext;
|
||||
use JMS\Serializer\SerializerInterface;
|
||||
use Nelmio\ApiDocBundle\Annotation\Operation;
|
||||
use OpenApi\Annotations as OA;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class ConfigRestController extends WallabagRestController
|
||||
{
|
||||
/**
|
||||
* Retrieve configuration for current user.
|
||||
*
|
||||
* @Operation(
|
||||
* tags={"Config"},
|
||||
* summary="Retrieve configuration for current user.",
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Returned when successful"
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @Route("/api/config.{_format}", methods={"GET"}, name="api_get_config", defaults={"_format": "json"})
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getConfigAction(SerializerInterface $serializer)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
|
||||
$json = $serializer->serialize(
|
||||
$this->getUser()->getConfig(),
|
||||
'json',
|
||||
SerializationContext::create()->setGroups(['config_api'])
|
||||
);
|
||||
|
||||
return (new JsonResponse())
|
||||
->setJson($json)
|
||||
->setStatusCode(JsonResponse::HTTP_OK);
|
||||
}
|
||||
}
|
110
src/Controller/Api/DeveloperController.php
Normal file
110
src/Controller/Api/DeveloperController.php
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Controller\Api;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use Wallabag\CoreBundle\Controller\AbstractController;
|
||||
use Wallabag\CoreBundle\Entity\Api\Client;
|
||||
use Wallabag\CoreBundle\Form\Type\Api\ClientType;
|
||||
use Wallabag\CoreBundle\Repository\Api\ClientRepository;
|
||||
|
||||
class DeveloperController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* List all clients and link to create a new one.
|
||||
*
|
||||
* @Route("/developer", name="developer")
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function indexAction(ClientRepository $repo)
|
||||
{
|
||||
$clients = $repo->findByUser($this->getUser()->getId());
|
||||
|
||||
return $this->render('Developer/index.html.twig', [
|
||||
'clients' => $clients,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a client (an app).
|
||||
*
|
||||
* @Route("/developer/client/create", name="developer_create_client")
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function createClientAction(Request $request, EntityManagerInterface $entityManager, TranslatorInterface $translator)
|
||||
{
|
||||
$client = new Client($this->getUser());
|
||||
$clientForm = $this->createForm(ClientType::class, $client);
|
||||
$clientForm->handleRequest($request);
|
||||
|
||||
if ($clientForm->isSubmitted() && $clientForm->isValid()) {
|
||||
$client->setAllowedGrantTypes(['token', 'authorization_code', 'password', 'refresh_token']);
|
||||
$entityManager->persist($client);
|
||||
$entityManager->flush();
|
||||
|
||||
$this->addFlash(
|
||||
'notice',
|
||||
$translator->trans('flashes.developer.notice.client_created', ['%name%' => $client->getName()])
|
||||
);
|
||||
|
||||
return $this->render('Developer/client_parameters.html.twig', [
|
||||
'client_id' => $client->getPublicId(),
|
||||
'client_secret' => $client->getSecret(),
|
||||
'client_name' => $client->getName(),
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->render('Developer/client.html.twig', [
|
||||
'form' => $clientForm->createView(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a client.
|
||||
*
|
||||
* @Route("/developer/client/delete/{id}", requirements={"id" = "\d+"}, name="developer_delete_client", methods={"POST"})
|
||||
*
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function deleteClientAction(Request $request, Client $client, EntityManagerInterface $entityManager, TranslatorInterface $translator)
|
||||
{
|
||||
if (!$this->isCsrfTokenValid('delete-client', $request->request->get('token'))) {
|
||||
throw $this->createAccessDeniedException('Bad CSRF token.');
|
||||
}
|
||||
|
||||
if (null === $this->getUser() || $client->getUser()->getId() !== $this->getUser()->getId()) {
|
||||
throw $this->createAccessDeniedException('You can not access this client.');
|
||||
}
|
||||
|
||||
$entityManager->remove($client);
|
||||
$entityManager->flush();
|
||||
|
||||
$this->addFlash(
|
||||
'notice',
|
||||
$translator->trans('flashes.developer.notice.client_deleted', ['%name%' => $client->getName()])
|
||||
);
|
||||
|
||||
return $this->redirect($this->generateUrl('developer'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display developer how to use an existing app.
|
||||
*
|
||||
* @Route("/developer/howto/first-app", name="developer_howto_firstapp")
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function howtoFirstAppAction()
|
||||
{
|
||||
return $this->render('Developer/howto_app.html.twig', [
|
||||
'wallabag_url' => $this->getParameter('domain_name'),
|
||||
]);
|
||||
}
|
||||
}
|
1414
src/Controller/Api/EntryRestController.php
Normal file
1414
src/Controller/Api/EntryRestController.php
Normal file
File diff suppressed because it is too large
Load diff
97
src/Controller/Api/SearchRestController.php
Normal file
97
src/Controller/Api/SearchRestController.php
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Controller\Api;
|
||||
|
||||
use Hateoas\Configuration\Route as HateoasRoute;
|
||||
use Hateoas\Representation\Factory\PagerfantaFactory;
|
||||
use Nelmio\ApiDocBundle\Annotation\Operation;
|
||||
use OpenApi\Annotations as OA;
|
||||
use Pagerfanta\Doctrine\ORM\QueryAdapter as DoctrineORMAdapter;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Wallabag\CoreBundle\Repository\EntryRepository;
|
||||
|
||||
class SearchRestController extends WallabagRestController
|
||||
{
|
||||
/**
|
||||
* Search all entries by term.
|
||||
*
|
||||
* @Operation(
|
||||
* tags={"Search"},
|
||||
* summary="Search all entries by term.",
|
||||
* @OA\Parameter(
|
||||
* name="term",
|
||||
* in="query",
|
||||
* description="Any query term",
|
||||
* required=false,
|
||||
* @OA\Schema(type="string")
|
||||
* ),
|
||||
* @OA\Parameter(
|
||||
* name="page",
|
||||
* in="query",
|
||||
* description="what page you want.",
|
||||
* required=false,
|
||||
* @OA\Schema(
|
||||
* type="integer",
|
||||
* default=1
|
||||
* )
|
||||
* ),
|
||||
* @OA\Parameter(
|
||||
* name="perPage",
|
||||
* in="query",
|
||||
* description="results per page.",
|
||||
* required=false,
|
||||
* @OA\Schema(
|
||||
* type="integer",
|
||||
* default=30
|
||||
* )
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Returned when successful"
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @Route("/api/search.{_format}", methods={"GET"}, name="api_get_search", defaults={"_format": "json"})
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getSearchAction(Request $request, EntryRepository $entryRepository)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
|
||||
$term = $request->query->get('term');
|
||||
$page = (int) $request->query->get('page', 1);
|
||||
$perPage = (int) $request->query->get('perPage', 30);
|
||||
|
||||
$qb = $entryRepository->getBuilderForSearchByUser(
|
||||
$this->getUser()->getId(),
|
||||
$term,
|
||||
null
|
||||
);
|
||||
|
||||
$pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false);
|
||||
$pager = new Pagerfanta($pagerAdapter);
|
||||
|
||||
$pager->setMaxPerPage($perPage);
|
||||
$pager->setCurrentPage($page);
|
||||
|
||||
$pagerfantaFactory = new PagerfantaFactory('page', 'perPage');
|
||||
$paginatedCollection = $pagerfantaFactory->createRepresentation(
|
||||
$pager,
|
||||
new HateoasRoute(
|
||||
'api_get_search',
|
||||
[
|
||||
'term' => $term,
|
||||
'page' => $page,
|
||||
'perPage' => $perPage,
|
||||
],
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
return $this->sendResponse($paginatedCollection);
|
||||
}
|
||||
}
|
203
src/Controller/Api/TagRestController.php
Normal file
203
src/Controller/Api/TagRestController.php
Normal file
|
@ -0,0 +1,203 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Controller\Api;
|
||||
|
||||
use Nelmio\ApiDocBundle\Annotation\Operation;
|
||||
use OpenApi\Annotations as OA;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
use Wallabag\CoreBundle\Entity\Tag;
|
||||
use Wallabag\CoreBundle\Repository\EntryRepository;
|
||||
use Wallabag\CoreBundle\Repository\TagRepository;
|
||||
|
||||
class TagRestController extends WallabagRestController
|
||||
{
|
||||
/**
|
||||
* Retrieve all tags.
|
||||
*
|
||||
* @Operation(
|
||||
* tags={"Tags"},
|
||||
* summary="Retrieve all tags.",
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Returned when successful"
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @Route("/api/tags.{_format}", methods={"GET"}, name="api_get_tags", defaults={"_format": "json"})
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getTagsAction(TagRepository $tagRepository)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
|
||||
$tags = $tagRepository->findAllFlatTagsWithNbEntries($this->getUser()->getId());
|
||||
|
||||
$json = $this->serializer->serialize($tags, 'json');
|
||||
|
||||
return (new JsonResponse())->setJson($json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently remove one tag from **every** entry by passing the Tag label.
|
||||
*
|
||||
* @Operation(
|
||||
* tags={"Tags"},
|
||||
* summary="Permanently remove one tag from every entry by passing the Tag label.",
|
||||
* @OA\Parameter(
|
||||
* name="tag",
|
||||
* in="query",
|
||||
* description="Tag as a string",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="string",
|
||||
* pattern="\w+",
|
||||
* )
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Returned when successful"
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @Route("/api/tag/label.{_format}", methods={"DELETE"}, name="api_delete_tag_label", defaults={"_format": "json"})
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function deleteTagLabelAction(Request $request, TagRepository $tagRepository, EntryRepository $entryRepository)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
$label = $request->get('tag', '');
|
||||
|
||||
$tags = $tagRepository->findByLabelsAndUser([$label], $this->getUser()->getId());
|
||||
|
||||
if (empty($tags)) {
|
||||
throw $this->createNotFoundException('Tag not found');
|
||||
}
|
||||
|
||||
$tag = $tags[0];
|
||||
|
||||
$entryRepository->removeTag($this->getUser()->getId(), $tag);
|
||||
|
||||
$this->cleanOrphanTag($tag);
|
||||
|
||||
$json = $this->serializer->serialize($tag, 'json');
|
||||
|
||||
return (new JsonResponse())->setJson($json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently remove some tags from **every** entry.
|
||||
*
|
||||
* @Operation(
|
||||
* tags={"Tags"},
|
||||
* summary="Permanently remove some tags from every entry.",
|
||||
* @OA\Parameter(
|
||||
* name="tags",
|
||||
* in="query",
|
||||
* description="Tags as strings (comma splitted)",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="string",
|
||||
* example="tag1,tag2",
|
||||
* )
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Returned when successful"
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @Route("/api/tags/label.{_format}", methods={"DELETE"}, name="api_delete_tags_label", defaults={"_format": "json"})
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function deleteTagsLabelAction(Request $request, TagRepository $tagRepository, EntryRepository $entryRepository)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
|
||||
$tagsLabels = $request->get('tags', '');
|
||||
|
||||
$tags = $tagRepository->findByLabelsAndUser(explode(',', $tagsLabels), $this->getUser()->getId());
|
||||
|
||||
if (empty($tags)) {
|
||||
throw $this->createNotFoundException('Tags not found');
|
||||
}
|
||||
|
||||
$entryRepository->removeTags($this->getUser()->getId(), $tags);
|
||||
|
||||
$this->cleanOrphanTag($tags);
|
||||
|
||||
$json = $this->serializer->serialize($tags, 'json');
|
||||
|
||||
return (new JsonResponse())->setJson($json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently remove one tag from **every** entry by passing the Tag ID.
|
||||
*
|
||||
* @Operation(
|
||||
* tags={"Tags"},
|
||||
* summary="Permanently remove one tag from every entry by passing the Tag ID.",
|
||||
* @OA\Parameter(
|
||||
* name="tag",
|
||||
* in="path",
|
||||
* description="The tag",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="integer",
|
||||
* pattern="\w+",
|
||||
* )
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Returned when successful"
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @Route("/api/tags/{tag}.{_format}", methods={"DELETE"}, name="api_delete_tag", defaults={"_format": "json"})
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function deleteTagAction(Tag $tag, TagRepository $tagRepository, EntryRepository $entryRepository)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
|
||||
$tagFromDb = $tagRepository->findByLabelsAndUser([$tag->getLabel()], $this->getUser()->getId());
|
||||
|
||||
if (empty($tagFromDb)) {
|
||||
throw $this->createNotFoundException('Tag not found');
|
||||
}
|
||||
|
||||
$entryRepository->removeTag($this->getUser()->getId(), $tag);
|
||||
|
||||
$this->cleanOrphanTag($tag);
|
||||
|
||||
$json = $this->serializer->serialize($tag, 'json');
|
||||
|
||||
return (new JsonResponse())->setJson($json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove orphan tag in case no entries are associated to it.
|
||||
*
|
||||
* @param Tag|array $tags
|
||||
*/
|
||||
private function cleanOrphanTag($tags)
|
||||
{
|
||||
if (!\is_array($tags)) {
|
||||
$tags = [$tags];
|
||||
}
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
if (0 === \count($tag->getEntries())) {
|
||||
$this->entityManager->remove($tag);
|
||||
}
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
}
|
50
src/Controller/Api/TaggingRuleRestController.php
Normal file
50
src/Controller/Api/TaggingRuleRestController.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Controller\Api;
|
||||
|
||||
use JMS\Serializer\SerializationContext;
|
||||
use JMS\Serializer\SerializerBuilder;
|
||||
use Nelmio\ApiDocBundle\Annotation\Operation;
|
||||
use OpenApi\Annotations as OA;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class TaggingRuleRestController extends WallabagRestController
|
||||
{
|
||||
/**
|
||||
* Export all tagging rules as a json file.
|
||||
*
|
||||
* @Operation(
|
||||
* tags={"TaggingRule"},
|
||||
* summary="Export all tagging rules as a json file.",
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Returned when successful"
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @Route("/api/taggingrule/export.{_format}", methods={"GET"}, name="api_get_taggingrule_export", defaults={"_format": "json"})
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getTaggingruleExportAction()
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
|
||||
$data = SerializerBuilder::create()->build()->serialize(
|
||||
$this->getUser()->getConfig()->getTaggingRules(),
|
||||
'json',
|
||||
SerializationContext::create()->setGroups(['export_tagging_rule'])
|
||||
);
|
||||
|
||||
return Response::create(
|
||||
$data,
|
||||
200,
|
||||
[
|
||||
'Content-type' => 'application/json',
|
||||
'Content-Disposition' => 'attachment; filename="tagging_rules_' . $this->getUser()->getUsername() . '.json"',
|
||||
'Content-Transfer-Encoding' => 'UTF-8',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
214
src/Controller/Api/UserRestController.php
Normal file
214
src/Controller/Api/UserRestController.php
Normal file
|
@ -0,0 +1,214 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Controller\Api;
|
||||
|
||||
use Craue\ConfigBundle\Util\Config;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use FOS\UserBundle\Event\UserEvent;
|
||||
use FOS\UserBundle\FOSUserEvents;
|
||||
use FOS\UserBundle\Model\UserManagerInterface;
|
||||
use JMS\Serializer\SerializationContext;
|
||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||
use Nelmio\ApiDocBundle\Annotation\Operation;
|
||||
use OpenApi\Annotations as OA;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Wallabag\CoreBundle\Entity\Api\Client;
|
||||
use Wallabag\CoreBundle\Entity\User;
|
||||
use Wallabag\CoreBundle\Form\Type\NewUserType;
|
||||
|
||||
class UserRestController extends WallabagRestController
|
||||
{
|
||||
/**
|
||||
* Retrieve current logged in user information.
|
||||
*
|
||||
* @Operation(
|
||||
* tags={"User"},
|
||||
* summary="Retrieve current logged in user information.",
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Returned when successful",
|
||||
* @Model(type=User::class, groups={"user_api"}))
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @Route("/api/user.{_format}", methods={"GET"}, name="api_get_user", defaults={"_format": "json"})
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getUserAction()
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
|
||||
return $this->sendUser($this->getUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an user and create a client.
|
||||
*
|
||||
* @Operation(
|
||||
* tags={"User"},
|
||||
* summary="Register an user and create a client.",
|
||||
* @OA\RequestBody(
|
||||
* @OA\JsonContent(
|
||||
* type="object",
|
||||
* required={"username", "password", "email"},
|
||||
* @OA\Property(
|
||||
* property="username",
|
||||
* description="The user's username",
|
||||
* type="string",
|
||||
* example="wallabag",
|
||||
* ),
|
||||
* @OA\Property(
|
||||
* property="password",
|
||||
* description="The user's password",
|
||||
* type="string",
|
||||
* example="hidden_value",
|
||||
* ),
|
||||
* @OA\Property(
|
||||
* property="email",
|
||||
* description="The user's email",
|
||||
* type="string",
|
||||
* example="wallabag@wallabag.io",
|
||||
* ),
|
||||
* @OA\Property(
|
||||
* property="client_name",
|
||||
* description="The client name (to be used by your app)",
|
||||
* type="string",
|
||||
* example="Fancy App",
|
||||
* ),
|
||||
* )
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="201",
|
||||
* description="Returned when successful",
|
||||
* @Model(type=User::class, groups={"user_api_with_client"})),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="403",
|
||||
* description="Server doesn't allow registrations"
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="400",
|
||||
* description="Request is incorrectly formatted"
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @todo Make this method (or the whole API) accessible only through https
|
||||
*
|
||||
* @Route("/api/user.{_format}", methods={"PUT"}, name="api_put_user", defaults={"_format": "json"})
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function putUserAction(Request $request, Config $craueConfig, UserManagerInterface $userManager, EntityManagerInterface $entityManager, EventDispatcherInterface $eventDispatcher)
|
||||
{
|
||||
if (!$this->getParameter('fosuser_registration') || !$craueConfig->get('api_user_registration')) {
|
||||
$json = $this->serializer->serialize(['error' => "Server doesn't allow registrations"], 'json');
|
||||
|
||||
return (new JsonResponse())
|
||||
->setJson($json)
|
||||
->setStatusCode(JsonResponse::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
$user = $userManager->createUser();
|
||||
\assert($user instanceof User);
|
||||
// user will be disabled BY DEFAULT to avoid spamming account to be enabled
|
||||
$user->setEnabled(false);
|
||||
|
||||
$form = $this->createForm(NewUserType::class, $user, [
|
||||
'csrf_protection' => false,
|
||||
]);
|
||||
|
||||
// simulate form submission
|
||||
$form->submit([
|
||||
'username' => $request->request->get('username'),
|
||||
'plainPassword' => [
|
||||
'first' => $request->request->get('password'),
|
||||
'second' => $request->request->get('password'),
|
||||
],
|
||||
'email' => $request->request->get('email'),
|
||||
]);
|
||||
|
||||
if ($form->isSubmitted() && false === $form->isValid()) {
|
||||
$view = $this->view($form, 400);
|
||||
$view->setFormat('json');
|
||||
|
||||
// handle errors in a more beautiful way than the default view
|
||||
$data = json_decode($this->handleView($view)->getContent(), true)['errors']['children'];
|
||||
$errors = [];
|
||||
|
||||
if (isset($data['username']['errors'])) {
|
||||
$errors['username'] = $this->translateErrors($data['username']['errors']);
|
||||
}
|
||||
|
||||
if (isset($data['email']['errors'])) {
|
||||
$errors['email'] = $this->translateErrors($data['email']['errors']);
|
||||
}
|
||||
|
||||
if (isset($data['plainPassword']['children']['first']['errors'])) {
|
||||
$errors['password'] = $this->translateErrors($data['plainPassword']['children']['first']['errors']);
|
||||
}
|
||||
|
||||
$json = $this->serializer->serialize(['error' => $errors], 'json');
|
||||
|
||||
return (new JsonResponse())
|
||||
->setJson($json)
|
||||
->setStatusCode(JsonResponse::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
// create a default client
|
||||
$client = new Client($user);
|
||||
$client->setName($request->request->get('client_name', 'Default client'));
|
||||
|
||||
$entityManager->persist($client);
|
||||
|
||||
$user->addClient($client);
|
||||
|
||||
$userManager->updateUser($user);
|
||||
|
||||
// dispatch a created event so the associated config will be created
|
||||
$eventDispatcher->dispatch(new UserEvent($user, $request), FOSUserEvents::USER_CREATED);
|
||||
|
||||
return $this->sendUser($user, 'user_api_with_client', JsonResponse::HTTP_CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send user response.
|
||||
*
|
||||
* @param string $group Used to define with serialized group might be used
|
||||
* @param int $status HTTP Status code to send
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
private function sendUser(User $user, $group = 'user_api', $status = JsonResponse::HTTP_OK)
|
||||
{
|
||||
$json = $this->serializer->serialize(
|
||||
$user,
|
||||
'json',
|
||||
SerializationContext::create()->setGroups([$group])
|
||||
);
|
||||
|
||||
return (new JsonResponse())
|
||||
->setJson($json)
|
||||
->setStatusCode($status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate errors message.
|
||||
*
|
||||
* @param array $errors
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function translateErrors($errors)
|
||||
{
|
||||
$translatedErrors = [];
|
||||
foreach ($errors as $error) {
|
||||
$translatedErrors[] = $this->translator->trans($error);
|
||||
}
|
||||
|
||||
return $translatedErrors;
|
||||
}
|
||||
}
|
144
src/Controller/Api/WallabagRestController.php
Normal file
144
src/Controller/Api/WallabagRestController.php
Normal file
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Controller\Api;
|
||||
|
||||
use Craue\ConfigBundle\Util\Config;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use FOS\RestBundle\Controller\AbstractFOSRestController;
|
||||
use JMS\Serializer\SerializationContext;
|
||||
use JMS\Serializer\SerializerInterface;
|
||||
use Nelmio\ApiDocBundle\Annotation\Model;
|
||||
use Nelmio\ApiDocBundle\Annotation\Operation;
|
||||
use OpenApi\Annotations as OA;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use Wallabag\CoreBundle\Entity\Api\ApplicationInfo;
|
||||
use Wallabag\CoreBundle\Entity\User;
|
||||
|
||||
class WallabagRestController extends AbstractFOSRestController
|
||||
{
|
||||
protected EntityManagerInterface $entityManager;
|
||||
protected SerializerInterface $serializer;
|
||||
protected AuthorizationCheckerInterface $authorizationChecker;
|
||||
protected TokenStorageInterface $tokenStorage;
|
||||
protected TranslatorInterface $translator;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, SerializerInterface $serializer, AuthorizationCheckerInterface $authorizationChecker, TokenStorageInterface $tokenStorage, TranslatorInterface $translator)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->serializer = $serializer;
|
||||
$this->authorizationChecker = $authorizationChecker;
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve version number.
|
||||
*
|
||||
* @Operation(
|
||||
* tags={"Information"},
|
||||
* summary="Retrieve version number.",
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Returned when successful",
|
||||
* @OA\JsonContent(
|
||||
* description="Version number of the application.",
|
||||
* type="string",
|
||||
* example="2.5.2",
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @deprecated Should use info endpoint instead
|
||||
*
|
||||
* @Route("/api/version.{_format}", methods={"GET"}, name="api_get_version", defaults={"_format": "json"})
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getVersionAction()
|
||||
{
|
||||
$version = $this->getParameter('wallabag_core.version');
|
||||
$json = $this->serializer->serialize($version, 'json');
|
||||
|
||||
return (new JsonResponse())->setJson($json);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Operation(
|
||||
* tags={"Information"},
|
||||
* summary="Retrieve information about the running wallabag application.",
|
||||
* @OA\Response(
|
||||
* response="200",
|
||||
* description="Returned when successful",
|
||||
* @Model(type=ApplicationInfo::class),
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @Route("/api/info.{_format}", methods={"GET"}, name="api_get_info", defaults={"_format": "json"})
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getInfoAction(Config $craueConfig)
|
||||
{
|
||||
$info = new ApplicationInfo(
|
||||
$this->getParameter('wallabag_core.version'),
|
||||
$this->getParameter('fosuser_registration') && $craueConfig->get('api_user_registration'),
|
||||
);
|
||||
|
||||
return (new JsonResponse())->setJson($this->serializer->serialize($info, 'json'));
|
||||
}
|
||||
|
||||
protected function validateAuthentication()
|
||||
{
|
||||
if (false === $this->authorizationChecker->isGranted('IS_AUTHENTICATED_FULLY')) {
|
||||
throw new AccessDeniedException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the first id is equal to the second one.
|
||||
* If not, throw exception. It means a user try to access information from an other user.
|
||||
*
|
||||
* @param int $requestUserId User id from the requested source
|
||||
*/
|
||||
protected function validateUserAccess($requestUserId)
|
||||
{
|
||||
$user = $this->tokenStorage->getToken()->getUser();
|
||||
\assert($user instanceof User);
|
||||
|
||||
if ($requestUserId !== $user->getId()) {
|
||||
throw $this->createAccessDeniedException('Access forbidden. Entry user id: ' . $requestUserId . ', logged user id: ' . $user->getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to send data serialized in json.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
protected function sendResponse($data)
|
||||
{
|
||||
// https://github.com/schmittjoh/JMSSerializerBundle/issues/293
|
||||
$context = new SerializationContext();
|
||||
$context->setSerializeNull(true);
|
||||
|
||||
$json = $this->serializer->serialize($data, 'json', $context);
|
||||
|
||||
return (new JsonResponse())->setJson($json);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User|null
|
||||
*/
|
||||
protected function getUser()
|
||||
{
|
||||
$user = parent::getUser();
|
||||
\assert(null === $user || $user instanceof User);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue