浏览代码

POC working SSE update during file export

Olivier Massot 3 年之前
父节点
当前提交
f464394498

+ 3 - 0
models/Core/File.ts

@@ -23,4 +23,7 @@ export class File extends Model {
 
   @Num(null, { nullable: true })
   ownerId!: number
+
+  @Str('')
+  status!: 'PENDING' | 'READY' | 'ERROR'
 }

+ 2 - 14
models/Organization/OrganizationNetwork.ts

@@ -1,20 +1,8 @@
 import {Str, Model, Uid} from '@vuex-orm/core'
 
-export class OrganizationLicence extends Model {
-  static entity = 'organization_licences'
+export class OrganizationNetwork extends Model {
+  static entity = 'organization_networks'
 
   @Uid()
   id!: number | string | null
-
-  @Str('', { nullable: false })
-  licensee!: string
-
-  @Str(null, { nullable: true })
-  licenceNumber!: string|null
-
-  @Str(null, { nullable: true })
-  categorie!: string|null
-
-  @Str(null, { nullable: true })
-  validityDate!: string|null
 }

+ 40 - 0
models/_import.ts

@@ -0,0 +1,40 @@
+import {MyProfile} from "~/models/Access/MyProfile";
+import {PersonalizedList} from "~/models/Access/PersonalizedList";
+import {AddressPostal} from "~/models/Core/AddressPostal";
+import {BankAccount} from "~/models/Core/BankAccount";
+import {ContactPoint} from "~/models/Core/ContactPoint";
+import {Country} from "~/models/Core/Country";
+import {File} from "~/models/Core/File";
+import {Notification} from "~/models/Core/Notification";
+import {NotificationMessage} from "~/models/Core/NotificationMessage";
+import {NotificationUsers} from "~/models/Core/NotificationUsers";
+import {LicenceCmfOrganizationER} from "~/models/Export/LicenceCmfOrganizationER";
+import {Network} from "~/models/Network/Network";
+import {NetworkOrganization} from "~/models/Network/NetworkOrganization";
+import {Organization} from "~/models/Organization/Organization";
+import {OrganizationAddressPostal} from "~/models/Organization/OrganizationAddressPostal";
+import {OrganizationArticle} from "~/models/Organization/OrganizationArticle";
+import {OrganizationNetwork} from "~/models/Organization/OrganizationNetwork";
+import {TypeOfPractice} from "~/models/Organization/TypeOfPractice";
+
+
+export const models: Array<any> = [
+  MyProfile,
+  PersonalizedList,
+  AddressPostal,
+  BankAccount,
+  ContactPoint,
+  Country,
+  File,
+  Notification,
+  NotificationMessage,
+  NotificationUsers,
+  LicenceCmfOrganizationER,
+  Network,
+  NetworkOrganization,
+  Organization,
+  OrganizationAddressPostal,
+  OrganizationArticle,
+  OrganizationNetwork,
+  TypeOfPractice
+]

+ 57 - 21
pages/cmf_licence/organization.vue

@@ -14,7 +14,7 @@
     >
       <div class="ma-12">
         <v-btn
-          v-if="!pending && fileUrl === null"
+          v-if="!pending && file().value === null"
           @click="submit"
         >
           {{ $t('generate') }}
@@ -25,48 +25,85 @@
           color="primary"
           :loading="pending"
           :disabled="pending"
-          :href="fileUrl">
+          :href="file().value ? file().value.url : ''">
           {{ $t('download') }}
         </v-btn>
       </div>
     </v-form>
     <!-- <<< for debugging purposes, TODO: remove before deploying -->
-    <ul>
-      <li v-for="event in events">{{ event }}</li>
-    </ul>
+    <div v-if="file !== null">
+      {{ file().value }}
+    </div>
+<!--    <ul>-->
+<!--      <li v-for="event in events">{{ event }}</li>-->
+<!--    </ul>-->
     <!-- >>> for debugging purposes -->
   </div>
 </template>
 
 <script lang="ts">
-import {defineComponent, Ref, ref, useContext} from "@nuxtjs/composition-api";
-import {HTTP_METHOD, QUERY_TYPE} from "~/types/enums";
+import {computed, ComputedRef, defineComponent, Ref, ref, useContext} from "@nuxtjs/composition-api";
+import {DENORMALIZER_TYPE, QUERY_TYPE} from "~/types/enums";
 import DataPersister from "~/services/data/dataPersister";
 import {DataPersisterArgs} from "~/types/interfaces";
+import { Context } from "@nuxt/types";
+import {Repository as VuexRepository} from "@vuex-orm/core/dist/src/repository/Repository";
+import {Model, Query} from "@vuex-orm/core";
+import {repositoryHelper} from "~/services/store/repository";
+import {File} from "~/models/Core/File";
+import {queryHelper} from "~/services/store/query";
+import Serializer from "~/services/serializer/serializer";
 
 export default defineComponent({
   name: 'OrganizationCmfLicence',
   setup() {
-    const { store } = useContext()
+    const context = useContext()
 
-    let pending: Ref<boolean> = ref(false)
-    let fileUrl: Ref<string | null> = ref(null)
 
-    const async = () => { return store.state.sse.connected }
+    let fileId: Ref<number | null> = ref(null)
 
-    let events: Ref<Array<Array<any>>> = ref(store.state.sse.events)
+    const file: ComputedRef<File | null> = computed(() => {
+      if (fileId.value === null)
+        return null
+      return queryHelper.getItem(query, fileId.value) as File
+    })
+
+    let pending: ComputedRef<boolean> = computed(() => {
+      return file.value !== null && file.value.status === 'PENDING'
+    })
+
+    const async = () => { return context.store.state.sse.connected }
+
+    const repository: VuexRepository<Model> = repositoryHelper.getRepository(File)
+    const query: Query = repository.query()
 
     const submit = async () => {
-      const response = await DataPersister.request(
-        '/api/export/cmf-licence/organization',
-        HTTP_METHOD.POST,
-        { type: QUERY_TYPE.DEFAULT, data: { format: 'pdf', async: true }, withCredentials: true } as DataPersisterArgs
+      const dataPersister = new DataPersister()
+      dataPersister.initCtx(context as unknown as Context)
+
+      const response = await dataPersister.invoke(
+        {
+          url: '/api/export/cmf-licence/organization',
+          type: QUERY_TYPE.DEFAULT,
+          data: { format: 'pdf', async: true },
+          withCredentials: true
+        } as DataPersisterArgs
       )
+
       if (async()) {
-        pending.value = true
+        // pending.value = true
+        console.log(response)
+        let entry = Serializer.denormalize(response.data, DENORMALIZER_TYPE.HYDRA)
+        let model = repositoryHelper.persist(File, entry.data) as any
+
+        console.log(model)
+        fileId.value = model.id
+        // file.value = () => { return queryHelper.getItem(query, model.id) as File }
+        // file.value = queryHelper.getItem(query, model.id) as File
+
       } else {
-        console.warn('File downloaded synchronously')
-        fileUrl.value = JSON.parse(response).url
+        console.error('SSE unavailable - File downloaded synchronously')
+        // file.value = response
       }
     }
 
@@ -78,8 +115,7 @@ export default defineComponent({
     return {
       submit,
       pending,
-      fileUrl,
-      events
+      file: () => file
     }
   }
 })

+ 1 - 0
services/data/dataPersister.ts

@@ -33,6 +33,7 @@ class DataPersister extends BaseDataManager {
       queryArguments.id ? HTTP_METHOD.PUT : HTTP_METHOD.POST,
       queryArguments
     )
+
     // Deserialize, post-process and return the response
     return await this.provideResponse(response, queryArguments)
   }

+ 1 - 1
services/data/processor/modelProcessor.ts

@@ -15,7 +15,7 @@ class ModelProcessor extends BaseProcessor implements Processor {
 
   /**
    * Exécute la requête et retourne la réponse désérialisée
-   * @param data
+   * @param payload
    */
   async process (payload: ApiResponse): Promise<any> {
     if (typeof this.arguments.model === 'undefined') {

+ 1 - 2
services/serializer/denormalizer/hydra.ts

@@ -27,11 +27,10 @@ class Hydra extends BaseDenormalizer {
   }
 
   private static parseItem (hydraData: AnyJson): ApiResponse {
-    const itemResponse: ApiResponse = {
+    return {
       data: hydraData,
       metadata: Hydra.definedMetadataForItem(hydraData)
     }
-    return itemResponse
   }
     /**
    * Méthode de parsing appelé si on est dans un GET

+ 43 - 4
store/sse.ts

@@ -1,15 +1,54 @@
-import { sseState } from "~/types/interfaces";
+import {MercureEntityUpdate, sseState} from "~/types/interfaces";
+import {repositoryHelper} from "~/services/store/repository";
+import {models} from "~/models/_import";
+import Serializer from "~/services/serializer/serializer";
+import {DENORMALIZER_TYPE} from "~/types/enums";
+import {queryHelper} from "~/services/store/query";
+import {Repository as VuexRepository} from "@vuex-orm/core/dist/src/repository/Repository";
+import {Model, Query} from "@vuex-orm/core";
+import {File} from "~/models/Core/File";
 
 export const state = () => ({
   connected: false,
-  events: []
 })
 
 export const mutations = {
   setConnected(state: sseState, connected: boolean) {
     state.connected = connected
   },
-  addEvent(state: sseState, event: Array<any>) {
-    state.events.push(event)
+  addEvent(state: sseState, event: MercureEntityUpdate) {
+
+    switch (event.operation) {
+      case "update":
+        const matches = event.iri.match(/^\/api\/(\w+)\/.*/)
+        if (!matches) {
+          throw new Error('SSE: cannot parse the IRI')
+        }
+        const entityName = matches[1]
+
+        let model = models.find(candidate => { return candidate.entity === entityName })
+
+        // let entry = Serializer.denormalize(event.data, DENORMALIZER_TYPE.HYDRA)
+
+        console.log(JSON.parse(event.data))
+
+        let entry = Serializer.denormalize(JSON.parse(event.data), DENORMALIZER_TYPE.HYDRA)
+        console.log(entry)
+
+        let item = repositoryHelper.persist(model, entry.data) as any
+
+        const repository: VuexRepository<Model> = repositoryHelper.getRepository(model)
+        const query: Query = repository.query()
+        console.log(item)
+        console.log(queryHelper.getItem(query, item.id))
+        break
+
+      case "create":
+        break
+      case "delete":
+        break
+      default:
+        throw new Error('SSE: unknown operation type')
+    }
   }
 }

+ 7 - 1
types/interfaces.d.ts

@@ -289,7 +289,13 @@ interface HydraMetadata {
   type?: METADATA_TYPE
 }
 
+interface MercureEntityUpdate {
+  iri: string,
+  operation: 'create' | 'delete' | 'update',
+  data: any
+}
+
 interface sseState {
   connected: boolean,
-  events: Array<Array<any>>,
+  events: Array<MercureEntityUpdate>,
 }