Przeglądaj źródła

rewrite models and many fixes

Olivier Massot 3 lat temu
rodzic
commit
6f13d6c4ce
45 zmienionych plików z 899 dodań i 506 usunięć
  1. 2 2
      .env.local
  2. 31 21
      composables/data/useAp2iRequestService.ts
  3. 3 3
      layouts/default.vue
  4. 13 5
      models/Access/Access.ts
  5. 13 7
      models/Access/AdminAccess.ts
  6. 53 7
      models/Access/MyProfile.ts
  7. 14 8
      models/Access/PersonalizedList.ts
  8. 12 16
      models/ApiModel.ts
  9. 18 0
      models/ApiResource.ts
  10. 11 5
      models/Billing/ResidenceArea.ts
  11. 31 25
      models/Core/AddressPostal.ts
  12. 28 21
      models/Core/BankAccount.ts
  13. 29 23
      models/Core/ContactPoint.ts
  14. 10 4
      models/Core/Country.ts
  15. 18 12
      models/Core/File.ts
  16. 16 10
      models/Core/Notification.ts
  17. 13 9
      models/Core/NotificationMessage.ts
  18. 15 9
      models/Core/NotificationUsers.ts
  19. 12 6
      models/Education/Cycle.ts
  20. 11 5
      models/Education/EducationTiming.ts
  21. 16 10
      models/Export/LicenceCmfOrganizationER.ts
  22. 11 5
      models/Network/Network.ts
  23. 12 6
      models/Network/NetworkOrganization.ts
  24. 47 39
      models/Organization/Organization.ts
  25. 12 6
      models/Organization/OrganizationAddressPostal.ts
  26. 12 6
      models/Organization/OrganizationArticle.ts
  27. 17 11
      models/Organization/OrganizationLicence.ts
  28. 4 3
      models/Organization/OrganizationNetwork.ts
  29. 44 0
      models/Organization/OrganizationProfile.ts
  30. 80 74
      models/Organization/Parameters.ts
  31. 13 8
      models/Organization/Subdomain.ts
  32. 11 5
      models/Organization/TypeOfPractice.ts
  33. 12 6
      models/Person/Person.ts
  34. 0 40
      models/_import.ts
  35. 5 5
      nuxt.config.ts
  36. 7 1
      package.json
  37. 18 0
      pages/form.vue
  38. 1 7
      pages/index.vue
  39. 9 0
      pages/organization.vue
  40. 0 0
      pages/organization/id_.vue
  41. 63 0
      pages/organization/index.vue
  42. 1 2
      plugins/init.server.ts
  43. 8 8
      services/data/apiRequestService.ts
  44. 125 42
      services/data/entityManager.ts
  45. 18 24
      store/profile/access.ts

+ 2 - 2
.env.local

@@ -18,11 +18,11 @@ NUXT_BASE_URL_ADMIN_LEGACY=https://local.admin.opentalent.fr/#
 NUXT_PUBLIC_BASE_URL_ADMIN_LEGACY=https://local.admin.opentalent.fr/#
 
 # Typo3 Base Url
-NUXT_BASE_URL_TYPO3=https://local.sub.opentalent.fr/###subDomain###
+NUXT_BASE_URL_TYPO3=https://typo3/###subDomain###
 NUXT_PUBLIC_BASE_URL_TYPO3=https://local.sub.opentalent.fr/###subDomain###
 
 # Mercure push events
-NUXT_BASE_URL_MERCURE=https://local.mercure.opentalent.fr/.well-known/mercure
+NUXT_BASE_URL_MERCURE=https://mercure/.well-known/mercure
 NUXT_PUBLIC_BASE_URL_MERCURE=https://local.mercure.opentalent.fr/.well-known/mercure
 
 MERCURE_SUBSCRIBER_JWT_KEY=NQEupdREijrfYvCmF2mnvZQFL9zLKDH9RCYter6tUWzjemPqzicffhc2fSf0yEmM

+ 31 - 21
composables/data/useAp2iRequestService.ts

@@ -2,9 +2,10 @@ import {useProfileAccessStore} from "~/store/profile/access";
 import {FetchContext, FetchOptions} from "ohmyfetch";
 import Page from "~/services/store/page";
 import {TYPE_ALERT} from "~/types/enums";
-import {useRuntimeConfig} from "#app";
+import {useAppConfig, useRuntimeConfig} from "#app";
 import OhMyFetchConnector from "~/services/data/connector/ohMyFetchConnector";
 import ApiRequestService from "~/services/data/apiRequestService";
+import {AssociativeArray} from "~/services/data/data";
 
 /**
  * Retourne une instance de ApiRequestService configurée pour interroger l'api Ap2i
@@ -14,30 +15,35 @@ import ApiRequestService from "~/services/data/apiRequestService";
 export const useAp2iRequestService = () => {
     const runtimeConfig = useRuntimeConfig()
 
+    const baseURL = runtimeConfig.baseUrl ?? runtimeConfig.public.baseUrl
+
     /**
      * Peuple les headers avant l'envoi de la requête
      *
      * @param request
      * @param options
      */
-    // const onRequest = async function ({ request, options }: FetchContext) {
-    //     // @ts-ignore
-    //     if(options && options.noXaccessId) {
-    //         return
-    //     }
-    //
-    //     request = request as Request
-    //
-    //     console.log(request, options)
-    //
-    //     const profileAccessStore = useProfileAccessStore()
-    //     request.headers.set('x-accessid', String(profileAccessStore.id))
-    //     request.headers.set('Authorization', 'BEARER ' + profileAccessStore.bearer)
-    //
-    //     if (profileAccessStore.switchId) {
-    //         request.headers.set('x-switch-user', String(profileAccessStore.switchId))
-    //     }
-    // }
+    const onRequest = async function ({ request, options }: FetchContext) {
+        // @ts-ignore
+        if(options && options.noXaccessId) {
+            return
+        }
+
+        const profileAccessStore = useProfileAccessStore()
+
+        const headers: AssociativeArray = {
+            'x-accessid': String(profileAccessStore.id),
+            'Authorization': 'BEARER ' + profileAccessStore.bearer,
+        }
+
+        if (profileAccessStore.switchId) {
+            headers['x-switch-user'] = String(profileAccessStore.switchId)
+        }
+
+        options.headers = { ...options.headers, ...headers }
+
+        console.log('Request : ' + request + ' (SSR: ' + process.server + ')')
+    }
 
     /**
      * Gère les erreurs retournées par l'api
@@ -48,19 +54,22 @@ export const useAp2iRequestService = () => {
      */
     const onResponseError = async function ({ request, response, error }: FetchContext) {
         if (response && response.status === 401) {
-            navigateTo('/login')
+            // navigateTo('/login')
+            console.error('Unauthorized')
         }
         if (response && response.status === 403) {
             new Page().addAlerts(TYPE_ALERT.ALERT, ['forbidden'])
+            console.error('forbidden')
         }
 
         if (response && response.status === 500) {
             new Page().addAlerts(TYPE_ALERT.ALERT, [error ? error.message : response.statusText])
+            console.error(error ? error.message : response.statusText)
         }
     }
 
     const config : FetchOptions = {
-        baseURL: runtimeConfig.baseUrl ?? runtimeConfig.public.baseUrl,
+        baseURL,
         onRequest,
         onResponseError
     }
@@ -69,5 +78,6 @@ export const useAp2iRequestService = () => {
     const fetcher = $fetch.create(config)
 
     const connector = new OhMyFetchConnector(fetcher)
+
     return new ApiRequestService(connector)
 }

+ 3 - 3
layouts/default.vue

@@ -1,10 +1,10 @@
 <template>
   <div>
     <!-- The client only is used to show the loading picture -->
-    <ClientOnly placeholder-tag="client-only-placeholder" placeholder=" " />
-
+<!--    <ClientOnly placeholder-tag="client-only-placeholder" placeholder=" " />-->
+    <h1>Test</h1>
     <v-app>
-      <LayoutMenu v-if="displayedMenu" :menu="menu" :mini-variant="properties.miniVariant" :openMenu="properties.openMenu" />
+<!--      <LayoutMenu v-if="displayedMenu" :menu="menu" :mini-variant="properties.miniVariant" :openMenu="properties.openMenu" />-->
 
 <!--      <LayoutHeader @handle-open-menu-click="handleOpenMenu" @handle-open-mini-menu-click="handleOpenMiniMenu" />-->
 

