You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

233 lines
7.4 KiB

  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OC\Core\Controller;
  8. use OC\Core\ResponseDefinitions;
  9. use OCP\AppFramework\Http;
  10. use OCP\AppFramework\Http\Attribute\AnonRateLimit;
  11. use OCP\AppFramework\Http\Attribute\ApiRoute;
  12. use OCP\AppFramework\Http\Attribute\NoAdminRequired;
  13. use OCP\AppFramework\Http\Attribute\PublicPage;
  14. use OCP\AppFramework\Http\DataResponse;
  15. use OCP\AppFramework\OCSController;
  16. use OCP\Collaboration\Reference\IDiscoverableReferenceProvider;
  17. use OCP\Collaboration\Reference\IReferenceManager;
  18. use OCP\Collaboration\Reference\Reference;
  19. use OCP\IRequest;
  20. /**
  21. * @psalm-import-type CoreReference from ResponseDefinitions
  22. * @psalm-import-type CoreReferenceProvider from ResponseDefinitions
  23. */
  24. class ReferenceApiController extends OCSController {
  25. private const LIMIT_MAX = 15;
  26. public function __construct(
  27. string $appName,
  28. IRequest $request,
  29. private IReferenceManager $referenceManager,
  30. private ?string $userId,
  31. ) {
  32. parent::__construct($appName, $request);
  33. }
  34. /**
  35. * Extract references from a text
  36. *
  37. * @param string $text Text to extract from
  38. * @param bool $resolve Resolve the references
  39. * @param int $limit Maximum amount of references to extract
  40. * @return DataResponse<Http::STATUS_OK, array{references: array<string, CoreReference|null>}, array{}>
  41. *
  42. * 200: References returned
  43. */
  44. #[NoAdminRequired]
  45. #[ApiRoute(verb: 'POST', url: '/extract', root: '/references')]
  46. public function extract(string $text, bool $resolve = false, int $limit = 1): DataResponse {
  47. $references = $this->referenceManager->extractReferences($text);
  48. $result = [];
  49. $index = 0;
  50. foreach ($references as $reference) {
  51. if ($index++ >= $limit) {
  52. break;
  53. }
  54. $result[$reference] = $resolve ? $this->referenceManager->resolveReference($reference)->jsonSerialize() : null;
  55. }
  56. return new DataResponse([
  57. 'references' => $result
  58. ]);
  59. }
  60. /**
  61. * Extract references from a text
  62. *
  63. * @param string $text Text to extract from
  64. * @param string $sharingToken Token of the public share
  65. * @param bool $resolve Resolve the references
  66. * @param int $limit Maximum amount of references to extract, limited to 15
  67. * @return DataResponse<Http::STATUS_OK, array{references: array<string, CoreReference|null>}, array{}>
  68. *
  69. * 200: References returned
  70. */
  71. #[ApiRoute(verb: 'POST', url: '/extractPublic', root: '/references')]
  72. #[PublicPage]
  73. #[AnonRateLimit(limit: 10, period: 120)]
  74. public function extractPublic(string $text, string $sharingToken, bool $resolve = false, int $limit = 1): DataResponse {
  75. $references = $this->referenceManager->extractReferences($text);
  76. $result = [];
  77. $index = 0;
  78. foreach ($references as $reference) {
  79. if ($index++ >= min($limit, self::LIMIT_MAX)) {
  80. break;
  81. }
  82. $result[$reference] = $resolve ? $this->referenceManager->resolveReference($reference, true, $sharingToken)?->jsonSerialize() : null;
  83. }
  84. return new DataResponse([
  85. 'references' => $result
  86. ]);
  87. }
  88. /**
  89. * Resolve a reference
  90. *
  91. * @param string $reference Reference to resolve
  92. * @return DataResponse<Http::STATUS_OK, array{references: array<string, ?CoreReference>}, array{}>
  93. *
  94. * 200: Reference returned
  95. */
  96. #[NoAdminRequired]
  97. #[ApiRoute(verb: 'GET', url: '/resolve', root: '/references')]
  98. public function resolveOne(string $reference): DataResponse {
  99. /** @var ?CoreReference $resolvedReference */
  100. $resolvedReference = $this->referenceManager->resolveReference(trim($reference))?->jsonSerialize();
  101. $response = new DataResponse(['references' => [$reference => $resolvedReference]]);
  102. $response->cacheFor(3600, false, true);
  103. return $response;
  104. }
  105. /**
  106. * Resolve from a public page
  107. *
  108. * @param string $reference Reference to resolve
  109. * @param string $sharingToken Token of the public share
  110. * @return DataResponse<Http::STATUS_OK, array{references: array<string, ?CoreReference>}, array{}>
  111. *
  112. * 200: Reference returned
  113. */
  114. #[ApiRoute(verb: 'GET', url: '/resolvePublic', root: '/references')]
  115. #[PublicPage]
  116. #[AnonRateLimit(limit: 25, period: 120)]
  117. public function resolveOnePublic(string $reference, string $sharingToken): DataResponse {
  118. /** @var ?CoreReference $resolvedReference */
  119. $resolvedReference = $this->referenceManager->resolveReference(trim($reference), true, trim($sharingToken))?->jsonSerialize();
  120. $response = new DataResponse(['references' => [$reference => $resolvedReference]]);
  121. $response->cacheFor(3600, false, true);
  122. return $response;
  123. }
  124. /**
  125. * Resolve multiple references
  126. *
  127. * @param list<string> $references References to resolve
  128. * @param int $limit Maximum amount of references to resolve
  129. * @return DataResponse<Http::STATUS_OK, array{references: array<string, CoreReference|null>}, array{}>
  130. *
  131. * 200: References returned
  132. */
  133. #[NoAdminRequired]
  134. #[ApiRoute(verb: 'POST', url: '/resolve', root: '/references')]
  135. public function resolve(array $references, int $limit = 1): DataResponse {
  136. $result = [];
  137. $index = 0;
  138. foreach ($references as $reference) {
  139. if ($index++ >= $limit) {
  140. break;
  141. }
  142. $result[$reference] = $this->referenceManager->resolveReference($reference)?->jsonSerialize();
  143. }
  144. return new DataResponse([
  145. 'references' => $result
  146. ]);
  147. }
  148. /**
  149. * Resolve multiple references from a public page
  150. *
  151. * @param list<string> $references References to resolve
  152. * @param string $sharingToken Token of the public share
  153. * @param int $limit Maximum amount of references to resolve, limited to 15
  154. * @return DataResponse<Http::STATUS_OK, array{references: array<string, CoreReference|null>}, array{}>
  155. *
  156. * 200: References returned
  157. */
  158. #[ApiRoute(verb: 'POST', url: '/resolvePublic', root: '/references')]
  159. #[PublicPage]
  160. #[AnonRateLimit(limit: 10, period: 120)]
  161. public function resolvePublic(array $references, string $sharingToken, int $limit = 1): DataResponse {
  162. $result = [];
  163. $index = 0;
  164. foreach ($references as $reference) {
  165. if ($index++ >= min($limit, self::LIMIT_MAX)) {
  166. break;
  167. }
  168. $result[$reference] = $this->referenceManager->resolveReference($reference, true, $sharingToken)?->jsonSerialize();
  169. }
  170. return new DataResponse([
  171. 'references' => $result
  172. ]);
  173. }
  174. /**
  175. * Get the providers
  176. *
  177. * @return DataResponse<Http::STATUS_OK, list<CoreReferenceProvider>, array{}>
  178. *
  179. * 200: Providers returned
  180. */
  181. #[NoAdminRequired]
  182. #[ApiRoute(verb: 'GET', url: '/providers', root: '/references')]
  183. public function getProvidersInfo(): DataResponse {
  184. $providers = $this->referenceManager->getDiscoverableProviders();
  185. $jsonProviders = array_values(array_map(static function (IDiscoverableReferenceProvider $provider) {
  186. return $provider->jsonSerialize();
  187. }, $providers));
  188. return new DataResponse($jsonProviders);
  189. }
  190. /**
  191. * Touch a provider
  192. *
  193. * @param string $providerId ID of the provider
  194. * @param int|null $timestamp Timestamp of the last usage
  195. * @return DataResponse<Http::STATUS_OK, array{success: bool}, array{}>
  196. *
  197. * 200: Provider touched
  198. */
  199. #[NoAdminRequired]
  200. #[ApiRoute(verb: 'PUT', url: '/provider/{providerId}', root: '/references')]
  201. public function touchProvider(string $providerId, ?int $timestamp = null): DataResponse {
  202. if ($this->userId !== null) {
  203. $success = $this->referenceManager->touchProvider($this->userId, $providerId, $timestamp);
  204. return new DataResponse(['success' => $success]);
  205. }
  206. return new DataResponse(['success' => false]);
  207. }
  208. }