From a23c01d26a66572de460d148ef63eba9e55c34a2 Mon Sep 17 00:00:00 2001
From: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Date: Mon, 31 Jul 2023 17:51:28 +0200
Subject: [PATCH] Bug 30708: Rebase - Use a dedicated 'config' endpoint

To retrieve the sysprefs, instead of using the svc script. See bug
33606.

Signed-off-by: Laurence Rault <laurence.rault@biblibre.com>
---
 Koha/REST/V1/Preservation.pm                  | 54 +++++++++++++++++++
 .../definitions/preservation_config.yaml      |  7 +++
 api/v1/swagger/paths/preservation_config.yaml | 38 +++++++++++++
 api/v1/swagger/swagger.yaml                   |  4 ++
 .../js/vue/components/Preservation/Main.vue   | 52 +++++++-----------
 .../vue/components/Preservation/Settings.vue  | 20 ++++---
 .../components/Preservation/TrainsFormAdd.vue |  7 +--
 .../components/Preservation/WaitingList.vue   |  9 ++--
 .../js/vue/fetch/preservation-api-client.js   |  9 ++++
 .../prog/js/vue/modules/preservation.ts       |  6 ++-
 .../prog/js/vue/stores/preservation.js        |  9 ++--
 11 files changed, 163 insertions(+), 52 deletions(-)
 create mode 100644 Koha/REST/V1/Preservation.pm
 create mode 100644 api/v1/swagger/definitions/preservation_config.yaml
 create mode 100644 api/v1/swagger/paths/preservation_config.yaml

diff --git a/Koha/REST/V1/Preservation.pm b/Koha/REST/V1/Preservation.pm
new file mode 100644
index 00000000000..994f9eb583b
--- /dev/null
+++ b/Koha/REST/V1/Preservation.pm
@@ -0,0 +1,54 @@
+package Koha::REST::V1::Preservation;
+
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
+
+use Modern::Perl;
+
+use Mojo::Base 'Mojolicious::Controller';
+
+use Koha::Patrons;
+
+use Try::Tiny qw( catch try );
+
+=head1 NAME
+
+Koha::REST::V1::Preservation
+
+=head1 API
+
+=head2 Class methods
+
+=head3 config
+
+Return the configuration options needed for the Preservation Vue app
+
+=cut
+
+sub config {
+    my $c = shift->openapi->valid_input or return;
+    return $c->render(
+        status  => 200,
+        openapi => {
+            settings => {
+                enabled                       => C4::Context->preference('PreservationModule'),
+                not_for_loan_waiting_list_in  => C4::Context->preference('PreservationNotForLoanWaitingListIn'),
+                not_for_loan_default_train_in => C4::Context->preference('PreservationNotForLoanDefaultTrainIn'),
+            },
+        },
+    );
+}
+
+1;
diff --git a/api/v1/swagger/definitions/preservation_config.yaml b/api/v1/swagger/definitions/preservation_config.yaml
new file mode 100644
index 00000000000..c88e1bd0bdf
--- /dev/null
+++ b/api/v1/swagger/definitions/preservation_config.yaml
@@ -0,0 +1,7 @@
+---
+type: object
+properties:
+  settings:
+    type: object
+    description: List of sysprefs used for the Preservation module
+additionalProperties: false
diff --git a/api/v1/swagger/paths/preservation_config.yaml b/api/v1/swagger/paths/preservation_config.yaml
new file mode 100644
index 00000000000..59cd7d4a4d3
--- /dev/null
+++ b/api/v1/swagger/paths/preservation_config.yaml
@@ -0,0 +1,38 @@
+---
+/preservation/config:
+  get:
+    x-mojo-to: Preservation#config
+    operationId: getPreservationconfig
+    description: This resource returns a list of options needed for the Preservation Vue app. EXPERIMENTAL - DO NOT RELY on this, it is subject to change!
+    summary: get the Preservation config
+    tags:
+      - Preservation
+    produces:
+      - application/json
+    responses:
+      200:
+        description: The Preservation module config
+        schema:
+          $ref: "../swagger.yaml#/definitions/preservation_config"
+      400:
+        description: Bad request
+        schema:
+          $ref: "../swagger.yaml#/definitions/error"
+      403:
+        description: Access forbidden
+        schema:
+          $ref: "../swagger.yaml#/definitions/error"
+      500:
+        description: |
+          Internal server error. Possible `error_code` attribute values:
+
+          * `internal_server_error`
+        schema:
+          $ref: "../swagger.yaml#/definitions/error"
+      503:
+        description: Under maintenance
+        schema:
+          $ref: "../swagger.yaml#/definitions/error"
+    x-koha-authorization:
+      permissions:
+        preservation: 1
diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml
index cc18bdf095b..acd886815f3 100644
--- a/api/v1/swagger/swagger.yaml
+++ b/api/v1/swagger/swagger.yaml
@@ -90,6 +90,8 @@ definitions:
     $ref: ./definitions/patron_balance.yaml
   patron_extended_attribute:
     $ref: ./definitions/patron_extended_attribute.yaml
