DashboardApiController.php 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OCA\Dashboard\Controller;
  8. use OCA\Dashboard\ResponseDefinitions;
  9. use OCA\Dashboard\Service\DashboardService;
  10. use OCP\AppFramework\Http;
  11. use OCP\AppFramework\Http\Attribute\ApiRoute;
  12. use OCP\AppFramework\Http\Attribute\NoAdminRequired;
  13. use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
  14. use OCP\AppFramework\Http\DataResponse;
  15. use OCP\AppFramework\OCSController;
  16. use OCP\Dashboard\IAPIWidget;
  17. use OCP\Dashboard\IAPIWidgetV2;
  18. use OCP\Dashboard\IButtonWidget;
  19. use OCP\Dashboard\IIconWidget;
  20. use OCP\Dashboard\IManager;
  21. use OCP\Dashboard\IOptionWidget;
  22. use OCP\Dashboard\IReloadableWidget;
  23. use OCP\Dashboard\IWidget;
  24. use OCP\Dashboard\Model\WidgetButton;
  25. use OCP\Dashboard\Model\WidgetItem;
  26. use OCP\Dashboard\Model\WidgetOptions;
  27. use OCP\IConfig;
  28. use OCP\IRequest;
  29. /**
  30. * @psalm-import-type DashboardWidget from ResponseDefinitions
  31. * @psalm-import-type DashboardWidgetItem from ResponseDefinitions
  32. * @psalm-import-type DashboardWidgetItems from ResponseDefinitions
  33. */
  34. class DashboardApiController extends OCSController {
  35. public function __construct(
  36. string $appName,
  37. IRequest $request,
  38. private IManager $dashboardManager,
  39. private IConfig $config,
  40. private ?string $userId,
  41. private DashboardService $service,
  42. ) {
  43. parent::__construct($appName, $request);
  44. }
  45. /**
  46. * @param string[] $widgetIds Limit widgets to given ids
  47. * @return IWidget[]
  48. */
  49. private function getShownWidgets(array $widgetIds): array {
  50. if (empty($widgetIds)) {
  51. $systemDefault = $this->config->getAppValue('dashboard', 'layout', 'recommendations,spreed,mail,calendar');
  52. $widgetIds = explode(',', $this->config->getUserValue($this->userId, 'dashboard', 'layout', $systemDefault));
  53. }
  54. return array_filter(
  55. $this->dashboardManager->getWidgets(),
  56. static function (IWidget $widget) use ($widgetIds) {
  57. return in_array($widget->getId(), $widgetIds);
  58. },
  59. );
  60. }
  61. /**
  62. * Get the items for the widgets
  63. *
  64. * @param array<string, string> $sinceIds Array indexed by widget Ids, contains date/id from which we want the new items
  65. * @param int $limit Limit number of result items per widget
  66. * @psalm-param int<1, 30> $limit
  67. * @param list<string> $widgets Limit results to specific widgets
  68. * @return DataResponse<Http::STATUS_OK, array<string, list<DashboardWidgetItem>>, array{}>
  69. *
  70. * 200: Widget items returned
  71. */
  72. #[NoAdminRequired]
  73. #[NoCSRFRequired]
  74. #[ApiRoute(verb: 'GET', url: '/api/v1/widget-items')]
  75. public function getWidgetItems(array $sinceIds = [], int $limit = 7, array $widgets = []): DataResponse {
  76. $items = [];
  77. $widgets = $this->getShownWidgets($widgets);
  78. foreach ($widgets as $widget) {
  79. if ($widget instanceof IAPIWidget) {
  80. $items[$widget->getId()] = array_map(static function (WidgetItem $item) {
  81. return $item->jsonSerialize();
  82. }, $widget->getItems($this->userId, $sinceIds[$widget->getId()] ?? null, $limit));
  83. }
  84. }
  85. return new DataResponse($items);
  86. }
  87. /**
  88. * Get the items for the widgets
  89. *
  90. * @param array<string, string> $sinceIds Array indexed by widget Ids, contains date/id from which we want the new items
  91. * @param int $limit Limit number of result items per widget, not more than 30 are allowed
  92. * @psalm-param int<1, 30> $limit
  93. * @param list<string> $widgets Limit results to specific widgets
  94. * @return DataResponse<Http::STATUS_OK, array<string, DashboardWidgetItems>, array{}>
  95. *
  96. * 200: Widget items returned
  97. */
  98. #[NoAdminRequired]
  99. #[NoCSRFRequired]
  100. #[ApiRoute(verb: 'GET', url: '/api/v2/widget-items')]
  101. public function getWidgetItemsV2(array $sinceIds = [], int $limit = 7, array $widgets = []): DataResponse {
  102. $items = [];
  103. $widgets = $this->getShownWidgets($widgets);
  104. foreach ($widgets as $widget) {
  105. if ($widget instanceof IAPIWidgetV2) {
  106. $items[$widget->getId()] = $widget
  107. ->getItemsV2($this->userId, $sinceIds[$widget->getId()] ?? null, $limit)
  108. ->jsonSerialize();
  109. }
  110. }
  111. return new DataResponse($items);
  112. }
  113. /**
  114. * Get the widgets
  115. *
  116. * @return DataResponse<Http::STATUS_OK, array<string, DashboardWidget>, array{}>
  117. *
  118. * 200: Widgets returned
  119. */
  120. #[NoAdminRequired]
  121. #[NoCSRFRequired]
  122. #[ApiRoute(verb: 'GET', url: '/api/v1/widgets')]
  123. public function getWidgets(): DataResponse {
  124. $widgets = $this->dashboardManager->getWidgets();
  125. $items = array_map(function (IWidget $widget) {
  126. $options = ($widget instanceof IOptionWidget) ? $widget->getWidgetOptions() : WidgetOptions::getDefault();
  127. $data = [
  128. 'id' => $widget->getId(),
  129. 'title' => $widget->getTitle(),
  130. 'order' => $widget->getOrder(),
  131. 'icon_class' => $widget->getIconClass(),
  132. 'icon_url' => ($widget instanceof IIconWidget) ? $widget->getIconUrl() : '',
  133. 'widget_url' => $widget->getUrl(),
  134. 'item_icons_round' => $options->withRoundItemIcons(),
  135. 'item_api_versions' => [],
  136. 'reload_interval' => 0,
  137. ];
  138. if ($widget instanceof IButtonWidget) {
  139. $data += [
  140. 'buttons' => array_map(function (WidgetButton $button) {
  141. return [
  142. 'type' => $button->getType(),
  143. 'text' => $button->getText(),
  144. 'link' => $button->getLink(),
  145. ];
  146. }, $widget->getWidgetButtons($this->userId)),
  147. ];
  148. }
  149. if ($widget instanceof IReloadableWidget) {
  150. $data['reload_interval'] = $widget->getReloadInterval();
  151. }
  152. if ($widget instanceof IAPIWidget) {
  153. $data['item_api_versions'][] = 1;
  154. }
  155. if ($widget instanceof IAPIWidgetV2) {
  156. $data['item_api_versions'][] = 2;
  157. }
  158. return $data;
  159. }, $widgets);
  160. return new DataResponse($items);
  161. }
  162. /**
  163. * Get the layout
  164. *
  165. * @return DataResponse<Http::STATUS_OK, array{layout: list<string>}, array{}>
  166. *
  167. * 200: Layout returned
  168. */
  169. #[NoAdminRequired]
  170. #[ApiRoute(verb: 'GET', url: '/api/v3/layout')]
  171. public function getLayout(): DataResponse {
  172. return new DataResponse(['layout' => $this->service->getLayout()]);
  173. }
  174. /**
  175. * Update the layout
  176. *
  177. * @param list<string> $layout The new layout
  178. * @return DataResponse<Http::STATUS_OK, array{layout: list<string>}, array{}>
  179. *
  180. * 200: Statuses updated successfully
  181. */
  182. #[NoAdminRequired]
  183. #[ApiRoute(verb: 'POST', url: '/api/v3/layout')]
  184. public function updateLayout(array $layout): DataResponse {
  185. $this->config->setUserValue($this->userId, 'dashboard', 'layout', implode(',', $layout));
  186. return new DataResponse(['layout' => $layout]);
  187. }
  188. /**
  189. * Get the statuses
  190. *
  191. * @return DataResponse<Http::STATUS_OK, array{statuses: list<string>}, array{}>
  192. *
  193. * 200: Statuses returned
  194. */
  195. #[NoAdminRequired]
  196. #[ApiRoute(verb: 'GET', url: '/api/v3/statuses')]
  197. public function getStatuses(): DataResponse {
  198. return new DataResponse(['statuses' => $this->service->getStatuses()]);
  199. }
  200. /**
  201. * Update the statuses
  202. *
  203. * @param list<string> $statuses The new statuses
  204. * @return DataResponse<Http::STATUS_OK, array{statuses: list<string>}, array{}>
  205. *
  206. * 200: Statuses updated successfully
  207. */
  208. #[NoAdminRequired]
  209. #[ApiRoute(verb: 'POST', url: '/api/v3/statuses')]
  210. public function updateStatuses(array $statuses): DataResponse {
  211. $this->config->setUserValue($this->userId, 'dashboard', 'statuses', implode(',', $statuses));
  212. return new DataResponse(['statuses' => $statuses]);
  213. }
  214. }