From fe5500c2e2cb250ab5091ea5008251cf428b0312 Mon Sep 17 00:00:00 2001
From: Mathieu Massaviol <mathieu.massaviol@univ-amu.fr>
Date: Wed, 20 Nov 2024 11:23:01 +0100
Subject: [PATCH] Add visibility choice for new subcatalog #35

---
 .../OcCatalogForm/OcCatalogForm.vue           | 81 ++++++++++++++++++-
 .../catalog/[[identifier]].new.vue            |  2 -
 src/sparql/catalog.ts                         | 10 ++-
 3 files changed, 87 insertions(+), 6 deletions(-)

diff --git a/src/components/OcCatalogForm/OcCatalogForm.vue b/src/components/OcCatalogForm/OcCatalogForm.vue
index 0598546..226ea00 100644
--- a/src/components/OcCatalogForm/OcCatalogForm.vue
+++ b/src/components/OcCatalogForm/OcCatalogForm.vue
@@ -10,7 +10,7 @@
         <OcCatalogSelect
           inputId="parentCatalog"
           :model-value="value"
-          @update:model-value="handleChange"
+          @update:model-value="updateParentCatalogValue($event, handleChange, resetField)"
           :community="community"
           :auth="auth"
           :invalid="!!errorMessage"
@@ -21,6 +21,40 @@
       </OcField>
       <Message v-if="errorMessage" severity="error">{{ errorMessage }}</Message>
     </Field>
+    <Field v-if="!edit" name="visibility" v-slot="{ value, errorMessage, handleChange }">
+      <div class="flex gap-1 mb-2 items-center">
+        <label for="visibility" class="required">
+          {{ t('datasets.new.steps.2.access') }}
+        </label>
+        <OcFairBadge :letter="false" size="small" :badges="['f', 'r']" :popover="true" />
+      </div>
+      <Message severity="secondary" icon="fa fa-info" class="text-sm">
+        <p class="italic mb-2">{{ t('datasets.new.steps.2.accessHelp.1') }}</p>
+        <p class="mb-2">{{ t('datasets.new.steps.2.accessHelp.2') }}</p>
+        <p>{{ t('datasets.new.steps.2.accessHelp.3') }}</p>
+        <p class="mb-2">{{ t('datasets.new.steps.2.accessHelp.4') }}</p>
+        <p class="mb-2">{{ t('datasets.new.steps.2.accessHelp.5') }}</p>
+        <p class="mb-2">{{ t('datasets.new.steps.2.accessHelp.6') }}</p>
+      </Message>
+      <SelectButton
+        inputId="visibility"
+        :model-value="value"
+        :options="visibilityOptions"
+        optionLabel="key"
+        optionValue="graph"
+        optionDisabled="disabled"
+        @update:model-value="handleChange"
+        :invalid="!!errorMessage"
+        required
+      >
+        <template #option="slotProps">
+          <OcVisibilityIcon :visibility="slotProps.option.key" class="text-[0.6rem] -mr-1" />
+          {{ t('resourceVisibility.' + slotProps.option.key) }}
+        </template>
+      </SelectButton>
+      <Message v-if="errorMessage" severity="error">{{ errorMessage }}</Message>
+    </Field>
+    <hr v-if="!edit" class="my-4"/>
     <Field name="title" v-slot="{ value, handleChange, errorMessage }">
       <OcField for="title" :metadata="catalogMetadata.title">
         <OcMultilingualField
@@ -175,6 +209,7 @@ import DatePicker from 'primevue/datepicker'
 import InputText from 'primevue/inputtext'
 import Textarea from 'primevue/textarea'
 import Message from 'primevue/message'
+import SelectButton from 'primevue/selectbutton'
 import OcField from '@/components/FormInputs/OcField/OcField.vue'
 import OcAgentAutocomplete from '@/components/FormInputs/OcAgentAutocomplete/OcAgentAutocomplete.vue'
 import OcConceptAutocomplete from '@/components/FormInputs/OcConceptAutocomplete/OcConceptAutocomplete.vue'
@@ -185,9 +220,13 @@ import { toTypedSchema } from '@vee-validate/yup'
 import OcMultilingualField from '../FormInputs/OcMultilingualField/OcMultilingualField.vue'
 import OcMultipleField from '../FormInputs/OcMultipleField/OcMultipleField.vue'
 import type { PropType } from 'vue'