+  preservation_config:
+    $ref: ./definitions/preservation_config.yaml
   preservation_train:
     $ref: ./definitions/preservation_train.yaml
   preservation_processing:
@@ -321,6 +323,8 @@ paths:
     $ref: "./paths/patrons_password.yaml#/~1patrons~1{patron_id}~1password"
   "/patrons/{patron_id}/password/expiration_date":
     $ref: "./paths/patrons_password.yaml#/~1patrons~1{patron_id}~1password~1expiration_date"
+  /preservation/config:
+    $ref: ./paths/preservation_config.yaml#/~1preservation~1config
   /preservation/trains:
     $ref: ./paths/preservation_trains.yaml#/~1preservation~1trains
   "/preservation/trains/{train_id}":
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/Main.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/Main.vue
index b5bcc9a7e8b..217bc513936 100644
--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/Main.vue
+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/Main.vue
@@ -1,5 +1,5 @@
 <template>
-    <div v-if="initialized && PreservationModule == 1">
+    <div v-if="initialized && config.settings.enabled == 1">
         <div id="sub-header">
             <Breadcrumbs />
             <Help />
@@ -32,6 +32,7 @@ import LeftMenu from "../LeftMenu.vue"
 import Dialog from "../Dialog.vue"
 import { APIClient } from "../../fetch/api-client.js"
 import "vue-select/dist/vue-select.css"
