From 1b262461492d759bf16747e773a603025c3eea3c Mon Sep 17 00:00:00 2001 From: Jonas Rittershofer Date: Mon, 9 Nov 2020 21:21:35 +0100 Subject: [PATCH 1/5] API return shared forms Signed-off-by: Jonas Rittershofer --- appinfo/routes.php | 1 + docs/API.md | 10 +++++++++ lib/Controller/ApiController.php | 35 +++++++++++++++++++++++++++++++- lib/Service/FormsService.php | 11 ++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index 3620e691e..4c58381da 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -43,6 +43,7 @@ ['name' => 'api#cloneForm', 'url' => '/api/v1/form/clone/{id}', 'verb' => 'POST'], ['name' => 'api#updateForm', 'url' => '/api/v1/form/update', 'verb' => 'POST'], ['name' => 'api#deleteForm', 'url' => '/api/v1/form/{id}', 'verb' => 'DELETE'], + ['name' => 'api#getSharedForms', 'url' => '/api/v1/shared_forms', 'verb' => 'GET'], // Questions ['name' => 'api#newQuestion', 'url' => '/api/v1/question', 'verb' => 'POST'], diff --git a/docs/API.md b/docs/API.md index 2f53614b9..5ac547b33 100644 --- a/docs/API.md +++ b/docs/API.md @@ -46,6 +46,16 @@ Returns condensed objects of all Forms beeing owned by the authenticated user. ] ``` +### List shared Forms +Returns condensed objects of all Forms, that are shared to the authenticated user via instance ([access-type](DataStructure.md#share-types) `registered` or `selected`) and have not expired yet. +- Endpoint: `/api/v1/shared_forms` +- Method: `GET` +- Parameters: None +- Response: Array of condensed Form Objects, sorted as newest first, similar to [List owned Forms](#list-owned-forms). +``` +See above, 'List owned forms' +``` + ### Create a new Form - Endpoint: `/api/v1/form` - Method: `POST` diff --git a/lib/Controller/ApiController.php b/lib/Controller/ApiController.php index 30c081a29..386662821 100644 --- a/lib/Controller/ApiController.php +++ b/lib/Controller/ApiController.php @@ -149,7 +149,8 @@ public function __construct(string $appName, /** * @NoAdminRequired * - * Read Form-List only with necessary information for Listing. + * Read Form-List of owned forms + * Return only with necessary information for Listing. * @return DataResponse */ public function getForms(): DataResponse { @@ -169,6 +170,38 @@ public function getForms(): DataResponse { return new DataResponse($result); } + /** + * @NoAdminRequired + * + * Read List of forms shared with current user + * Return only with necessary information for Listing. + * @return DataResponse + */ + public function getSharedForms(): DataResponse { + $forms = $this->formMapper->findAll(); + + $result = []; + foreach ($forms as $form) { + // Don't add if user is owner, user has no access, form has expired, form is link-shared + if ($form->getOwnerId() === $this->currentUser->getUID() + || !$this->formsService->hasUserAccess($form->getId()) + || $this->formsService->hasFormExpired($form->getId()) + || $form->getAccess()['type'] === 'public') { + continue; + } + + $result[] = [ + 'id' => $form->getId(), + 'hash' => $form->getHash(), + 'title' => $form->getTitle(), + 'expires' => $form->getExpires(), + 'partial' => true + ]; + } + + return new DataResponse($result); + } + /** * @NoAdminRequired * diff --git a/lib/Service/FormsService.php b/lib/Service/FormsService.php index afef7974e..7e097d2a1 100644 --- a/lib/Service/FormsService.php +++ b/lib/Service/FormsService.php @@ -248,6 +248,17 @@ public function hasUserAccess(int $formId): bool { return false; } + /* + * Has the form expired? + * + * @param int $formId The id of the form to check. + * @return boolean + */ + public function hasFormExpired(int $formId): bool { + $form = $this->formMapper->findById($formId); + return ($form->getExpires() !== 0 && $form->getExpires() < time()); + } + /** * Format users access * From 437155aeb6f7f7c49a356d781d61df284d325dd8 Mon Sep 17 00:00:00 2001 From: Jonas Rittershofer Date: Sun, 31 Jan 2021 12:26:30 +0100 Subject: [PATCH 2/5] Include shared forms into Sidebar Signed-off-by: Jonas Rittershofer --- src/Forms.vue | 48 +++++++++++++++++++++++++--- src/components/AppNavigationForm.vue | 6 +++- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/Forms.vue b/src/Forms.vue index 2f1ad59fd..3292b2de3 100644 --- a/src/Forms.vue +++ b/src/Forms.vue @@ -26,12 +26,23 @@ @@ -80,6 +91,7 @@ import axios from '@nextcloud/axios' import AppContent from '@nextcloud/vue/dist/Components/AppContent' import AppNavigation from '@nextcloud/vue/dist/Components/AppNavigation' +import AppNavigationCaption from '@nextcloud/vue/dist/Components/AppNavigationCaption' import AppNavigationNew from '@nextcloud/vue/dist/Components/AppNavigationNew' import Content from '@nextcloud/vue/dist/Components/Content' import isMobile from '@nextcloud/vue/src/mixins/isMobile' @@ -95,6 +107,7 @@ export default { AppNavigationForm, AppContent, AppNavigation, + AppNavigationCaption, AppNavigationNew, Content, EmptyContent, @@ -107,12 +120,19 @@ export default { loading: true, sidebarOpened: false, forms: [], + sharedForms: [], } }, computed: { noForms() { - return this.forms && this.forms.length === 0 + return this.noOwnedForms && this.noSharedForms + }, + noOwnedForms() { + return this.forms?.length === 0 + }, + noSharedForms() { + return this.sharedForms?.length === 0 }, routeHash() { @@ -121,12 +141,19 @@ export default { selectedForm: { get() { - return this.forms.find(form => form.hash === this.routeHash) + return this.forms.concat(this.sharedForms).find(form => form.hash === this.routeHash) }, set(form) { - const index = this.forms.findIndex(search => search.hash === this.routeHash) + // If a owned form + let index = this.forms.findIndex(search => search.hash === this.routeHash) if (index > -1) { this.$set(this.forms, index, form) + return + } + // Otherwise a shared form + index = this.sharedForms.findIndex(search => search.hash === this.routeHash) + if (index > -1) { + this.$set(this.sharedForms, index, form) } }, }, @@ -151,15 +178,26 @@ export default { */ async loadForms() { this.loading = true + + // Load Owned forms try { const response = await axios.get(generateOcsUrl('apps/forms/api/v1', 2) + 'forms') this.forms = OcsResponse2Data(response) } catch (error) { showError(t('forms', 'An error occurred while loading the forms list')) console.error(error) - } finally { - this.loading = false } + + // Load shared forms + try { + const response = await axios.get(generateOcsUrl('apps/forms/api/v1', 2) + 'shared_forms') + this.sharedForms = OcsResponse2Data(response) + } catch (error) { + showError(t('forms', 'An error occurred while loading the forms list')) + console.error(error) + } + + this.loading = false }, /** diff --git a/src/components/AppNavigationForm.vue b/src/components/AppNavigationForm.vue index 4a03787cd..52bcc33c2 100644 --- a/src/components/AppNavigationForm.vue +++ b/src/components/AppNavigationForm.vue @@ -27,7 +27,7 @@ :title="formTitle" :to="{ name: 'formRoot', params: { hash: form.hash } }" @click="mobileCloseNavigation"> -