+import { ref } from 'vue'
+import { getVisibilityOptionsFor } from '@/helpers/resourceVisibility'
+import { useAbility } from '@casl/vue'
 
 const { t } = useI18n()
 const { translateValue } = useTranslateValue()
+const { can } = useAbility()
 
 const props = defineProps({
   community: {
@@ -227,17 +266,36 @@ const emit = defineEmits<{
   cancel: []
 }>()
 
+const visibilityOptions = ref(
+  getVisibilityOptionsFor(can, props.community, undefined, props.userPrivateGraph)
+)
+
 let parentCatalog = yup
   .object<OcCatalogSummary>()
   .label(translateValue(catalogMetadata.parentCatalog.label))
 
+let visibility = yup
+        .string()
+        .matches(
+          new RegExp(
+            visibilityOptions.value
+              .filter((item) => !item.disabled)
+              .map((item) => item.key)
+              .join('|')
+          ),
+          'Choosen option is disabled'
+        )
+        .label(t('datasets.new.steps.2.access'))
+
 if (!props.edit) {
   parentCatalog = parentCatalog.required()
+  visibility = visibility.required()
 }
 
 const validationSchema = toTypedSchema(
   yup.object({
     parentCatalog,
+    visibility,
     title: yup
       .mixed<LocalizedProperty<string>>()
       .required()
@@ -274,7 +332,6 @@ const validationSchema = toTypedSchema(
 
 const submit = async (values: GenericObject) => {
   // Mandatory values
-  model.value.parentCatalog = values.parentCatalog
   model.value.title = values.title
   model.value.description = values.description
   model.value.contactPoint = values.contactPoint
@@ -285,6 +342,26 @@ const submit = async (values: GenericObject) => {
   model.value.issued = values.issued
   model.value.temporal = values.temporal
   model.value.spatial = values.spatial
+
+  if (!props.edit){
+    model.value.parentCatalog = values.parentCatalog
+    model.value.graph = [values.visibility]
+  }
   emit('save')
 }
+
+const updateParentCatalogValue = (
+  value: OcCatalogSummary | undefined,
+  handleChange: Function,
+  resetField: Function
+) => {
+  handleChange(value)
+  visibilityOptions.value = getVisibilityOptionsFor(
+    can,
+    props.community,
+    value,
+    props.userPrivateGraph
+  )
+  resetField('visibility', undefined)
+}
 </script>
diff --git a/src/pages/community/[community]/catalog/[[identifier]].new.vue b/src/pages/community/[community]/catalog/[[identifier]].new.vue
index d67ebef..35ef3a4 100644
--- a/src/pages/community/[community]/catalog/[[identifier]].new.vue
+++ b/src/pages/community/[community]/catalog/[[identifier]].new.vue
@@ -119,8 +119,6 @@ const send = async () => {
     // Insert catalog
     catalog.value = await insertCatalog(
       catalog.value,
-      // TODO Is it really here we want to insert ? (#67)
-      accountStore.infos.hasPrivateGraph,
       catalog.value.parentCatalog as OcCatalog,
       accountStore.profile,
       accountStore.auth
diff --git a/src/sparql/catalog.ts b/src/sparql/catalog.ts
index ff5af15..1eb219e 100644
--- a/src/sparql/catalog.ts
+++ b/src/sparql/catalog.ts
@@ -185,7 +185,6 @@ export const getCatalogSummaryFromChildUri = async (uri: string, auth?: Credenti
 
 export async function insertCatalog(
   catalog: OcCatalog,
-  graph: string,
   parentCatalog: OcCatalog,
   profile: OcPerson,
   auth?: Credentials
@@ -193,8 +192,15 @@ export async function insertCatalog(
   catalog.identifier ||= crypto.randomUUID()
   catalog['@id'] ||= `${import.meta.env.VITE_OC_URI_BASE_URL}/catalogs/${catalog.identifier}`
 
+  if (!catalog.graph) {
+    throw Error('Catalog has no graph!')
+  }
+  if (!catalog.parentCatalog) {
+    throw Error('Catalog has no parent catalog!')
+  }
+
   let insertQuery = `
-    INSERT INTO <${graph}> {
+    INSERT INTO <${catalog.graph}> {
       <${parentCatalog['@id']}> dcat:catalog <${catalog['@id']}>.
   `
   insertQuery += buildCatalogTriples(catalog, profile)
-- 
GitLab