+ 13 - 5
models/Access/Access.ts

@@ -1,17 +1,25 @@
 import { Historical } from '~/types/interfaces'
 import {Person} from "~/models/Person/Person";
 import ApiModel from "~/models/ApiModel";
-import {HasOne, Num} from "pinia-orm/dist/decorators";
+import {HasOne, Num, Uid, Attr} from "pinia-orm/dist/decorators";
 
+/**
+ * AP2i Model : Access
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Access/Access.php
+ */
 export class Access extends ApiModel {
   static entity = 'accesses'
 
+  @Uid()
+  declare id: number | string
+
   @HasOne(() => Person, 'accessId')
-  person!: Person | null
+  declare person: Person | null
 
-  @Num(0, { nullable: true })
-  activityYear!: number
+  @Num(0)
+  declare activityYear: number
 
   @Attr({})
-  historical!: Historical
+  declare historical: Historical
 }

+ 13 - 7
models/Access/AdminAccess.ts

@@ -1,14 +1,20 @@
-import {Model, Str, Uid} from "pinia-orm";
+import {Str, Uid} from "pinia-orm/dist/decorators";
+import ApiResource from "~/models/ApiResource";
 
-export class AdminAccess extends Model {
+/**
+ * AP2i ApiResource : https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/ApiResources/Access/AdminAccess.php
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/ApiResources/Access/AdminAccess.php
+ */
+export class AdminAccess extends ApiResource {
   static entity = 'admin'
 
   @Uid()
-  id!: number
+  declare id: number
 
-  @Str(null, { nullable: true })
-  username!: string|null
+  @Str(null)
+  declare username: string|null
 
-  @Str(null, { nullable: true })
-  email!: string|null
+  @Str(null)
+  declare email: string|null
 }

+ 53 - 7
models/Access/MyProfile.ts

@@ -1,16 +1,62 @@
-import {Model} from 'pinia-orm'
-import {Num, Uid, Attr} from 'pinia-orm/dist/decorators'
+import {Num, Uid, Attr, Bool, Str} from 'pinia-orm/dist/decorators'
 import { Historical } from '~/types/interfaces'
+import {Access} from "~/models/Access/Access";
+import {OrganizationProfile} from "~/models/Organization/OrganizationProfile";
+import ApiResource from "~/models/ApiResource";
 
-export class MyProfile extends Model {
-  static entity = 'accesses'
+/**
+ * Ap2i ApiResource : AccessProfile
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/ApiResources/Profile/AccessProfile.php
+ */
+export class MyProfile extends ApiResource {
+  static entity = 'my_profile'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
+
+  @Bool(false)
+  declare isAdminAccess: boolean
+
+  @Bool(false)
+  declare isSuperAdminAccess: boolean
+
+  @Str(null)
+  declare name: string
+
+  @Str(null)
+  declare givenName: string
+
+  @Str(null)
+  declare gender: string
+
+  @Num(null)
+  declare avatarId: number
+
+  @Attr([])
+  declare roles: Array<string>
 
   @Num(0, { notNullable: false })
-  activityYear!: number
+  declare activityYear: number
+
+  @Attr({})
+  declare historical: Historical
+
+  @Bool(false)
+  declare isGuardian: boolean
+
+  @Bool(false)
+  declare isPayor: boolean
+
+  @Attr({})
+  declare organization: OrganizationProfile | null
+
+  @Attr([])
+  declare multiAccesses: Array<string>
+
+  @Attr([])
+  declare familyAccesses: Array<string>
 
   @Attr({})
-  historical!: Historical
+  declare originalAccess: Access | null
 }

+ 14 - 8
models/Access/PersonalizedList.ts

@@ -1,17 +1,23 @@
-import {Model, Str, Uid} from 'pinia-orm'
+import {Str, Uid} from "pinia-orm/dist/decorators";
+import ApiModel from "~/models/ApiModel";
 
-export class PersonalizedList extends Model {
+/**
+ * Ap2i Model : PersonalizedList
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Access/PersonalizedList.php
+ */
+export class PersonalizedList extends ApiModel {
   static entity = 'personalized_lists'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
-  @Str(null, { nullable: true })
-  label!:string|null
+  @Str(null)
+  declare label:string|null
 
-  @Str(null, { nullable: true })
-  entity!:string|null
+  @Str(null)
+  declare entity:string|null
 
   @Str('')
-  menuKey!:string
+  declare menuKey:string
 }

+ 12 - 16
models/ApiModel.ts

@@ -1,19 +1,15 @@
-import { Model } from "pinia-orm";
-import {Uid} from "pinia-orm/dist/decorators";
-
-export class ApiModel extends Model {
-    @Uid()
-    id!: number | string
-
-    /**
-     * Does the entity exists in the data source
-     */
-    persisted: boolean = false
-
-    /**
-     * The entity as it was when it was fetched from the data source
-     */
-    initialState: object | null = null
+import ApiResource from "~/models/ApiResource";
+import {ModelOptions} from "pinia-orm";
+import {randomUUID} from "crypto";
+
+/**
+ * Entities from the API
+ *
+ * These models support CRUD operations
+ *
+ * TODO: faut il séparer les apiresources des entités?
+ */
+export class ApiModel extends ApiResource {
 }
 
 export default ApiModel

+ 18 - 0
models/ApiResource.ts

@@ -0,0 +1,18 @@
+import {Model, ModelOptions} from "pinia-orm";
+import {randomUUID} from "crypto";
+
+/**
+ * Base class for resources that can be fetched from the API
+ */
+export class ApiResource extends Model {
+    /**
+     * Is it a newly created entity?
+     *
+     * If it is, it means this entity does not exist in the data source and that it has a temporary id
+     */
+    public isNew(): boolean {
+        return !this.id || (typeof this.id === 'string' && this.id.slice(0, 3) === 'tmp')
+    }
+}
+
+export default ApiResource

+ 11 - 5
models/Billing/ResidenceArea.ts

@@ -1,11 +1,17 @@
-import {Str, Model, Uid} from 'pinia-orm'
+import ApiModel from "~/models/ApiModel";
+import {Str, Uid} from "pinia-orm/dist/decorators";
 
-export class ResidenceArea extends Model {
+/**
+ * Ap2i Model : ResidenceArea
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Billing/ResidenceArea.php
+ */
+export class ResidenceArea extends ApiModel {
   static entity = 'residence_areas'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
-  @Str(null, { nullable: true })
-  label!: string|null
+  @Str(null)
+  declare label: string|null
 }

+ 31 - 25
models/Core/AddressPostal.ts

@@ -1,41 +1,47 @@
-import {Attr, Str, Num, Model, Uid} from 'pinia-orm'
-
-export class AddressPostal extends Model {
+import ApiModel from "~/models/ApiModel";
+import {Num, Str, Uid, Attr} from "pinia-orm/dist/decorators";
+
+/**
+ * Ap2i Model : AddressPostal
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Core/AddressPostal.php
+ */
+export class AddressPostal extends ApiModel {
   static entity = 'address_postals'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
-  @Str('', { nullable: true })
-  '@id'!: string
+  @Str('')
+  declare '@id': string // TODO: pqoi le conserver celui là?
 
   @Attr(null)
-  organizationAddressPostalId!: number | null
+  declare organizationAddressPostalId: number | null
 
-  @Str(null, { nullable: true })
-  addressCountry!: string|null
+  @Str(null)
+  declare addressCountry: string|null
 
-  @Str(null, { nullable: true })
-  addressCity!: string|null
+  @Str(null)
+  declare addressCity: string|null
 
-  @Str(null, { nullable: true })
-  addressOwner!: string|null
+  @Str(null)
+  declare addressOwner: string|null
 
-  @Str(null, { nullable: true })
-  postalCode!: string|null
+  @Str(null)
+  declare postalCode: string|null
 
-  @Str(null, { nullable: true })
-  streetAddress!: string|null
+  @Str(null)
+  declare streetAddress: string|null
 
-  @Str(null, { nullable: true })
-  streetAddressSecond!: string|null
+  @Str(null)
+  declare streetAddressSecond: string|null
 
-  @Str(null, { nullable: true })
-  streetAddressThird!: string|null
+  @Str(null)
+  declare streetAddressThird: string|null
 
-  @Num(0, { nullable: true })
-  latitude!: number
+  @Num(0)
+  declare latitude: number
 
-  @Num(0, { nullable: true })
-  longitude!: number
+  @Num(0)
+  declare longitude: number
 }

+ 28 - 21
models/Core/BankAccount.ts

@@ -1,35 +1,42 @@
-import {Str, Bool, Model, Uid, Attr} from 'pinia-orm'
-
-export class BankAccount extends Model {
+import ApiModel from "~/models/ApiModel";
+import {Bool, Str, Uid, Attr} from "pinia-orm/dist/decorators";
+import {Organization} from "~/models/Organization/Organization";
+
+/**
+ * AP2i Model : BankAccount
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Core/BankAccount.php
+ */
+export class BankAccount extends ApiModel {
   static entity = 'bank_accounts'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
-  @Str(null, { nullable: true })
-  bankName!: string|null
+  @Str(null)
+  declare bankName: string|null
 
-  @Str(null, { nullable: true })
-  bic!: string|null
+  @Str(null)
+  declare bic: string|null
 
-  @Str(null, { nullable: true })
-  bicInvalid!: string|null
+  @Str(null)
+  declare bicInvalid: string|null
 
-  @Str(null, { nullable: true })
-  iban!: string|null
+  @Str(null)
+  declare iban: string|null
 
-  @Str(null, { nullable: true })
-  ibanInvalid!: string|null
+  @Str(null)
+  declare ibanInvalid: string|null
 
-  @Str(null, { nullable: true })
-  debitAddress!: string|null
+  @Str(null)
+  declare debitAddress: string|null
 
-  @Str(null, { nullable: true })
-  holder!: string|null
+  @Str(null)
+  declare holder: string|null
 
-  @Bool(false, { nullable: false })
-  principal!: boolean
+  @Bool(false)
+  declare principal: boolean
 
   @Attr([])
-  organization!: []
+  declare organization: []
 }

+ 29 - 23
models/Core/ContactPoint.ts

@@ -1,38 +1,44 @@
-import {Str, Model, Uid, Attr} from 'pinia-orm'
-
-export class ContactPoint extends Model {
+import ApiModel from "~/models/ApiModel";
+import {Str, Uid, Attr} from "pinia-orm/dist/decorators";
+
+/**
+ * AP2i Model : ContactPoint
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Core/ContactPoint.php
+ */
+export class ContactPoint extends ApiModel {
   static entity = 'contact_points'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
-  @Str('PRINCIPAL', { nullable: false })
-  contactType!: string
+  @Str('PRINCIPAL')
+  declare contactType: string
 
-  @Str(null, { nullable: true })
-  email!: string|null
+  @Str(null)
+  declare email: string|null
 
-  @Str(null, { nullable: true })
-  emailInvalid!: string|null
+  @Str(null)
+  declare emailInvalid: string|null
 
-  @Str(null, { nullable: true })
-  telphone!: string|null
+  @Str(null)
+  declare telphone: string|null
 
-  @Str(null, { nullable: true })
-  telphoneInvalid!: string|null
+  @Str(null)
+  declare telphoneInvalid: string|null
 
-  @Str(null, { nullable: true })
-  mobilPhone!: string|null
+  @Str(null)
+  declare mobilPhone: string|null
 
-  @Str(null, { nullable: true })
-  mobilPhoneInvalid!: string|null
+  @Str(null)
+  declare mobilPhoneInvalid: string|null
 
-  @Str(null, { nullable: true })
-  faxNumber!: string|null
+  @Str(null)
+  declare faxNumber: string|null
 
-  @Str(null, { nullable: true })
-  faxNumberInvalid!: string|null
+  @Str(null)
+  declare faxNumberInvalid: string|null
 
   @Attr([])
-  organization!: []
+  declare organization: []
 }

+ 10 - 4
models/Core/Country.ts

@@ -1,11 +1,17 @@
-import {Str, Model, Uid} from 'pinia-orm'
+import ApiModel from "~/models/ApiModel";
+import {Str, Uid} from "pinia-orm/dist/decorators";
 
-export class Country extends Model {
+/**
+ * AP2i Model : Country
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Core/Country.php
+ */
+export class Country extends ApiModel {
   static entity = 'countries'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
   @Str('')
-  name!: string
+  declare name: string
 }

+ 18 - 12
models/Core/File.ts

@@ -1,29 +1,35 @@
-import {Str, Model, Uid, Num} from 'pinia-orm'
-
-export class File extends Model {
+import ApiModel from "~/models/ApiModel";
+import {Num, Str, Uid} from "pinia-orm/dist/decorators";
+
+/**
+ * AP2i Model : File
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Core/File.php
+ */
+export class File extends ApiModel {
   static entity = 'files'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
   @Str('')
-  name!: string
+  declare name: string
 
   @Str('')
-  imgFieldName!: string
+  declare imgFieldName: string
 
   @Str('')
-  visibility!: string
+  declare visibility: string
 
   @Str('')
-  config!: string
+  declare config: string
 
   @Str('')
-  folder!: string
+  declare folder: string
 
-  @Num(null, { nullable: true })
-  ownerId!: number
+  @Num(null)
+  declare ownerId: number
 
   @Str('')
-  status!: 'PENDING' | 'READY' | 'ERROR'
+  declare status: 'PENDING' | 'READY' | 'ERROR'
 }

+ 16 - 10
models/Core/Notification.ts

@@ -1,24 +1,30 @@
-import {Attr, Str, Model, HasOne, Uid} from 'pinia-orm'
 import {NotificationMessage} from "~/models/Core/NotificationMessage";
+import {HasOne, Str, Uid, Attr} from "pinia-orm/dist/decorators";
+import ApiModel from "~/models/ApiModel";
 
-export class Notification extends Model {
+/**
+ * AP2i Model : Notification
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Core/Notification.php
+ */
+export class Notification extends ApiModel {
   static entity = 'notifications'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
   @Str('')
-  name!: string
+  declare name: string
 
   @HasOne(() => NotificationMessage, 'id')
-  message!: NotificationMessage | null
+  declare message: NotificationMessage | null
 
-  @Str(null, { nullable: true })
-  type!: string|null
+  @Str(null)
+  declare type: string|null
 
-  @Str(null, { nullable: true })
-  link!: string|null
+  @Str(null)
+  declare link: string|null
 
   @Attr({})
-  notificationUsers!: Array<string>
+  declare notificationUsers: Array<string>
 }

+ 13 - 9
models/Core/NotificationMessage.ts

@@ -1,17 +1,21 @@
-import {Str, Model, Uid} from 'pinia-orm'
+import ApiModel from "~/models/ApiModel";
+import {Str, Uid} from "pinia-orm/dist/decorators";
 
-export class NotificationMessage extends Model {
+/**
+ * // TODO: qu'est-ce que c'est?
+ */
+export class NotificationMessage extends ApiModel {
   static entity = 'notification_messages'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
-  @Str(null, { nullable: true })
-  about!: string|null
+  @Str(null)
+  declare about: string|null
 
-  @Str(null, { nullable: true })
-  action!: string|null
+  @Str(null)
+  declare action: string|null
 
-  @Str(null, { nullable: true })
-  fileName!: string|null
+  @Str(null)
+  declare fileName: string|null
 }

+ 15 - 9
models/Core/NotificationUsers.ts

@@ -1,17 +1,23 @@
-import { Str, Model, Bool, Uid } from 'pinia-orm'
+import ApiModel from "~/models/ApiModel";
+import {Bool, Str, Uid} from "pinia-orm/dist/decorators";
 
-export class NotificationUsers extends Model {
+/**
+ * AP2i Model : NotificationUser
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Core/NotificationUser.php
+ */
+export class NotificationUsers extends ApiModel {
   static entity = 'notification_users'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
-  @Str(null, { nullable: true })
-  notification!: string|null
+  @Str(null)
+  declare notification: string|null
 
-  @Str(null, { nullable: true })
-  access!: string|null
+  @Str(null)
+  declare access: string|null
 
-  @Bool(false, { nullable: false })
-  isRead!: boolean
+  @Bool(false)
+  declare isRead: boolean
 }

+ 12 - 6
models/Education/Cycle.ts

@@ -1,14 +1,20 @@
-import {Str, Model, Uid, Num} from 'pinia-orm'
+import ApiModel from "~/models/ApiModel";
+import {Num, Str, Uid} from "pinia-orm/dist/decorators";
 
-export class Cycle extends Model {
+/**
+ * AP2i Model: Cycle
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Education/Cycle.php
+ */
+export class Cycle extends ApiModel {
   static entity = 'cycles'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
-  @Str(null, { nullable: true })
-  label!: string|null
+  @Str(null)
+  declare label: string|null
 
   @Num(0)
-  order!: number
+  declare order: number
 }

+ 11 - 5
models/Education/EducationTiming.ts

@@ -1,11 +1,17 @@
-import {Num, Model, Uid} from 'pinia-orm'
+import ApiModel from "~/models/ApiModel";
+import {Num, Uid} from "pinia-orm/dist/decorators";
 
-export class EducationTiming extends Model {
+/**
+ * AP2i Model : EducationTiming
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Education/EducationTiming.php
+ */
+export class EducationTiming extends ApiModel {
   static entity = 'education_timings'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
-  @Num(null, { nullable: true })
-  timing!: number
+  @Num(null)
+  declare timing: number
 }

+ 16 - 10
models/Export/LicenceCmfOrganizationER.ts

@@ -1,17 +1,23 @@
-import {Bool, Model, Num, Str, Uid} from "pinia-orm";
+import {Bool, Num, Str, Uid} from "pinia-orm/dist/decorators";
+import ApiResource from "~/models/ApiResource";
 
-export class LicenceCmfOrganizationER extends Model {
-  static entity = 'licence_cmf_'
+/**
+ * Ap2i ApiResource : LicenceCmfOrganizationER
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/ApiResources/Export/LicenceCmf/LicenceCmfOrganizationER.php
+ */
+export class LicenceCmfOrganizationER extends ApiResource {
+  static entity = ''
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
-  @Str(null, {nullable: true})
-  format!: string | null
+  @Str(null)
+  declare format: string | null
 
-  @Num(0, {nullable: false})
-  requesterId!: number | string | null
+  @Num(0)
+  declare requesterId: number | string | null
 
-  @Bool(false, {nullable: false})
-  async!: boolean
+  @Bool(false)
+  declare async: boolean
 }

+ 11 - 5
models/Network/Network.ts

@@ -1,14 +1,20 @@
-import {Str, Model, Uid, Attr} from 'pinia-orm'
+import ApiModel from "~/models/ApiModel";
+import {Str, Uid, Attr} from "pinia-orm/dist/decorators";
 
-export class Network extends Model {
+/**
+ * AP2i Model : Network
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Network/Network.php
+ */
+export class Network extends ApiModel {
   static entity = 'networks'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
   @Str('')
-  name!: string
+  declare name: string
 
   @Attr(null)
-  networkOrganizationId!: number | null
+  declare networkOrganizationId: number | null
 }

+ 12 - 6
models/Network/NetworkOrganization.ts

@@ -1,18 +1,24 @@
-import {Str, Model, Uid, HasOne} from 'pinia-orm'
 import {Network} from "~/models/Network/Network";
+import ApiModel from "~/models/ApiModel";
+import {HasOne, Str, Uid} from "pinia-orm/dist/decorators";
 
-export class NetworkOrganization extends Model {
+/**
+ * AP2i Model : NetworkOrganization
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Network/NetworkOrganization.php
+ */
+export class NetworkOrganization extends ApiModel {
   static entity = 'network_organizations'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
   @HasOne(() => Network, 'networkOrganizationId')
-  network!: Network | null
+  declare network: Network | null
 
   @Str('')
-  startDate!: string
+  declare startDate: string
 
   @Str('')
-  category!: string
+  declare category: string
 }

+ 47 - 39
models/Organization/Organization.ts

@@ -1,120 +1,128 @@
 import ApiModel from "~/models/ApiModel";
-import {Bool, Str, Attr, Num} from "pinia-orm/dist/decorators";
+import {Bool, Str, Attr, Num, Uid} from "pinia-orm/dist/decorators";
 
+/**
+ * AP2i Model : Organization
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Organization/Organization.php
+ */
 export class Organization extends ApiModel {
   static entity = 'organizations'
 
+  @Uid()
+  declare id: number | string
+
   @Str(null)
-  name!: string|null
+  declare name: string|null
 
   @Str(null)
-  acronym!: string|null
+  declare acronym: string|null
 
   @Str(null)
-  siretNumber!: string|null
+  declare siretNumber: string|null
 
   @Str(null)
-  apeNumber!: string|null
+  declare apeNumber: string|null
 
   @Str(null)
-  waldecNumber!: string|null
+  declare waldecNumber: string|null
 
   @Str(null)
-  identifier!: string|null
+  declare identifier: string|null
 
   @Str(null)
-  ffecApproval!: string|null
+  declare ffecApproval: string|null
 
   @Str(null)
-  description!: string|null
+  declare description: string|null
 
   @Attr([])
-  typeOfPractices!: []
+  declare typeOfPractices: []
 
   @Str(null)
-  otherPractice!: string|null
+  declare otherPractice: string|null
 
   @Str(null)
-  legalStatus!: string|null
+  declare legalStatus: string|null
 
   @Str(null)
-  principalType!: string|null
+  declare principalType: string|null
 
   @Str(null)
-  youngApproval!: string|null
+  declare youngApproval: string|null
 
   @Str(null)
-  trainingApproval!: string|null
+  declare trainingApproval: string|null
 
   @Str(null)
-  otherApproval!: string|null
+  declare otherApproval: string|null
 
   @Str(null)
-  collectiveAgreement!: string|null
+  declare collectiveAgreement: string|null
 
   @Str(null)
-  opca!: string|null
+  declare opca: string|null
 
   @Str(null)
-  icomNumber!: string|null
+  declare icomNumber: string|null
 
   @Str(null)
-  urssafNumber!: string|null
+  declare urssafNumber: string|null
 
   @Str(null)
-  twitter!: string|null
+  declare twitter: string|null
 
   @Str(null)
-  youtube!: string|null
+  declare youtube: string|null
 
   @Str(null)
-  facebook!: string|null
+  declare facebook: string|null
 
   @Str(null)
-  instagram!: string|null
+  declare instagram: string|null
 
   @Bool(true, { notNullable: true })
-  portailVisibility!: boolean
+  declare portailVisibility: boolean
 
   @Str(null)
-  image!: string|null
+  declare image: string|null
 
   @Str(null)
-  creationDate!: string|null
+  declare creationDate: string|null
 
   @Str(null)
-  prefectureName!: string|null
+  declare prefectureName: string|null
 
   @Str(null)
-  prefectureNumber!: string|null
+  declare prefectureNumber: string|null
 
   @Str(null)
-  declarationDate!: string|null
+  declare declarationDate: string|null
 
   @Str(null)
-  tvaNumber!: string|null
+  declare tvaNumber: string|null
 
   @Str(null)
-  schoolCategory!: string|null
+  declare schoolCategory: string|null
 
   @Str(null)
-  typeEstablishment!: string|null
+  declare typeEstablishment: string|null
 
   @Str(null)
-  typeEstablishmentDetail!: string|null
+  declare typeEstablishmentDetail: string|null
 
   @Bool(false, { notNullable: true })
-  isPerformanceContractor!: boolean
+  declare isPerformanceContractor: boolean
 
   @Num(0)
-  budget!: number
+  declare budget: number
 
   @Bool(false, { notNullable: true })
-  isPedagogicIsPrincipalActivity!: boolean
+  declare isPedagogicIsPrincipalActivity: boolean
 
   @Num(0)
-  pedagogicBudget!: number
+  declare pedagogicBudget: number
 
   @Str(null)
-  logo!: string|null
+  declare logo: string|null
 }

+ 12 - 6
models/Organization/OrganizationAddressPostal.ts

@@ -1,15 +1,21 @@
-import {Str, HasOne, Model, Uid} from 'pinia-orm'
 import { AddressPostal } from '~/models/Core/AddressPostal'
+import ApiModel from "~/models/ApiModel";
+import {HasOne, Str, Uid} from "pinia-orm/dist/decorators";
 
-export class OrganizationAddressPostal extends Model {
+/**
+ * AP2i Model : OrganizationAddressPostal
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Organization/OrganizationAddressPostal.php
+ */
+export class OrganizationAddressPostal extends ApiModel {
   static entity = 'organization_address_postals'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
   @HasOne(() => AddressPostal, 'organizationAddressPostalId')
-  addressPostal!: AddressPostal | null
+  declare addressPostal: AddressPostal | null
 
-  @Str('ADDRESS_HEAD_OFFICE', { nullable: false })
-  type!: string
+  @Str('ADDRESS_HEAD_OFFICE', { notNullable: true })
+  declare type: string
 }

+ 12 - 6
models/Organization/OrganizationArticle.ts

@@ -1,17 +1,23 @@
-import {Str, Model, Uid} from 'pinia-orm'
+import ApiModel from "~/models/ApiModel";
+import {Str, Uid} from "pinia-orm/dist/decorators";
 
-export class OrganizationArticle extends Model {
+/**
+ * AP2i Model : OrganizationArticle
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Organization/OrganizationArticle.php
+ */
+export class OrganizationArticle extends ApiModel {
   static entity = 'organization_articles'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
   @Str('')
-  title!: string
+  declare title: string
 
   @Str('')
-  link!: string
+  declare link: string
 
   @Str('')
-  date!: string
+  declare date: string
 }

+ 17 - 11
models/Organization/OrganizationLicence.ts

@@ -1,20 +1,26 @@
-import {Str, Model, Uid} from 'pinia-orm'
+import ApiModel from "~/models/ApiModel";
+import {Str, Uid} from "pinia-orm/dist/decorators";
 
-export class OrganizationLicence extends Model {
+/**
+ * AP2i Model : OrganizationLicence
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Organization/OrganizationLicence.php
+ */
+export class OrganizationLicence extends ApiModel {
   static entity = 'organization_licences'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
-  @Str('', { nullable: false })
-  licensee!: string
+  @Str('')
+  declare licensee: string
 
-  @Str(null, { nullable: true })
-  licenceNumber!: string|null
+  @Str(null)
+  declare licenceNumber: string|null
 
-  @Str(null, { nullable: true })
-  categorie!: string|null
+  @Str(null)
+  declare categorie: string|null
 
-  @Str(null, { nullable: true })
-  validityDate!: string|null
+  @Str(null)
+  declare validityDate: string|null
 }

+ 4 - 3
models/Organization/OrganizationNetwork.ts

@@ -1,8 +1,9 @@
-import {Str, Model, Uid} from 'pinia-orm'
+import ApiModel from "~/models/ApiModel";
+import {Uid} from "pinia-orm/dist/decorators";
 
-export class OrganizationNetwork extends Model {
+export class OrganizationNetwork extends ApiModel {
   static entity = 'organization_networks'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 }

+ 44 - 0
models/Organization/OrganizationProfile.ts

@@ -0,0 +1,44 @@
+import ApiResource from "~/models/ApiResource";
+import {Str, Uid, Attr, Bool, Num} from "pinia-orm/dist/decorators";
+
+/**
+ * ApiResource : OrganizationProfile
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/ApiResources/Profile/OrganizationProfile.php
+ */
+export class OrganizationProfile extends ApiResource {
+    static entity = 'organization_profile'
+
+    @Uid()
+    declare id: number | string | null
+
+    @Str(null)
+    declare name: string
+
+    @Str(null)
+    declare product: string
+
+    @Str(null)
+    declare legalStatus: string
+
+    @Attr([])
+    declare networks: Array<string>
+
+    @Attr([])
+    declare modules: Array<string>
+
+    @Bool(false)
+    declare hasChildren: boolean
+
+    @Attr([])
+    declare parents: Array<number>
+
+    @Bool(false)
+    declare showAdherentList: boolean
+
+    @Num(null)
+    declare currentYear: null
+
+    @Num(null)
+    declare parametersId: null
+}

+ 80 - 74
models/Organization/Parameters.ts

@@ -1,116 +1,122 @@
-import {Str, Model, Uid, Bool, Num, Attr, HasOne} from 'pinia-orm'
-
-export class Parameters extends Model {
+import ApiModel from "~/models/ApiModel";
+import {Bool, Num, Str, Uid, Attr} from "pinia-orm/dist/decorators";
+
+/**
+ * AP2i Model : Parameters
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Organization/Parameters.php
+ */
+export class Parameters extends ApiModel {
   static entity = 'parameters'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
-  @Str(null, { nullable: true })
-  financialDate!: string|null
+  @Str(null)
+  declare financialDate: string|null
 
-  @Str(null, { nullable: true })
-  musicalDate!: string|null
+  @Str(null)
+  declare musicalDate: string|null
 
-  @Str(null, { nullable: true })
-  startCourseDate!: string|null
+  @Str(null)
+  declare startCourseDate: string|null
 
-  @Str(null, { nullable: true })
-  endCourseDate!: string|null
+  @Str(null)
+  declare endCourseDate: string|null
 
-  @Bool(false, { nullable: false })
-  trackingValidation!: boolean
+  @Bool(false, { notNullable: true })
+  declare trackingValidation: boolean
 
-  @Num(20, { nullable: true })
-  average!: number
+  @Num(20)
+  declare average: number
 
-  @Bool(true, { nullable: false })
-  editCriteriaNotationByAdminOnly!: boolean
+  @Bool(true, { notNullable: true })
+  declare editCriteriaNotationByAdminOnly: boolean
 
-  @Str(null, { nullable: true })
-  smsSenderName!: string|null
+  @Str(null)
+  declare smsSenderName: string|null
 
-  @Bool(true, { nullable: false })
-  logoDonorsMove!: boolean
+  @Bool(true, { notNullable: true })
+  declare logoDonorsMove: boolean
 
-  @Str(null, { nullable: true })
-  otherWebsite!: string|null
+  @Str(null)
+  declare otherWebsite: string|null
 
-  @Str(null, { nullable: true })
-  customDomain!: string|null
+  @Str(null)
+  declare customDomain: string|null
 
-  @Bool(false, { nullable: false })
-  desactivateOpentalentSiteWeb!: boolean
+  @Bool(false, { notNullable: true })
+  declare desactivateOpentalentSiteWeb: boolean
 
   @Attr([])
-  publicationDirectors!: []
+  declare publicationDirectors: []
 
-  @Str(null, { nullable: true })
-  bulletinPeriod!: string|null
+  @Str(null)
+  declare bulletinPeriod: string|null
 
-  @Bool(false, { nullable: false })
-  bulletinWithTeacher!: boolean
+  @Bool(false, { notNullable: true })
+  declare bulletinWithTeacher: boolean
 
-  @Bool(false, { nullable: false })
-  bulletinPrintAddress!: boolean
+  @Bool(false, { notNullable: true })
+  declare bulletinPrintAddress: boolean
 
-  @Bool(true, { nullable: false })
-  bulletinSignatureDirector!: boolean
+  @Bool(true, { notNullable: true })
+  declare bulletinSignatureDirector: boolean
 
-  @Bool(true, { nullable: false })
-  bulletinDisplayLevelAcquired!: boolean
+  @Bool(true, { notNullable: true })
+  declare bulletinDisplayLevelAcquired: boolean
 
-  @Bool(false, { nullable: false })
-  bulletinShowEducationWithoutEvaluation!: boolean
+  @Bool(false, { notNullable: true })
+  declare bulletinShowEducationWithoutEvaluation: boolean
 
-  @Bool(false, { nullable: false })
-  bulletinViewTestResults!: boolean
+  @Bool(false, { notNullable: true })
+  declare bulletinViewTestResults: boolean
 
-  @Bool(false, { nullable: false })
-  bulletinShowAbsences!: boolean
+  @Bool(false, { notNullable: true })
+  declare bulletinShowAbsences: boolean
 
-  @Bool(true, { nullable: false })
-  bulletinShowAverages!: boolean
+  @Bool(true, { notNullable: true })
+  declare bulletinShowAverages: boolean
 
-  @Str(null, { nullable: true })
-  bulletinOutput!: string|null
+  @Str(null)
+  declare bulletinOutput: string|null
 
-  @Bool(true, { nullable: false })
-  bulletinEditWithoutEvaluation!: boolean
+  @Bool(true, { notNullable: true })
+  declare bulletinEditWithoutEvaluation: boolean
 
-  @Str('STUDENTS_AND_THEIR_GUARDIANS', { nullable: true })
-  bulletinReceiver!: string|null
+  @Str('STUDENTS_AND_THEIR_GUARDIANS')
+  declare bulletinReceiver: string|null
 
-  @Str(null, { nullable: true })
-  usernameSMS!: string|null
+  @Str(null)
+  declare usernameSMS: string|null
 
-  @Str(null, { nullable: true })
-  passwordSMS!: string|null
+  @Str(null)
+  declare passwordSMS: string|null
 
-  @Bool(true, { nullable: false })
-  showAdherentList!: boolean
+  @Bool(true, { notNullable: true })
+  declare showAdherentList: boolean
 
-  @Bool(false, { nullable: false })
-  studentsAreAdherents!: boolean
+  @Bool(false, { notNullable: true })
+  declare studentsAreAdherents: boolean
 
-  @Str(null, { nullable: true })
-  qrCode!: string|null
+  @Str(null)
+  declare qrCode: string|null
 
-  @Str('Europe/Paris', { nullable: true })
-  timezone!: string|null
+  @Str('Europe/Paris')
+  declare timezone: string|null
 
-  @Str('ANNUAL', { nullable: true })
-  educationPeriodicity!: string|null
+  @Str('ANNUAL')
+  declare educationPeriodicity: string|null
 
-  @Str('BY_EDUCATION', { nullable: true })
-  advancedEducationNotationType!: string|null
+  @Str('BY_EDUCATION')
+  declare advancedEducationNotationType: string|null
 
-  @Bool(false, { nullable: false })
-  sendAttendanceEmail!: boolean
+  @Bool(false, { notNullable: true })
+  declare sendAttendanceEmail: boolean
 
-  @Bool(false, { nullable: false })
-  sendAttendanceSms!: boolean
+  @Bool(false, { notNullable: true })
+  declare sendAttendanceSms: boolean
 
   @Attr([])
-  subdomains!: []
+  declare subdomains: []
 }

+ 13 - 8
models/Organization/Subdomain.ts

@@ -1,15 +1,20 @@
-import {Bool, Model, Str, Uid} from "pinia-orm";
+import ApiModel from "~/models/ApiModel";
+import {Bool, Str, Uid} from "pinia-orm/dist/decorators";
 
-
-export class Subdomain extends Model {
+/**
+ * AP2i Model : Subdomain
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Organization/Subdomain.php
+ */
+export class Subdomain extends ApiModel {
   static entity = 'subdomains'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
-  @Str(null, {nullable: true})
-  subdomain!: string | null
+  @Str(null)
+  declare subdomain: string | null
 
-  @Bool(false, { nullable: false })
-  active!: boolean
+  @Bool(false, { notNullable: true })
+  declare active: boolean
 }

+ 11 - 5
models/Organization/TypeOfPractice.ts

@@ -1,14 +1,20 @@
-import {Str, Model, Uid} from 'pinia-orm'
+import ApiModel from "~/models/ApiModel";
+import {Str, Uid} from "pinia-orm/dist/decorators";
 
-export class TypeOfPractice extends Model {
+/**
+ * AP2i Model : TypeOfPractice
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Organization/TypeOfPractice.php
+ */
+export class TypeOfPractice extends ApiModel {
   static entity = 'type_of_practices'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
   @Str('')
-  name!: string
+  declare name: string
 
   @Str('')
-  category!: string
+  declare category: string
 }

+ 12 - 6
models/Person/Person.ts

@@ -1,14 +1,20 @@
-import {Model, Uid, Str, Attr} from 'pinia-orm'
+import ApiModel from "~/models/ApiModel";
+import {Str, Uid, Attr} from "pinia-orm/dist/decorators";
 
-export class Person extends Model {
+/**
+ * AP2i Model : Person
+ *
+ * @see https://gitlab.2iopenservice.com/opentalent/ap2i/-/blob/develop/src/Entity/Person/Person.php
+ */
+export class Person extends ApiModel {
   static entity = 'people'
 
   @Uid()
-  id!: number | string | null
+  declare id: number | string | null
 
   @Attr(null)
-  accessId!: number | null
+  declare accessId: number | null
 
-  @Str(null, { nullable: true })
-  username!: string|null
+  @Str(null)
+  declare username: string|null
 }

+ 0 - 40
models/_import.ts

@@ -1,40 +0,0 @@
-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
-]

+ 5 - 5
nuxt.config.ts

@@ -1,4 +1,5 @@
 import fs from 'fs';
+import {builtinModules} from 'module';
 
 // https://v3.nuxtjs.org/api/configuration/nuxt.config
 // @ts-ignore
@@ -82,6 +83,7 @@ export default {
     modules: [
         [
             '@pinia/nuxt',
+            '@pinia-orm/nuxt',
             {
                 autoImports: [
                     // automatically imports `usePinia()`
@@ -89,8 +91,9 @@ export default {
                     // automatically imports `usePinia()` as `usePiniaStore()`
                     ['defineStore', 'definePiniaStore'],
                 ],
-            },
+            }
         ],
+        'nuxt-lodash'
     ],
     typescript: {
         strict: true
@@ -98,12 +101,9 @@ export default {
     build: {
         transpile: ['vuetify'],
     },
-    server: {
-        host: "0.0.0.0"
-    },
     vite: {
         define: {
-            'process.env.DEBUG': false,
+            'process.env.DEBUG': process.env.DEBUG,
         },
         //@ts-ignore
         server : {

+ 7 - 1
package.json

@@ -2,6 +2,9 @@
   "private": true,
   "version": "2.3.0",
   "type": "module",
+  "engines": {
+    "node": ">=18.0.0"
+  },
   "scripts": {
     "dev": "nuxt dev",
     "dev:local": "yarn dev --dotenv .env.local",
@@ -28,6 +31,7 @@
     "@types/event-source-polyfill": "^1.0.0",
     "@types/jest": "^29.0.3",
     "@types/lodash": "^4.14.185",
+    "@types/uuid": "^8.3.4",
     "@typescript-eslint/eslint-plugin": "^5.39.0",
     "@typescript-eslint/parser": "^5.39.0",
     "@vue/eslint-config-standard": "^8.0.1",
@@ -57,8 +61,10 @@
     "js-yaml": "^4.1.0",
     "libphonenumber-js": "^1.10.13",
     "nuxt": "^3.0.0-rc.10",
-    "pinia-orm": "^1.0.0-rc.5",
+    "nuxt-lodash": "^2.3.0",
+    "pinia-orm": "1.0.3",
     "sass": "^1.54.5",
+    "uuid": "^9.0.0",
     "vuetify": "^3.0.0-beta.11",
     "yaml-import": "^2.0.0"
   }

+ 18 - 0
pages/form.vue

@@ -0,0 +1,18 @@
+<template>
+  <main>
+    <p>Test : {{ organization.name }}</p>
+
+    <nuxt-link to="/">Goto main</nuxt-link>
+  </main>
+</template>
+
+<script setup lang="ts">
+import {useEntityManager} from "~/composables/data/useEntityManager";
+import {Organization} from "~/models/Organization/Organization";
+
+const em = useEntityManager()
+
+const organization = ref(null)
+organization.value = await em.fetch(Organization, 32366)
+
+</script>

+ 1 - 7
pages/index.vue

@@ -1,16 +1,10 @@
 <template>
   <main>
-    Test : {{ organization }}
+    <nuxt-link to="/organization">Goto organizations</nuxt-link>
   </main>
 </template>
 
 <script setup lang="ts">
-  import {useEntityManager} from "~/composables/data/useEntityManager";
-  import {Organization} from "~/models/Organization/Organization";
-
-  const em = useEntityManager()
-
-  const organization = await em.fetch(Organization, 498)
 
 </script>
 

+ 9 - 0
pages/organization.vue

@@ -0,0 +1,9 @@
+<template>
+  <main>
+    <h1>Organization</h1>
+    <NuxtPage/>
+  </main>
+</template>
+
+<script setup lang="ts">
+</script>

+ 0 - 0
pages/organization/id_.vue


+ 63 - 0
pages/organization/index.vue

@@ -0,0 +1,63 @@
+<template>
+  <main>
+    <p>Nom : {{ country }}</p>
+
+    <div>
+      <button @click="fetchPrevious">Previous</button>
+      <button @click="fetchNext">Next</button>
+    </div>
+    <nuxt-link to="/form">Edit</nuxt-link>
+  </main>
+</template>
+
+<script setup lang="ts">
+import {useEntityManager} from "~/composables/data/useEntityManager";
+import {Ref} from "@vue/reactivity";
+import {Country} from "~/models/Core/Country";
+import ApiResource from "~/models/ApiResource";
+
+const id: Ref<number> = ref(2)
+const em = useEntityManager()
+const country: Ref<ApiResource | null> = ref(null)
+
+const fetchCountry = async function () {
+  console.log('fetch ', id.value)
+  country.value = await em.fetch(Country, id.value)
+}
+await fetchCountry()
+
+const fetchNext = () => {
+  id.value += 1
+  console.log('next')
+  fetchCountry()
+}
+
+const fetchPrevious = async function () {
+  id.value -= 1
+  console.log('previous')
+  await fetchCountry()
+}
+
+
+</script>
+
+<style>
+a {
+  color: blue;
+}
+a:hover {
+  text-decoration: underline;
+}
+
+button {
+  border: grey solid 1px;
+  padding: 5px;
+  margin: 5px;
+}
+button:hover {
+  text-decoration: underline;
+}
+button:focus {
+  background-color: lightgrey;
+}
+</style>

+ 1 - 2
plugins/init.server.ts

@@ -3,11 +3,10 @@ import {useProfileAccessStore} from "~/store/profile/access";
 import {useEntityManager} from "~/composables/data/useEntityManager";
 
 export default defineNuxtPlugin(async ({ssrContext}) => {
-    const profileAccessStore = useProfileAccessStore()
-
     const bearer = useCookie('BEARER')
     const accessId = useCookie('AccessId')
 
+    const profileAccessStore = useProfileAccessStore()
     profileAccessStore.$patch({
         bearer: bearer.value,
         id: parseInt(accessId.value)

+ 8 - 8
services/data/apiRequestService.ts

@@ -20,11 +20,11 @@ class ApiRequestService {
      * @param url
      * @param query
      */
-    public get(
+    public async get(
         url: string,
         query: AssociativeArray | null = null
     ) {
-        return this.request(HTTP_METHOD.GET, url, null, null, query)
+        return await this.request(HTTP_METHOD.GET, url, null, null, query)
     }
 
     /**
@@ -35,13 +35,13 @@ class ApiRequestService {
      * @param params
      * @param query
      */
-    public post(
+    public async post(
         url: string,
         body: string | null = null,
         params: AssociativeArray | null = null,
         query: AssociativeArray | null = null
     ) {
-        return this.request(HTTP_METHOD.POST, url, body, params, query)
+        return await this.request(HTTP_METHOD.POST, url, body, params, query)
     }
 
     /**
@@ -52,13 +52,13 @@ class ApiRequestService {
      * @param params
      * @param query
      */
-    public put(
+    public async put(
         url: string,
         body: string | null = null,
         params: AssociativeArray | null = null,
         query: AssociativeArray | null = null
     ) {
-        return this.request(HTTP_METHOD.PUT, url, body, params, query)
+        return await this.request(HTTP_METHOD.PUT, url, body, params, query)
     }
 
     /**
@@ -67,11 +67,11 @@ class ApiRequestService {
      * @param url
      * @param query
      */
-    public delete(
+    public async delete(
         url: string,
         query: AssociativeArray | null = null
     ) {
-        return this.request(HTTP_METHOD.GET, url, null, null, query)
+        return await this.request(HTTP_METHOD.GET, url, null, null, query)
     }
 
     /**

+ 125 - 42
services/data/entityManager.ts

@@ -1,47 +1,54 @@
 import ApiRequestService from "./apiRequestService";
 import {AssociativeArray} from "./data";
-import {useRepo} from "pinia-orm";
+import {Repository, useRepo} from "pinia-orm";
 import UrlBuilder from "~/services/utils/urlBuilder";
 import ModelNormalizer from "./serializer/normalizer/modelNormalizer";
 import HydraDenormalizer from "./serializer/denormalizer/hydraDenormalizer";
 import ApiModel from "~/models/ApiModel";
 import {useProfileAccessStore} from "~/store/profile/access";
+import ApiResource from "~/models/ApiResource";
+import {MyProfile} from "~/models/Access/MyProfile";
+import { v4 as uuid4 } from 'uuid';
 
 /**
  * Entity manager: make operations on the models defined with the Pinia-Orm library
  *
  * @see https://pinia-orm.codedredd.de/
  */
-class EntityManager  {
+class EntityManager {
+    private initialState: Map<string, Map<number, ApiResource>>;
     private apiRequestService: ApiRequestService;
 
     public constructor(apiRequestService: ApiRequestService) {
         this.apiRequestService = apiRequestService
+        this.initialState = new Map<string, Map<number, ApiResource>>()
     }
 
-    public getRepository(model: typeof ApiModel) {
+    /**
+     * Return the repository for the model
+     *
+     * @param model
+     */
+    public getRepository(model: typeof ApiResource): Repository<ApiResource> {
         return useRepo(model)
     }
 
-    private static getEntityModel(entity: ApiModel): typeof ApiModel{
-        return Object.getPrototypeOf(entity)
-    }
-
     /**
-     * Fetch one entity by its id, save it to the store and returns it
+     * Fetch one Entity / ApiResource by its id, save it to the store and returns it
      *
      * @param model  Model of the object to fetch
      * @param id   Id of the object to fetch
      * @param forceRefresh  Force a new get request to the api ;
      *                      current object in store will be overwritten if it exists
      */
-    public async fetch(model: typeof ApiModel, id: number, forceRefresh: boolean = false) {
+    public async fetch(model: typeof ApiResource, id: number, forceRefresh: boolean = false): Promise<ApiResource> {
 
         const repository = this.getRepository(model)
 
         // If the entity is already in the store and forceRefresh is false, return the object in store
         if (!forceRefresh) {
             const item = repository.find(id)
+            console.log(model, id, ' => item : ', item)
             if (item && typeof item !== 'undefined') {
                 return item
             }
@@ -53,51 +60,62 @@ class EntityManager  {
         const response = await this.apiRequestService.get(url)
 
         // deserialize the response
-        const entity = await HydraDenormalizer.denormalize(response)
-        entity.persisted = true
-
-        entity.initialState = structuredClone(entity)
-
-        // Save data into the store
-        repository.save(entity)
+        const attributes = HydraDenormalizer.denormalize(response).data as object
 
-        return entity
+        return this.new(model, attributes)
     }
 
-    public findBy(model: typeof ApiModel, query: AssociativeArray) {
+    public findBy(model: typeof ApiResource, query: AssociativeArray) {
         // TODO: implement
     }
 
-    public fetchAll(model: typeof ApiModel) {
+    public fetchAll(model: typeof ApiResource) {
         // TODO: implement
     }
 
+    /**
+     * Persist the entity as it is in the store into the data source via the API
+     *
+     * @param model
+     * @param entity
+     */
     public async persist(model: typeof ApiModel, entity: ApiModel) {
-        const data = ModelNormalizer.normalize(entity)
+
+        const repository = this.getRepository(model)
+
         let url = UrlBuilder.join('api', model.entity)
-        let response = null
+        let response
+
+        const data = ModelNormalizer.normalize(entity)
 
-        if (entity.persisted) {
+        if (!entity.isNew()) {
             url = UrlBuilder.join(url, String(entity.id))
             response = await this.apiRequestService.put(url, data)
         } else {
             response = await this.apiRequestService.post(url, data)
         }
 
-        const fetchedEntity = await HydraDenormalizer.denormalize(response)
-        fetchedEntity.persisted = true
+        const attributes = await HydraDenormalizer.denormalize(response)
+        const returnedEntity = this.new(model, attributes)
+
+        this.storeInitialState(returnedEntity)
 
         // Save data into the store
-        const repository = this.getRepository(model)
-        repository.save(fetchedEntity)
+        repository.save(returnedEntity)
 
         if (['accesses', 'organizations', 'parameters', 'subdomains'].includes(model.entity)) {
             await this.refreshProfile()
         }
 
-        return fetchedEntity
+        return returnedEntity
     }
 
+    /**
+     * Delete the entity from the datasource via the API
+     *
+     * @param model
+     * @param id
+     */
     public async delete(model: typeof ApiModel, id: number) {
         const repository = this.getRepository(model)
         const entity = repository.find(id) as ApiModel
@@ -107,7 +125,7 @@ class EntityManager  {
         }
 
         // If object has been persisted to the datasource, send a delete request
-        if (entity.persisted) {
+        if (!entity.isNew()) {
             const url = UrlBuilder.join('api', model.entity, String(id))
             await this.apiRequestService.delete(url)
         }
@@ -116,39 +134,104 @@ class EntityManager  {
         repository.destroy(id)
     }
 
-    public new(model: typeof ApiModel) {
+    /**
+     * Create a new instance of the given model
+     *
+     * @param model
+     * @param properties
+     */
+    public new(model: typeof ApiResource, properties: object = {}) {
         const repository = this.getRepository(model)
 
-        const entity = repository.make()
-        entity.persisted = false
+        const entity = repository.make(properties)
 
-        // Save data into the store
+        if (!entity.id) {
+            // Object has no id yet, we give him a temporary one
+            entity.id = 'tmp' + uuid4()
+        }
         repository.save(entity)
 
+        this.storeInitialState(entity)
+
         return entity
     }
 
-    public reset(entity: ApiModel) {
-        if (entity.initialState === null) {
-            console.log('object has no initial state - abort')
+    /**
+     * Reset the entity to its initial state (i.e. the state it had when it was fetched from the API)
+     *
+     * @param entity
+     */
+    public reset(entity: ApiResource) {
+        const state = this.getInitialStateOf(entity)
+        if (state === null) {
+            console.log('no initial state recorded for this object - abort', entity)
             return
         }
 
-        entity = entity.initialState as ApiModel
-        entity.initialState = structuredClone(entity)
-
-        const repository = this.getRepository(EntityManager.getEntityModel(entity))
-        repository.save(entity)
+        const repository = this.getRepository(EntityManager.getModelOf(entity))
+        repository.save(state)
     }
 
+    /**
+     * Re-fetch the user profile and update the store
+     */
     public async refreshProfile() {
         const response = await this.apiRequestService.get('api/my_profile')
 
         // deserialize the response
-        const profile = await HydraDenormalizer.denormalize(response)
+        const attributes = await HydraDenormalizer.denormalize(response).data
+
+        const profile = this.new(MyProfile, attributes)
 
         const profileAccessStore = useProfileAccessStore()
-        profileAccessStore.setProfile(profile.data)
+        profileAccessStore.setProfile(profile)
+    }
+
+    /**
+     * Delete all records in the repository of the model
+     *
+     * @param model
+     */
+    public async flush(model: typeof ApiModel) {
+        const repository = this.getRepository(model)
+        repository.flush()
+    }
+
+    private storeInitialState(entity: ApiResource) {
+        const model = EntityManager.getModelOf(entity)
+
+        if (!this.initialState.has(model.entity)) {
+            this.initialState.set(model.entity, new Map())
+        }
+
+        // @ts-ignore
+        this.initialState.get(model.entity).set(entity.id, useCloneDeep(entity))
+
+        // TODO: voir si structuredClone est compatible avec les navigateurs supportés, et si ça vaut le coup
+        //       de l'utiliser à la place du clonedeep de lodash
+        //        >> https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
+    }
+
+    private getInitialStateOf(entity: ApiResource): ApiResource | null {
+        const model = EntityManager.getModelOf(entity)
+
+        // @ts-ignore
+        if (!this.initialState.has(model.entity) || !this.initialState.get(model.entity).has(entity.id)) {
+            return null
+        }
+
+        // @ts-ignore
+        return this.initialState.get(model.entity).get(entity.id)
+    }
+
+    /**
+     * Return the model (=class) of the given entity
+     *
+     * @param entity
+     * @private
+     */
+    private static getModelOf(entity: ApiResource): typeof ApiResource {
+        return Object.getPrototypeOf(entity)
     }
 }
 

+ 18 - 24
store/profile/access.ts

@@ -3,8 +3,8 @@ import {$roleUtils} from "~/services/rights/roleUtils";
 import {accessState, baseAccessState, baseOrganizationState, OrignalAccessState} from "~/types/interfaces";
 import {useProfileOrganizationStore} from "~/store/profile/organization";
 
-import {repositoryHelper} from "~/services/store/repository";
 import {MyProfile} from "~/models/Access/MyProfile";
+import {useRepo} from "pinia-orm";
 
 export const useProfileAccessStore = defineStore('profileAccess', {
   state: (): accessState => {
@@ -44,7 +44,8 @@ export const useProfileAccessStore = defineStore('profileAccess', {
   },
   actions: {
     setProfile(profile: any) {
-      const roles_to_array: Array<string> = Object.values(profile.roles)
+      const roles: Array<string> = Object.values(profile.roles)
+
       this.name = profile.name
       this.givenName = profile.givenName
       this.gender = profile.gender
@@ -52,33 +53,34 @@ export const useProfileAccessStore = defineStore('profileAccess', {
       this.activityYear = profile.activityYear
       this.historical = profile.historical
       this.isAdminAccess = profile.isAdminAccess
-      this.isAdmin = $roleUtils.isA('ADMIN', roles_to_array)
-      this.isAdministratifManager = $roleUtils.isA('ADMINISTRATIF_MANAGER', roles_to_array)
-      this.isPedagogicManager = $roleUtils.isA('PEDAGOGICS_MANAGER', roles_to_array)
-      this.isFinancialManager = $roleUtils.isA('FINANCIAL_MANAGER', roles_to_array)
-      this.isCaMember = $roleUtils.isA('CA', roles_to_array)
-      this.isStudent = $roleUtils.isA('STUDENT', roles_to_array)
-      this.isTeacher = $roleUtils.isA('TEACHER', roles_to_array)
-      this.isMember = $roleUtils.isA('MEMBER', roles_to_array)
-      this.isOther = $roleUtils.isA('OTHER', roles_to_array)
+
+      this.isAdmin = $roleUtils.isA('ADMIN', roles)
+      this.isAdministratifManager = $roleUtils.isA('ADMINISTRATIF_MANAGER', roles)
+      this.isPedagogicManager = $roleUtils.isA('PEDAGOGICS_MANAGER', roles)
+      this.isFinancialManager = $roleUtils.isA('FINANCIAL_MANAGER', roles)
+      this.isCaMember = $roleUtils.isA('CA', roles)
+      this.isStudent = $roleUtils.isA('STUDENT', roles)
+      this.isTeacher = $roleUtils.isA('TEACHER', roles)
+      this.isMember = $roleUtils.isA('MEMBER', roles)
+      this.isOther = $roleUtils.isA('OTHER', roles)
       this.isGuardian = profile.isGuardian
       this.isPayor = profile.isPayor
-      this.roles = $roleUtils.filterFunctionRoles(roles_to_array)
+      this.roles = $roleUtils.filterFunctionRoles(roles)
 
-      // // Time to add the original Access (switch User case)
+      // Time to add the original Access (switch User case)
       this.originalAccess = profile.originalAccess
 
       // Time to set Multi Accesses
       this.setMultiAccesses(profile.multiAccesses)
 
-      //Time to set Family Accesses
+      // Time to set Family Accesses
       this.setFamilyAccesses(profile.familyAccesses)
 
-      // Time to set Oganization Profile
+      // Time to set Organization Profile
       const organizationProfileStore = useProfileOrganizationStore()
       organizationProfileStore.setProfile(profile.organization)
 
-      this.createNewMyProfilePiniaOrmInstance(profile)
+      useRepo(MyProfile).save(profile)
     },
     refreshProfile(profile: any) {
       this.name = profile.name
@@ -130,13 +132,5 @@ export const useProfileAccessStore = defineStore('profileAccess', {
         this.setOriginalAccess(originalAccess)
       }
     },
-
-    /**
-     * Créer une nouvelle instance MyProfile dans Vuex ORM
-     * @param access
-     */
-    createNewMyProfilePiniaOrmInstance(access: any): void {
-      repositoryHelper.persist(MyProfile, access)
-    }
   }
 })