+import { storeToRefs } from "pinia"
 
 export default {
     setup() {
@@ -42,62 +43,45 @@ export default {
         const { loading, loaded, setError } = mainStore
 
         const PreservationStore = inject("PreservationStore")
+
+        const { config } = storeToRefs(PreservationStore)
+
         return {
             AVStore,
             loading,
             loaded,
+            config,
             setError,
-            PreservationStore,
         }
     },
     data() {
         return {
             initialized: false,
-            PreservationModule: null,
         }
     },
     beforeCreate() {
         this.loading()
 
-        const fetch_config = () => {
-            const sysprefs_client = APIClient.sysprefs
+        const fetch_additional_config = () => {
+            let promises = []
             const av_client = APIClient.authorised_values
-            let promises = [
-                sysprefs_client.sysprefs
-                    .get("PreservationNotForLoanWaitingListIn")
-                    .then(
-                        value => {
-                            this.PreservationStore.settings.not_for_loan_waiting_list_in =
-                                value.value
-                        },
-                        error => {}
-                    ),
-                sysprefs_client.sysprefs
-                    .get("PreservationNotForLoanDefaultTrainIn")
-                    .then(
-                        value => {
-                            this.PreservationStore.settings.not_for_loan_default_train_in =
-                                value.value
-                        },
-                        error => {}
-                    ),
+            promises.push(
                 av_client.values.get("NOT_LOAN").then(
                     values => {
                         this.AVStore.av_notforloan = values
                     },
                     error => {}
-                ),
-            ]
-
+                )
+            )
             return Promise.all(promises)
         }
 
-        const sysprefs_client = APIClient.sysprefs
-        sysprefs_client.sysprefs
-            .get("PreservationModule")
-            .then(value => {
-                this.PreservationModule = value.value
-                if (this.PreservationModule != 1) {
+        const client = APIClient.preservation
+        client.config
+            .get()
+            .then(config => {
+                this.config = config
+                if (this.config.settings.enabled != 1) {
                     return this.setError(
                         this.$__(
                             'The preservation module is disabled, turn on <a href="/cgi-bin/koha/admin/preferences.pl?tab=&op=search&searchfield=PreservationModule">PreservationModule</a> to use it'
@@ -105,7 +89,7 @@ export default {
                         false
                     )
                 }
-                return fetch_config()
+                return fetch_additional_config()
             })
             .then(() => {
                 this.loaded()
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/Settings.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/Settings.vue
index 29d8f1a4199..4170114aa92 100644
--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/Settings.vue
+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/Settings.vue
@@ -21,7 +21,9 @@
                             >
                             <v-select
                                 id="not_for_loan_waiting_list_in"
-                                v-model="settings.not_for_loan_waiting_list_in"
+                                v-model="
+                                    config.settings.not_for_loan_waiting_list_in
+                                "
                                 label="description"
                                 :reduce="av => av.value"
                                 :options="av_notforloan"
@@ -29,7 +31,8 @@
                                 <template #search="{ attributes, events }">
                                     <input
                                         :required="
-                                            !settings.not_for_loan_waiting_list_in
+                                            !config.settings
+                                                .not_for_loan_waiting_list_in
                                         "
                                         class="vs__search"
                                         v-bind="attributes"
@@ -48,7 +51,10 @@
                             >
                             <v-select
                                 id="not_for_loan_default_train_in"
-                                v-model="settings.not_for_loan_default_train_in"
+                                v-model="
+                                    config.settings
+                                        .not_for_loan_default_train_in
+                                "
                                 label="description"
                                 :reduce="av => av.value"
                                 :options="av_notforloan"
@@ -84,9 +90,9 @@ export default {
 
         const { setMessage, setWarning } = inject("mainStore")
         const PreservationStore = inject("PreservationStore")
-        const { settings } = storeToRefs(PreservationStore)
+        const { config } = PreservationStore
 
-        return { av_notforloan, setMessage, setWarning, settings }
+        return { av_notforloan, setMessage, setWarning, config }
     },
     data() {
         return {
@@ -108,12 +114,12 @@ export default {
             client.sysprefs
                 .update(
                     "PreservationNotForLoanWaitingListIn",
-                    this.settings.not_for_loan_waiting_list_in
+                    this.config.settings.not_for_loan_waiting_list_in
                 )
                 .then(
                     client.sysprefs.update(
                         "PreservationNotForLoanDefaultTrainIn",
-                        this.settings.not_for_loan_default_train_in || 0
+                        this.config.settings.not_for_loan_default_train_in || 0
                     )
                 )
                 .then(
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/TrainsFormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/TrainsFormAdd.vue
index c1ac05aa3e3..89ed2e70cab 100644
--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/TrainsFormAdd.vue
+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/TrainsFormAdd.vue
@@ -103,9 +103,9 @@ export default {
         const { setMessage, setWarning } = inject("mainStore")
 
         const PreservationStore = inject("PreservationStore")
-        const { settings } = storeToRefs(PreservationStore)
+        const { config } = PreservationStore
 
-        return { av_notforloan, setMessage, setWarning, settings }
+        return { av_notforloan, setMessage, setWarning, config }
     },
     data() {
         return {
@@ -113,7 +113,8 @@ export default {
                 train_id: null,
                 name: "",
                 description: "",
-                not_for_loan: this.settings.not_for_loan_default_train_in,
+                not_for_loan:
+                    this.config.settings.not_for_loan_default_train_in,
                 default_processing_id: null,
                 created_on: null,
                 closed_on: null,
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/WaitingList.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/WaitingList.vue
index cb7340d3b38..a8963d35ab8 100644
--- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/WaitingList.vue
+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Preservation/WaitingList.vue
@@ -81,7 +81,10 @@
         </div>
     </transition>
     <div v-if="!initialized">{{ $__("Loading") }}</div>
-    <div v-else-if="!settings.not_for_loan_waiting_list_in" id="waiting-list">
+    <div
+        v-else-if="!config.settings.not_for_loan_waiting_list_in"
+        id="waiting-list"
+    >
         {{ $__("You need to configure this module first.") }}
     </div>
     <div v-else id="waiting-list">
@@ -130,14 +133,14 @@ export default {
         const table = ref()
 
         const PreservationStore = inject("PreservationStore")
-        const { settings } = storeToRefs(PreservationStore)
+        const { config } = PreservationStore
 
         const { setMessage, setConfirmationDialog, loading, loaded } =
             inject("mainStore")
 
         return {
             table,
-            settings,
+            config,
             setMessage,
             setConfirmationDialog,
             loading,
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/preservation-api-client.js b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/preservation-api-client.js
index 329a01455ce..f8a281f4178 100644
--- a/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/preservation-api-client.js
+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/preservation-api-client.js
@@ -7,6 +7,15 @@ export class PreservationAPIClient extends HttpClient {
         });
     }
 
+    get config() {
+        return {
+            get: () =>
+                this.get({
+                    endpoint: "config",
+                }),
+        };
+    }
+
     get trains() {
         return {
             get: id =>
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/preservation.ts b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/preservation.ts
index eb8e2edbe60..b23624fc1b8 100644
--- a/koha-tmpl/intranet-tmpl/prog/js/vue/modules/preservation.ts
+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/modules/preservation.ts
@@ -40,6 +40,7 @@ import i18n from "../i18n";
 const pinia = createPinia();
 
 const mainStore = useMainStore(pinia);
+const AVStore = useAVStore(pinia);
 const navigationStore = useNavigationStore(pinia);
 const routes = navigationStore.setRoutes(routesDef);
 
@@ -60,9 +61,10 @@ const rootComponent = app
 
 app.config.unwrapInjectedRef = true;
 app.provide("mainStore", mainStore);
-app.provide("navigationStore", navigationStore);
 app.provide("AVStore", useAVStore(pinia));
-app.provide("PreservationStore", usePreservationStore(pinia));
+app.provide("navigationStore", navigationStore);
+const PreservationStore = usePreservationStore(pinia);
+app.provide("PreservationStore", PreservationStore);
 
 app.mount("#preservation");
 
diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/stores/preservation.js b/koha-tmpl/intranet-tmpl/prog/js/vue/stores/preservation.js
index 164dde6a68b..29b3e9d582f 100644
--- a/koha-tmpl/intranet-tmpl/prog/js/vue/stores/preservation.js
+++ b/koha-tmpl/intranet-tmpl/prog/js/vue/stores/preservation.js
@@ -2,9 +2,12 @@ import { defineStore } from "pinia";
 
 export const usePreservationStore = defineStore("preservation", {
     state: () => ({
-        settings: {
-            not_for_loan_waiting_list_in: null,
-            not_for_loan_default_train_in: 0,
+        config: {
+            settings: {
+                enabled: 0,
+                not_for_loan_waiting_list_in: null,
+                not_for_loan_default_train_in: 0,
+            },
         },
     }),
 });
-- 
2.25.1