Tags.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <?php
  2. namespace Shaarli\Api\Controllers;
  3. use Shaarli\Api\ApiUtils;
  4. use Shaarli\Api\Exceptions\ApiBadParametersException;
  5. use Shaarli\Api\Exceptions\ApiLinkNotFoundException;
  6. use Shaarli\Api\Exceptions\ApiTagNotFoundException;
  7. use Slim\Http\Request;
  8. use Slim\Http\Response;
  9. /**
  10. * Class Tags
  11. *
  12. * REST API Controller: all services related to tags collection.
  13. *
  14. * @package Api\Controllers
  15. */
  16. class Tags extends ApiController
  17. {
  18. /**
  19. * @var int Number of links returned if no limit is provided.
  20. */
  21. public static $DEFAULT_LIMIT = 'all';
  22. /**
  23. * Retrieve a list of tags, allowing different filters.
  24. *
  25. * @param Request $request Slim request.
  26. * @param Response $response Slim response.
  27. *
  28. * @return Response response.
  29. *
  30. * @throws ApiBadParametersException Invalid parameters.
  31. */
  32. public function getTags($request, $response)
  33. {
  34. $visibility = $request->getParam('visibility');
  35. $tags = $this->linkDb->linksCountPerTag([], $visibility);
  36. // Return tags from the {offset}th tag, starting from 0.
  37. $offset = $request->getParam('offset');
  38. if (! empty($offset) && ! ctype_digit($offset)) {
  39. throw new ApiBadParametersException('Invalid offset');
  40. }
  41. $offset = ! empty($offset) ? intval($offset) : 0;
  42. if ($offset > count($tags)) {
  43. return $response->withJson([], 200, $this->jsonStyle);
  44. }
  45. // limit parameter is either a number of links or 'all' for everything.
  46. $limit = $request->getParam('limit');
  47. if (empty($limit)) {
  48. $limit = self::$DEFAULT_LIMIT;
  49. }
  50. if (ctype_digit($limit)) {
  51. $limit = intval($limit);
  52. } elseif ($limit === 'all') {
  53. $limit = count($tags);
  54. } else {
  55. throw new ApiBadParametersException('Invalid limit');
  56. }
  57. $out = [];
  58. $index = 0;
  59. foreach ($tags as $tag => $occurrences) {
  60. if (count($out) >= $limit) {
  61. break;
  62. }
  63. if ($index++ >= $offset) {
  64. $out[] = ApiUtils::formatTag($tag, $occurrences);
  65. }
  66. }
  67. return $response->withJson($out, 200, $this->jsonStyle);
  68. }
  69. /**
  70. * Return a single formatted tag by its name.
  71. *
  72. * @param Request $request Slim request.
  73. * @param Response $response Slim response.
  74. * @param array $args Path parameters. including the tag name.
  75. *
  76. * @return Response containing the link array.
  77. *
  78. * @throws ApiTagNotFoundException generating a 404 error.
  79. */
  80. public function getTag($request, $response, $args)
  81. {
  82. $tags = $this->linkDb->linksCountPerTag();
  83. if (!isset($tags[$args['tagName']])) {
  84. throw new ApiTagNotFoundException();
  85. }
  86. $out = ApiUtils::formatTag($args['tagName'], $tags[$args['tagName']]);
  87. return $response->withJson($out, 200, $this->jsonStyle);
  88. }
  89. /**
  90. * Rename a tag from the given name.
  91. * If the new name provided matches an existing tag, they will be merged.
  92. *
  93. * @param Request $request Slim request.
  94. * @param Response $response Slim response.
  95. * @param array $args Path parameters. including the tag name.
  96. *
  97. * @return Response response.
  98. *
  99. * @throws ApiTagNotFoundException generating a 404 error.
  100. * @throws ApiBadParametersException new tag name not provided
  101. */
  102. public function putTag($request, $response, $args)
  103. {
  104. $tags = $this->linkDb->linksCountPerTag();
  105. if (! isset($tags[$args['tagName']])) {
  106. throw new ApiTagNotFoundException();
  107. }
  108. $data = $request->getParsedBody();
  109. if (empty($data['name'])) {
  110. throw new ApiBadParametersException('New tag name is required in the request body');
  111. }
  112. $updated = $this->linkDb->renameTag($args['tagName'], $data['name']);
  113. $this->linkDb->save($this->conf->get('resource.page_cache'));
  114. foreach ($updated as $link) {
  115. $this->history->updateLink($link);
  116. }
  117. $tags = $this->linkDb->linksCountPerTag();
  118. $out = ApiUtils::formatTag($data['name'], $tags[$data['name']]);
  119. return $response->withJson($out, 200, $this->jsonStyle);
  120. }
  121. /**
  122. * Delete an existing tag by its name.
  123. *
  124. * @param Request $request Slim request.
  125. * @param Response $response Slim response.
  126. * @param array $args Path parameters. including the tag name.
  127. *
  128. * @return Response response.
  129. *
  130. * @throws ApiTagNotFoundException generating a 404 error.
  131. */
  132. public function deleteTag($request, $response, $args)
  133. {
  134. $tags = $this->linkDb->linksCountPerTag();
  135. if (! isset($tags[$args['tagName']])) {
  136. throw new ApiTagNotFoundException();
  137. }
  138. $updated = $this->linkDb->renameTag($args['tagName'], null);
  139. $this->linkDb->save($this->conf->get('resource.page_cache'));
  140. foreach ($updated as $link) {
  141. $this->history->updateLink($link);
  142. }
  143. return $response->withStatus(204);
  144. }
  145. }