Browse Source

rewrite data services (ongoing)

Olivier Massot 3 years ago
parent
commit
d4019bd3db
54 changed files with 732 additions and 598 deletions
  1. 29 0
      .eslintrc.cjs
  2. 0 15
      .eslintrc.js
  3. 4 0
      .prettierrc
  4. 63 0
      composables/data/useAp2iFetch.ts
  5. BIN
      logo.png
  6. 2 4
      models/Access/Access.ts
  7. 11 0
      models/ApiModel.ts
  8. 15 1
      package.json
  9. 0 230
      services/connection/connection.ts
  10. 0 63
      services/connection/urlOptionsBuilder.ts
  11. 98 0
      services/data/apiRequestService.ts
  12. 47 0
      services/data/connector/ohMyFetchConnector.ts
  13. 26 0
      services/data/data.d.ts
  14. 96 0
      services/data/entityManager.ts
  15. 15 0
      services/data/enumManager.ts
  16. 15 0
      services/data/fileManager.ts
  17. 15 0
      services/data/imageManager.ts
  18. 0 0
      services/data/serializer/denormalizer/_import.ts
  19. 1 2
      services/data/serializer/denormalizer/baseDenormalizer.ts
  20. 12 12
      services/data/serializer/denormalizer/hydraDenormalizer.ts
  21. 0 0
      services/data/serializer/denormalizer/yaml.ts
  22. 0 0
      services/data/serializer/normalizer/_import.ts
  23. 1 1
      services/data/serializer/normalizer/baseNormalizer.ts
  24. 0 0
      services/data/serializer/normalizer/default.ts
  25. 0 0
      services/data/serializer/normalizer/file.ts
  26. 22 0
      services/data/serializer/normalizer/modelNormalizer.ts
  27. 23 0
      services/data/serializer/serializer.ts
  28. 0 0
      services/data_old/__mocks__/__dataProvider.ts
  29. 0 0
      services/data_old/baseDataManager.ts
  30. 0 0
      services/data_old/dataDeleter.ts
  31. 0 0
      services/data_old/dataPersister.ts
  32. 0 0
      services/data_old/dataProvider.ts
  33. 0 0
      services/data_old/hookable.ts
  34. 0 0
      services/data_old/hooks/baseHook.ts
  35. 0 0
      services/data_old/hooks/hookDeleter/_import.ts
  36. 0 0
      services/data_old/hooks/hookDeleter/hookDeleterExample.ts
  37. 0 0
      services/data_old/hooks/hookPersister/_import.ts
  38. 0 0
      services/data_old/hooks/hookPersister/hookPersisterExample.ts
  39. 0 0
      services/data_old/hooks/hookPersister/postPersistProfileRefresh.ts
  40. 0 0
      services/data_old/hooks/hookProvider/_import.ts
  41. 0 0
      services/data_old/hooks/hookProvider/hookProviderExample.ts
  42. 0 0
      services/data_old/processor/_import.ts
  43. 0 0
      services/data_old/processor/baseProcessor.ts
  44. 0 0
      services/data_old/processor/defaultProcessor.ts
  45. 0 0
      services/data_old/processor/enumProcessor.ts
  46. 0 0
      services/data_old/processor/fileProcessor.ts
  47. 0 0
      services/data_old/processor/imageProcessor.ts
  48. 0 0
      services/data_old/processor/modelProcessor.ts
  49. 0 76
      services/serializer/normalizer/model.ts
  50. 0 24
      services/serializer/serializer.ts
  51. 14 15
      services/utils/datesUtils.ts
  52. 56 3
      services/utils/urlBuilder.ts
  53. 3 0
      tsconfig.json
  54. 164 152
      types/interfaces.d.ts

+ 29 - 0
.eslintrc.cjs

@@ -0,0 +1,29 @@
+module.exports = {
+  root: true,
+  env: {
+    browser: true,
+    node: true
+  },
+  parser: "vue-eslint-parser",
+  parserOptions: {
+    "ecmaVersion": 2020,
+    "parser": "@typescript-eslint/parser",
+    "sourceType": "module"
+  },
+  extends: [
+    '@nuxtjs/eslint-config-typescript',
+    'plugin:nuxt/recommended',
+    "eslint:recommended",
+    "plugin:@typescript-eslint/recommended",
+    'plugin:vue/vue3-recommended',
+    'plugin:prettier/recommended',
+
+  ],
+  plugins: [
+    "vue",
+    "@typescript-eslint"
+  ],
+  // add your custom rules here
+  rules: {
+  }
+}

+ 0 - 15
.eslintrc.js

@@ -1,15 +0,0 @@
-module.exports = {
-  root: true,
-  env: {
-    browser: true,
-    node: true
-  },
-  extends: [
-    '@nuxtjs/eslint-config-typescript',
-    'plugin:nuxt/recommended'
-  ],
-  plugins: [
-  ],
-  // add your custom rules here
-  rules: {}
-}

+ 4 - 0
.prettierrc

@@ -0,0 +1,4 @@
+{
+  "semi": false,
+  "singleQuote": true
+}

+ 63 - 0
composables/data/useAp2iFetch.ts

@@ -0,0 +1,63 @@
+import {useProfileAccessStore} from "~/store/profile/access";
+import {FetchContext, FetchOptions} from "ohmyfetch";
+import Page from "~/services/store/page";
+import {TYPE_ALERT} from "~/types/enums";
+
+/**
+ * Utilise la fonction `create` de ohmyfetch pour générer un fetcher dédié à l'interrogation de Ap2i
+ *
+ * @see https://github.com/unjs/ohmyfetch/blob/main/README.md#%EF%B8%8F-create-fetch-with-default-options
+ */
+export const useAp2iFetch = () => {
+    const runtimeConfig = useRuntimeConfig()
+
+    /**
+     * 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 ?. params.noXaccessId) {
+            return
+        }
+
+        request = request as Request
+
+        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))
+        }
+    }
+
+    /**
+     * Gère les erreurs retournées par l'api
+     *
+     * @param request
+     * @param response
+     * @param error
+     */
+    const onResponseError = async function ({ request, response, error }: FetchContext) {
+        if (response && response.status === 401) {
+            navigateTo('/login')
+        }
+        if (response && response.status === 403) {
+            new Page().addAlerts(TYPE_ALERT.ALERT, ['forbidden'])
+        }
+
+        if (response && response.status === 500) {
+            new Page().addAlerts(TYPE_ALERT.ALERT, [error ? error.message : response.statusText])
+        }
+    }
+
+    const config : FetchOptions = {
+        baseURL: runtimeConfig.baseUrl ?? runtimeConfig.public.baseUrl,
+        onRequest,
+        onResponseError
+    }
+    return $fetch.create(config)
+}

BIN
logo.png


+ 2 - 4
models/Access/Access.ts

@@ -1,13 +1,11 @@
 import {Attr, Num, Model, Uid, HasOne} from 'pinia-orm'
 import { Historical } from '~/types/interfaces'
 import {Person} from "~/models/Person/Person";
+import ApiModel from "~/models/ApiModel";
 
-export class Access extends Model {
+export class Access extends ApiModel {
   static entity = 'accesses'
 
-  @Uid()
-  id!: number | string | null
-
   @HasOne(() => Person, 'accessId')
   person!: Person | null
 

+ 11 - 0
models/ApiModel.ts

@@ -0,0 +1,11 @@
+import { Model } from "pinia-orm";
+import { Uid } from "pinia-orm/dist/nanoid";
+
+export class ApiModel extends Model {
+    @Uid()
+    id!: number | string
+
+    isNew: boolean = false
+}
+
+export default ApiModel

+ 15 - 1
package.json

@@ -1,5 +1,7 @@
 {
   "private": true,
+  "version": "2.3.0",
+  "type": "module",
   "scripts": {
     "dev": "nuxt dev --hostname '0.0.0.0' --port 3003",
     "dev:local": "yarn dev --dotenv .env.local",
@@ -14,19 +16,30 @@
     "start:preprod": "yarn start --dotenv .env.preprod",
     "start:prod": "yarn start --dotenv .env.prod",
     "deploy": "git pull && yarn install && yarn build && pm2 start app",
-    "infos": "npx nuxi info"
+    "infos": "npx nuxi info",
+    "lint": "eslint --ext \".ts,.js,.vue\" --ignore-path .gitignore .",
+    "lint-fix": "eslint --fix --ext \".ts,.js,.vue\" --ignore-path .gitignore ."
   },
   "devDependencies": {
     "@nuxt/test-utils-edge": "^3.0.0-rc.11-27727864.720da64",
     "@nuxtjs/eslint-config": "^10.0.0",
+    "@nuxtjs/eslint-config-typescript": "^11.0.0",
     "@nuxtjs/eslint-module": "^3.1.0",
     "@types/event-source-polyfill": "^1.0.0",
     "@types/jest": "^29.0.3",
     "@types/lodash": "^4.14.185",
+    "@typescript-eslint/eslint-plugin": "^5.39.0",
+    "@typescript-eslint/parser": "^5.39.0",
+    "@vue/eslint-config-standard": "^8.0.1",
     "eslint": "^8.22.0",
+    "eslint-config-prettier": "^8.5.0",
     "eslint-plugin-nuxt": "^4.0.0",
+    "eslint-plugin-prettier": "^4.2.1",
+    "eslint-plugin-vue": "^9.6.0",
     "jest": "^29.0.3",
+    "prettier": "^2.7.1",
     "ts-jest": "^29.0.1",
+    "typescript": "^4.8.4",
     "vitest": "^0.23.4",
     "vue-jest": "^3.0.7"
   },
@@ -39,6 +52,7 @@
     "@pinia-orm/nuxt": "^1.0.18",
     "@pinia/nuxt": "^0.4.0",
     "@types/js-yaml": "^4.0.5",
+    "date-fns": "^2.29.3",
     "event-source-polyfill": "^1.0.31",
     "js-yaml": "^4.1.0",
     "libphonenumber-js": "^1.10.13",

+ 0 - 230
services/connection/connection.ts

@@ -1,230 +0,0 @@
-import {AnyJson, DataPersisterArgs, DataProviderArgs, UrlArgs} from '~/types/interfaces'
-import {HTTP_METHOD, QUERY_TYPE} from '~/types/enums'
-import TypesTesting from "~/services/utils/typesTesting";
-import {$fetch, FetchOptions} from "ohmyfetch";
-import {useProfileAccessStore} from "~/store/profile/access";
-import Page from "~//services/store/page";
-import {TYPE_ALERT} from "~//types/enums";
-
-/**
- * @category Services/connection
- * @class Connection
- *
- * Classe Wrapper du connecteur de requête (Axios dans notre cas)
- */
-class Connection {
-
-  /**
-   * Main méthode qui appellera les méthodes privées correspondantes (getItem, getCollection, put, post, delete)
-   * @param {HTTP_METHOD} method Mode de requêtage (GET, PUT, DELETE...)
-   * @param {string} url
-   * @param {DataProviderArgs|DataPersisterArgs} args
-   * @return {Promise<any>}
-   */
-  public static invoke (method: HTTP_METHOD, url: string, args: UrlArgs): Promise<any> {
-    switch (method) {
-      case HTTP_METHOD.GET:
-        if (args.type === QUERY_TYPE.FILE) {
-          return Connection.download(url, args.showProgress, args.params)
-        }
-        if (args.id) {
-          return Connection.getItem(url, args.id, args.showProgress, args.params)
-        } else {
-          return Connection.getCollection(url, args.type, args.showProgress, args.params)
-        }
-
-      case HTTP_METHOD.PUT:
-      case HTTP_METHOD.POST:
-        if (!TypesTesting.isDataPersisterArgs(args)) {
-          throw new Error('*args* is not a dataPersisterArgs')
-        }
-        if (!args.data) {
-          throw new Error('*args* has no data')
-        }
-
-        switch (method) {
-          case HTTP_METHOD.PUT:
-            return Connection.put(url, args.id, args.data, args.showProgress, args.params)
-          case HTTP_METHOD.POST:
-            return Connection.post(url, args.data, args.showProgress, args.params)
-        }
-        break;
-
-      case HTTP_METHOD.DELETE:
-        return Connection.deleteItem(url, args.id, args.showProgress, args.params)
-    }
-
-    throw new Error('Unknown connection method was invoked')
-  }
-
-  /**
-   * GET Item : préparation de la config pour la récupération d'un item
-   * @param {string} url
-   * @param {number} id
-   * @param {boolean} showProgress
-   * @param {AnyJson} params
-   * @return {Promise<any>}
-   */
-  public static getItem (url: string, id: number, showProgress: boolean = true, params: AnyJson = {}): Promise<any> {
-    const config: FetchOptions = {
-      method: HTTP_METHOD.GET,
-      progress: showProgress,
-      params: params
-    }
-    return Connection.request(`${url}/${id}`, config)
-  }
-
-  /**
-   * Get collection : préparation de la config pour la récupération d'une collection d'items
-   * @param {string} url
-   * @param {boolean} progress
-   * @param {QUERY_TYPE} type
-   * @param {AnyJson} params
-   * @return {Promise<any>}
-   */
-  public static getCollection (url: string, type: QUERY_TYPE, progress: boolean = true, params: AnyJson = {}): Promise<any> {
-    let config: FetchOptions = {
-      method: HTTP_METHOD.GET,
-      progress,
-      params: params
-    }
-    if(type === QUERY_TYPE.IMAGE)
-      config = {...config, responseType: 'blob'}
-
-    return Connection.request(`${url}`, config)
-  }
-
-  /**
-   * GET dédié au téléchargement de fichiers
-   * @param url
-   * @param {number} id
-   * @param {boolean} showProgress
-   * @param {AnyJson} params
-   * @return {Promise<any>}
-   */
-  public static download (url: string, showProgress: boolean = true, params: AnyJson = {}): Promise<any> {
-    const config: FetchOptions = {
-      method: HTTP_METHOD.GET,
-      progress: showProgress,
-      responseType: 'blob',
-      params: params
-    }
-    return Connection.request(`${url}`, config)
-  }
-
-  /**
-   * Post : préparation de la config pour la création d'un item
-   * @param {string} url
-   * @param {AnyJson} data
-   * @param {boolean} progress
-   * @param {AnyJson} params
-   * @return {Promise<any>}
-   */
-  public static post(url: string, data: AnyJson, progress: boolean = true, params: AnyJson = {}): Promise<any> {
-    const config: FetchOptions = {
-      method: HTTP_METHOD.POST,
-      data,
-      progress,
-      params: params
-    }
-    return Connection.request(`${url}`, config)
-  }
-
-  /**
-   * Put : préparation de la config pour la mise à jour d'un item
-   * @param {string} url
-   * @param {number} id
-   * @param {AnyJson} data
-   * @param {boolean} progress
-   * @param {AnyJson} params
-   * @return {Promise<any>}
-   */
-  public static put (url: string, id: number, data: AnyJson, progress: boolean = true, params: AnyJson = {}): Promise<any> {
-    const config: FetchOptions = {
-      method: HTTP_METHOD.PUT,
-      data,
-      progress,
-      params: params
-    }
-    return Connection.request(`${url}/${id}`, config)
-  }
-
-  /**
-   * DELETE Item : préparation de la config pour la suppression d'un item
-   * @param {string} url
-   * @param {number} id
-   * @param {boolean} progress
-   * @param {AnyJson} params
-   * @return {Promise<any>}
-   */
-  public static deleteItem (url: string, id: number, progress: boolean = true, params: AnyJson = {}): Promise<any> {
-    const config: FetchOptions = {
-      method: HTTP_METHOD.DELETE,
-      progress,
-      params: params
-    }
-    return Connection.request(`${url}/${id}`, config)
-  }
-
-  /**
-   * Exécute la requete
-   * @param {string} url
-   * @param {FetchOptions} config
-   * @return {Promise<any>}
-   */
-  public static async request (url: string, config: FetchOptions): Promise<FetchResponse> {
-    Connection.addBaseUrl(config)
-    Connection.addHeader(config)
-    Connection.addOnResponseError(config)
-    return await $fetch(url, config)
-  }
-
-  /**
-   * On ajoute la base URL
-   * @param config
-   */
-  public static addBaseUrl(config){
-    const runtimeConfig = useRuntimeConfig()
-    config['baseURL'] = runtimeConfig.baseUrl ?? runtimeConfig.public.baseUrl
-  }
-
-  /**
-   * On ajoute les headers
-   * @param config
-   */
-  public static addHeader(config){
-    if(!config.params.noXaccessId){
-      const profileAccessStore = useProfileAccessStore()
-      config['headers'] = {
-        'x-accessid' : profileAccessStore.id,
-        'Authorization' : 'BEARER ' + profileAccessStore.bearer
-      }
-
-      if (profileAccessStore.switchId) {
-        config['headers']['x-switch-user'] = profileAccessStore.switchId
-      }
-    }
-  }
-
-  /**
-   * Gestion des erreurs de réponse
-   * @param config
-   */
-  public static async addOnResponseError(config){
-    config['onResponseError'] = (({ request, response, options }) => {
-      // In case of unauthorized, redirect to a specific page
-      if (response.status === 401) {
-        redirect('/login')
-      }
-      if (response.status === 403) {
-        new Page().addAlerts(TYPE_ALERT.ALERT, ['forbidden'])
-      }
-
-      if (response.status === 500) {
-        new Page().addAlerts(TYPE_ALERT.ALERT, [response])
-      }
-    })
-  }
-}
-
-export default Connection

+ 0 - 63
services/connection/urlOptionsBuilder.ts

@@ -1,63 +0,0 @@
-/**
- * Classe permettant de construire les options d'une URL
- */
-import TypesTesting from "~/services/utils/typesTesting";
-import {ListArgs, UrlArgs} from "~/types/interfaces";
-import {QUERY_TYPE} from "~/types/enums";
-
-class UrlOptionsBuilder {
-
-  /**
-   * Main méthode qui appellera les méthode privées correspondantes (getUrlOptionsImage, getUrlOptionsLists)
-   * @param {UrlArgs} args
-   * @return {string}
-   */
-  public static build(args: UrlArgs): Array<string> {
-    let options: Array<string> = []
-
-    if (args.type === QUERY_TYPE.IMAGE){
-      options = [...options, this.getUrlOptionsImage()]
-    }
-
-    if (TypesTesting.isDataProviderArgs(args) && args.listArgs !== undefined) {
-      options = [...options, ...this.getUrlOptionsLists(args.listArgs)]
-    }
-
-    return options
-  }
-
-  /**
-   * Une image doit toujours avoir le time en options pour éviter les problème de cache
-   * @private
-   */
-  private static getUrlOptionsImage(): string {
-    return new Date().getTime().toString()
-  }
-
-  /**
-   * Fonction renvoyant le tableau d'options d'une list
-   * @param listArgs
-   * @private
-   */
-  private static getUrlOptionsLists(listArgs: ListArgs): Array<string> {
-    const options: Array<string> = []
-
-    if (listArgs.itemsPerPage) {
-      options.push(`itemsPerPage=${listArgs.itemsPerPage}`)
-    }
-
-    if (listArgs.page) {
-      options.push(`page=${listArgs.page}`)
-    }
-
-    if (listArgs.filters) {
-      for(const filter of listArgs.filters){
-        options.push(`${filter.key}=${filter.value}`)
-      }
-    }
-
-    return options
-  }
-}
-
-export default UrlOptionsBuilder

+ 98 - 0
services/data/apiRequestService.ts

@@ -0,0 +1,98 @@
+import {AssociativeArray, Connector, HTTP_METHOD} from "./data";
+
+/**
+ * A basic api request service
+ *
+ * It will send basic http requests and returns raw results
+ */
+class ApiRequestService {
+    private connector: Connector;
+
+    public constructor(
+        connector: Connector,
+    ) {
+        this.connector = connector
+    }
+
+    /**
+     * Send a GET request
+     *
+     * @param url
+     * @param query
+     */
+    public get(
+        url: string,
+        query: AssociativeArray | null = null
+    ) {
+        return this.request(HTTP_METHOD.GET, url, null, null, query)
+    }
+
+    /**
+     * Send a POST request
+     *
+     * @param url
+     * @param body
+     * @param params
+     * @param query
+     */
+    public 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)
+    }
+
+    /**
+     * Send a PUT request
+     *
+     * @param url
+     * @param body
+     * @param params
+     * @param query
+     */
+    public 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)
+    }
+
+    /**
+     * Send a DELETE request
+     *
+     * @param url
+     * @param query
+     */
+    public delete(
+        url: string,
+        query: AssociativeArray | null = null
+    ) {
+        return this.request(HTTP_METHOD.GET, url, null, null, query)
+    }
+
+    /**
+     * Send an http request
+     *
+     * @param method
+     * @param url
+     * @param body
+     * @param params
+     * @param query
+     * @private
+     */
+    private async request(
+        method: HTTP_METHOD,
+        url: string,
+        body: string | null = null,
+        params: AssociativeArray | null = null,
+        query: AssociativeArray | null = null
+    ): Promise<Response> {
+        return await this.connector.request(method, url, body, params, query)
+    }
+}
+
+export default ApiRequestService

+ 47 - 0
services/data/connector/ohMyFetchConnector.ts

@@ -0,0 +1,47 @@
+import {AssociativeArray, Connector, HTTP_METHOD} from "../data";
+import {$Fetch} from "nitropack";
+import {FetchOptions} from "ohmyfetch";
+
+/**
+ * Connector for the ohmyfetch library
+ *
+ * @see https://github.com/unjs/ohmyfetch
+ */
+class OhMyFetchConnector implements Connector {
+    private readonly fetch: $Fetch
+
+    public constructor(
+        fetcher: $Fetch,
+    ) {
+        this.fetch = fetcher
+    }
+
+    /**
+     * Send an HTTP request
+     *
+     * @param method
+     * @param url
+     * @param body
+     * @param params
+     * @param query
+     */
+    request(
+        method: HTTP_METHOD,
+        url: string,
+        body: string | null = null,
+        params: AssociativeArray | null = null,
+        query: AssociativeArray | null = null
+    ) {
+        const config: FetchOptions = { body }
+        if (params) {
+            config.params = params
+        }
+        if (query) {
+            config.query = query
+        }
+
+        return this.fetch(url, config)
+    }
+}
+
+export default OhMyFetchConnector

+ 26 - 0
services/data/data.d.ts

@@ -0,0 +1,26 @@
+export const enum HTTP_METHOD {
+    POST = 'POST',
+    PUT = 'PUT',
+    GET = 'GET',
+    DELETE = 'DELETE'
+}
+
+export const enum FORMAT {
+    HYDRA,
+    YAML
+}
+
+interface AssociativeArray {
+    [key: string]: any;
+}
+
+interface Connector {
+    request(
+        method: HTTP_METHOD,
+        url: string,
+        body: null | any,
+        params: null | AssociativeArray,
+        query: null | AssociativeArray
+    )
+}
+

+ 96 - 0
services/data/entityManager.ts

@@ -0,0 +1,96 @@
+import ApiRequestService from "./apiRequestService";
+import {AssociativeArray, FORMAT} from "./data";
+import {Model, useRepo} from "pinia-orm";
+import UrlBuilder from "~/services/utils/urlBuilder";
+import ModelNormalizer from "~/services/data/serializer/normalizer/modelNormalizer";
+import HydraDenormalizer from "~/services/data/serializer/denormalizer/hydraDenormalizer";
+import ApiModel from "~/models/ApiModel";
+
+/**
+ * Entity manager: make operations on the models defined with the Pinia-Orm library
+ *
+ * @see https://pinia-orm.codedredd.de/
+ */
+class EntityManager  {
+    private apiRequestService: ApiRequestService;
+
+    public constructor(apiRequestService: ApiRequestService) {
+        this.apiRequestService = apiRequestService
+    }
+
+    public getRepository(model: typeof Model) {
+        return useRepo(model)
+    }
+
+    /**
+     * Fetch one entity by its id, save it to the store and returns it
+     * @param model
+     * @param id
+     */
+    public async fetch(model: typeof ApiModel, id: number) {
+
+        const url = UrlBuilder.concat('api', model.entity, String(id))
+
+        const response = await this.apiRequestService.get(url)
+
+        // deserialize the response
+        const entity = await HydraDenormalizer.denormalize(response)
+
+        // Save data into the store
+        const repository = this.getRepository(model)
+        repository.save(entity)
+
+        return entity
+    }
+
+    public findBy(model: typeof ApiModel, query: AssociativeArray) {
+
+    }
+
+    public fetchAll(model: typeof ApiModel) {
+
+    }
+
+    public async persist(model: typeof ApiModel, entity: ApiModel) {
+        const data = ModelNormalizer.normalize(entity)
+        let url = UrlBuilder.concat('api', model.entity)
+        let response = null
+
+        if (entity.isNew) {
+            response = await this.apiRequestService.post(url, data)
+
+        } else {
+            url = UrlBuilder.concat(url, String(entity.id))
+            response = await this.apiRequestService.put(url, data)
+        }
+
+        const fetchedEntity = await HydraDenormalizer.denormalize(response)
+
+        // Save data into the store
+        const repository = this.getRepository(model)
+        repository.save(fetchedEntity)
+
+        return fetchedEntity
+    }
+
+    public delete() {
+
+    }
+
+    public new(model: typeof ApiModel) {
+        const entity = new model()
+        entity.isNew = true
+
+        // Save data into the store
+        const repository = this.getRepository(model)
+        repository.save(entity)
+
+        return entity
+    }
+
+    public reset() {
+
+    }
+}
+
+export default EntityManager

+ 15 - 0
services/data/enumManager.ts

@@ -0,0 +1,15 @@
+import ApiRequestService from "./apiRequestService";
+
+class EnumManager {
+    private apiRequestService: ApiRequestService;
+
+    public constructor(apiRequestService: ApiRequestService) {
+        this.apiRequestService = apiRequestService
+    }
+
+    public fetch() {
+
+    }
+}
+
+export default EnumManager

+ 15 - 0
services/data/fileManager.ts

@@ -0,0 +1,15 @@
+import ApiRequestService from "./apiRequestService";
+
+class FileManager {
+    private apiRequestService: ApiRequestService;
+
+    public constructor(apiRequestService: ApiRequestService) {
+        this.apiRequestService = apiRequestService
+    }
+
+    public fetch() {
+
+    }
+}
+
+export default FileManager

+ 15 - 0
services/data/imageManager.ts

@@ -0,0 +1,15 @@
+import ApiRequestService from "./apiRequestService";
+
+class FileManager {
+    private apiRequestService: ApiRequestService;
+
+    public constructor(apiRequestService: ApiRequestService) {
+        this.apiRequestService = apiRequestService
+    }
+
+    public fetch() {
+
+    }
+}
+
+export default FileManager

+ 0 - 0
services/serializer/denormalizer/_import.ts → services/data/serializer/denormalizer/_import.ts


+ 1 - 2
services/serializer/denormalizer/baseDenormalizer.ts → services/data/serializer/denormalizer/baseDenormalizer.ts

@@ -1,7 +1,6 @@
-import { DENORMALIZER_TYPE } from '~/types/enums'
 
 abstract class BaseDenormalizer {
-  static support (_type: DENORMALIZER_TYPE): boolean {
+  static support (subject: object): boolean {
     throw new Error('Not implemented')
   }
 }

+ 12 - 12
services/serializer/denormalizer/hydra.ts → services/data/serializer/denormalizer/hydraDenormalizer.ts

@@ -5,7 +5,7 @@ import {DENORMALIZER_TYPE, METADATA_TYPE} from '~/types/enums'
 /**
  * Classe permettant d'assurer la dénormalization d'un objet Hydra en JSON
  */
-class Hydra extends BaseDenormalizer {
+class HydraDenormalizer extends BaseDenormalizer {
   static support (type: DENORMALIZER_TYPE): boolean {
     return type === DENORMALIZER_TYPE.HYDRA
   }
@@ -19,16 +19,16 @@ class Hydra extends BaseDenormalizer {
   public static denormalize (hydraData: AnyJson): AnyJson {
     if (hydraData['hydra:member']) {
       hydraData.totalCount = hydraData['hydra:totalItems']
-      return Hydra.parseCollection(hydraData)
+      return HydraDenormalizer.parseCollection(hydraData)
     } else {
-      return Hydra.parseItem(hydraData)
+      return HydraDenormalizer.parseItem(hydraData)
     }
   }
 
   private static parseItem (hydraData: AnyJson): ApiResponse {
     return {
       data: hydraData,
-      metadata: Hydra.definedMetadataForItem(hydraData)
+      metadata: HydraDenormalizer.definedMetadataForItem(hydraData)
     }
   }
     /**
@@ -68,7 +68,7 @@ class Hydra extends BaseDenormalizer {
   private static parseCollection (hydraData: AnyJson): ApiResponse {
     const collectionResponse:ApiResponse = {
       data:hydraData['hydra:member'],
-      metadata : Hydra.definedMetadataForCollection(hydraData)
+      metadata : HydraDenormalizer.definedMetadataForCollection(hydraData)
     }
 
     // collectionResponse.order = {}
@@ -78,7 +78,7 @@ class Hydra extends BaseDenormalizer {
     // Populate href property for all elements of the collection
     for (const key in collectionResponse.data) {
       const value = collectionResponse.data[key]
-      Hydra.populateAllData(value)
+      HydraDenormalizer.populateAllData(value)
     }
 
     // if (typeof (hydraData['hydra:search']) !== 'undefined') {
@@ -102,10 +102,10 @@ class Hydra extends BaseDenormalizer {
     }
 
     if(data['hydra:view']){
-      metadata.firstPage = Hydra.getPageNumber(data['hydra:view']['hydra:first'])
-      metadata.lastPage = Hydra.getPageNumber(data['hydra:view']['hydra:last'])
-      metadata.nextPage = Hydra.getPageNumber(data['hydra:view']['hydra:next'])
-      metadata.previousPage = Hydra.getPageNumber(data['hydra:view']['hydra:previous'])
+      metadata.firstPage = HydraDenormalizer.getPageNumber(data['hydra:view']['hydra:first'])
+      metadata.lastPage = HydraDenormalizer.getPageNumber(data['hydra:view']['hydra:last'])
+      metadata.nextPage = HydraDenormalizer.getPageNumber(data['hydra:view']['hydra:next'])
+      metadata.previousPage = HydraDenormalizer.getPageNumber(data['hydra:view']['hydra:previous'])
     }
 
     metadata.type = METADATA_TYPE.COLLECTION
@@ -130,10 +130,10 @@ class Hydra extends BaseDenormalizer {
     for (const key in data) {
       const value = data[key]
       if (value instanceof Object) {
-        Hydra.populateAllData(value)
+        HydraDenormalizer.populateAllData(value)
       }
     }
   }
 }
 
-export default Hydra
+export default HydraDenormalizer

+ 0 - 0
services/serializer/denormalizer/yaml.ts → services/data/serializer/denormalizer/yaml.ts


+ 0 - 0
services/serializer/normalizer/_import.ts → services/data/serializer/normalizer/_import.ts


+ 1 - 1
services/serializer/normalizer/baseNormalizer.ts → services/data/serializer/normalizer/baseNormalizer.ts

@@ -1,7 +1,7 @@
 import { QUERY_TYPE } from '~/types/enums'
 
 abstract class BaseNormalizer {
-  static support (_type: QUERY_TYPE): boolean {
+  static support (subject: object): boolean {
     throw new Error('Not implemented')
   }
 }

+ 0 - 0
services/serializer/normalizer/default.ts → services/data/serializer/normalizer/default.ts


+ 0 - 0
services/serializer/normalizer/file.ts → services/data/serializer/normalizer/file.ts


+ 22 - 0
services/data/serializer/normalizer/modelNormalizer.ts

@@ -0,0 +1,22 @@
+import BaseNormalizer from './baseNormalizer'
+import ApiModel from "~/models/ApiModel";
+
+/**
+ * Classe assurant la normalization d'un Model vers un fichier JSON
+ */
+class ModelNormalizer extends BaseNormalizer {
+  static support (subject: object): boolean {
+    return subject instanceof ApiModel
+  }
+
+  /**
+   * Récupération de l'Item souhaité puis transformation en JSON
+   *
+   * @return {any} réponse
+   * @param subject
+   */
+  public static normalize (subject: ApiModel): any {
+    return subject.$toJson()
+  }
+}
+export default ModelNormalizer

+ 23 - 0
services/data/serializer/serializer.ts

@@ -0,0 +1,23 @@
+import { denormalizers } from './denormalizer/_import'
+import { normalizers } from './normalizer/_import'
+import {FORMAT} from "../data";
+
+class Serializer {
+  public static normalize (subject: object) {
+    for (const Normalizer of normalizers) {
+      if (Normalizer.support(subject)) {
+        return Normalizer.normalize(subject)
+      }
+    }
+  }
+
+  public static denormalize (data: object, format: FORMAT): any {
+    for (const Denormalizer of denormalizers) {
+      if (Denormalizer.support(format)) {
+        return Denormalizer.denormalize(data)
+      }
+    }
+  }
+}
+
+export default Serializer

+ 0 - 0
services/data/__mocks__/__dataProvider.ts → services/data_old/__mocks__/__dataProvider.ts


+ 0 - 0
services/data/baseDataManager.ts → services/data_old/baseDataManager.ts


+ 0 - 0
services/data/dataDeleter.ts → services/data_old/dataDeleter.ts


+ 0 - 0
services/data/dataPersister.ts → services/data_old/dataPersister.ts


+ 0 - 0
services/data/dataProvider.ts → services/data_old/dataProvider.ts


+ 0 - 0
services/data/hookable.ts → services/data_old/hookable.ts


+ 0 - 0
services/data/hooks/baseHook.ts → services/data_old/hooks/baseHook.ts


+ 0 - 0
services/data/hooks/hookDeleter/_import.ts → services/data_old/hooks/hookDeleter/_import.ts


+ 0 - 0
services/data/hooks/hookDeleter/hookDeleterExample.ts → services/data_old/hooks/hookDeleter/hookDeleterExample.ts


+ 0 - 0
services/data/hooks/hookPersister/_import.ts → services/data_old/hooks/hookPersister/_import.ts


+ 0 - 0
services/data/hooks/hookPersister/hookPersisterExample.ts → services/data_old/hooks/hookPersister/hookPersisterExample.ts


+ 0 - 0
services/data/hooks/hookPersister/postPersistProfileRefresh.ts → services/data_old/hooks/hookPersister/postPersistProfileRefresh.ts


+ 0 - 0
services/data/hooks/hookProvider/_import.ts → services/data_old/hooks/hookProvider/_import.ts


+ 0 - 0
services/data/hooks/hookProvider/hookProviderExample.ts → services/data_old/hooks/hookProvider/hookProviderExample.ts


+ 0 - 0
services/data/processor/_import.ts → services/data_old/processor/_import.ts


+ 0 - 0
services/data/processor/baseProcessor.ts → services/data_old/processor/baseProcessor.ts


+ 0 - 0
services/data/processor/defaultProcessor.ts → services/data_old/processor/defaultProcessor.ts


+ 0 - 0
services/data/processor/enumProcessor.ts → services/data_old/processor/enumProcessor.ts


+ 0 - 0
services/data/processor/fileProcessor.ts → services/data_old/processor/fileProcessor.ts


+ 0 - 0
services/data/processor/imageProcessor.ts → services/data_old/processor/imageProcessor.ts


+ 0 - 0
services/data/processor/modelProcessor.ts → services/data_old/processor/modelProcessor.ts


+ 0 - 76
services/serializer/normalizer/model.ts

@@ -1,76 +0,0 @@
-import BaseNormalizer from '~/services/serializer/normalizer/baseNormalizer'
-import {AnyJson, DataPersisterArgs} from '~/types/interfaces'
-import { QUERY_TYPE } from '~/types/enums'
-import { Item } from 'pinia-orm'
-import { repositoryHelper } from '~/services/store/repository'
-import {queryHelper} from "~/services/store/query";
-import {$objectProperties} from "~/services/utils/objectProperties";
-
-/**
- * @category Services/serializer/normalizer
- * @class Model
- * Classe assurant la normalization d'un Model vers un fichier JSON
- */
-class Model extends BaseNormalizer {
-  static support (type: QUERY_TYPE): boolean {
-    return type === QUERY_TYPE.MODEL
-  }
-
-  /**
-   * Récupération de l'Item souhaité puis transformation en JSON
-   * @param {DataPersisterArgs} args
-   * @return {any} réponse
-   */
-  public static normalize (args: DataPersisterArgs): any {
-    if (!args.model) {
-      throw new Error('*args* has no model attribute')
-    }
-
-    let item:Item = null
-    const itemId = args.idTemp ? args.idTemp : args.id
-
-    if(args.query){
-      item = queryHelper.getItem(args.query, itemId)
-    }else{
-      item = repositoryHelper.findItemFromModel(args.model, itemId)
-    }
-
-    if (!item || typeof item === 'undefined') {
-      throw new Error('Item not found')
-    }
-
-    let data = item.$toJson()
-
-    if(Model.isPostQuery(args)) data = Model.sanitizeBeforePost(data, args.query ? args.query.getAllRelations() : [])
-
-    return useOmit(data, 'originalState')
-  }
-
-  /**
-   * Return true si on est dans un POST
-   * @param args
-   */
-  public static isPostQuery(args: DataPersisterArgs): boolean{
-    return args.idTemp
-  }
-
-  /**
-   * Opération de nettoyage avant un POST
-   * @param data
-   * @param relations
-   */
-  public static sanitizeBeforePost(data:AnyJson, relations: Array<string>): AnyJson{
-    if(relations){
-      data = $objectProperties.cloneAndFlatten(data)
-      for(const relation of relations){
-        delete data[`${relation}.id`]
-        delete data[`${relation}.@id`]
-      }
-      data = $objectProperties.cloneAndNest(data)
-    }
-
-    delete data.id
-    return data
-  }
-}
-export default Model

+ 0 - 24
services/serializer/serializer.ts

@@ -1,24 +0,0 @@
-import { AnyJson, DataPersisterArgs } from '~/types/interfaces'
-import { denormalizers } from '~/services/serializer/denormalizer/_import'
-import { normalizers } from '~/services/serializer/normalizer/_import'
-import { DENORMALIZER_TYPE } from '~/types/enums'
-
-class Serializer {
-  public static normalize (args:DataPersisterArgs) {
-    for (const Normalizer of normalizers) {
-      if (Normalizer.support(args.type)) {
-        return Normalizer.normalize(args)
-      }
-    }
-  }
-
-  public static denormalize (data: AnyJson, type: DENORMALIZER_TYPE): any {
-    for (const Denormalizer of denormalizers) {
-      if (Denormalizer.support(type)) {
-        return Denormalizer.denormalize(data)
-      }
-    }
-  }
-}
-
-export default Serializer

+ 14 - 15
services/utils/datesUtils.ts

@@ -1,28 +1,27 @@
-import moment from 'moment'
+import { format } from 'date-fns';
 
 export default class DatesUtils {
-  private $moment: typeof moment;
+  private $dateFns: dateFns;
 
-  constructor (momentInstance: any) {
-    this.$moment = momentInstance
+  constructor(dateFns: dateFns) {
+    this.$dateFns = dateFns
   }
 
   /**
-   * Formate la ou les dates au format donné
+   * Formate la ou les dates au format donné et retourne la liste concaténée
    *
    * @param dates
-   * @param format
+   * @param fmt
+   * @param sep
    */
-  formattedDate (dates: any, format: string): string {
-    const dFormat: Array<string> = []
-    if (Array.isArray(dates)) {
-      for (const date of dates) {
-        dFormat.push(this.$moment(date).format(format))
-      }
-    } else {
-      dFormat.push(this.$moment(dates as string).format(format))
+  formatDatesAndConcat (dates: any, fmt: string, sep: string = ' - '): string {
+    dates = Array.isArray(dates) ? dates : [dates]
+
+    const dFormat: Array<string> = Array.isArray(dates) ? dates : [dates]
+    for (const date of dates) {
+      dFormat.push(format(date, fmt))
     }
-    return dFormat.join(' - ')
+    return dFormat.join(sep)
   }
 
   /**

+ 56 - 3
services/connection/urlBuilder.ts → services/utils/urlBuilder.ts

@@ -1,5 +1,5 @@
 import {Model} from '@vuex-orm/core'
-import {FileArgs, ImageArgs, UrlArgs} from '~/types/interfaces'
+import {FileArgs, ImageArgs, ListArgs, UrlArgs} from '~/types/interfaces'
 import {QUERY_TYPE} from '~/types/enums'
 import {repositoryHelper} from '~/services/store/repository'
 import TypesTesting from "~/services/utils/typesTesting";
@@ -56,8 +56,8 @@ class UrlBuilder {
         break;
     }
 
-    const options = UrlOptionsBuilder.build(args)
-    return options.length > 0 ? `${url}?${UrlOptionsBuilder.build(args).join('&')}` : url
+    const options = UrlBuilder.buildOptions(args)
+    return options.length > 0 ? `${url}?${UrlBuilder.buildOptions(args).join('&')}` : url
   }
 
   /**
@@ -159,6 +159,59 @@ class UrlBuilder {
     }
     return url;
   }
+
+
+  /**
+   * Main méthode qui appellera les méthode privées correspondantes (getUrlOptionsImage, getUrlOptionsLists)
+   * @param {UrlArgs} args
+   * @return {string}
+   */
+  public static buildOptions(args: UrlArgs): Array<string> {
+    let options: Array<string> = []
+
+    if (args.type === QUERY_TYPE.IMAGE){
+      options = [...options, this.getUrlOptionsImage()]
+    }
+
+    if (TypesTesting.isDataProviderArgs(args) && args.listArgs !== undefined) {
+      options = [...options, ...this.getUrlOptionsLists(args.listArgs)]
+    }
+
+    return options
+  }
+
+  /**
+   * Une image doit toujours avoir le time en options pour éviter les problème de cache
+   * @private
+   */
+  private static getUrlOptionsImage(): string {
+    return new Date().getTime().toString()
+  }
+
+  /**
+   * Fonction renvoyant le tableau d'options d'une list
+   * @param listArgs
+   * @private
+   */
+  private static getUrlOptionsLists(listArgs: ListArgs): Array<string> {
+    const options: Array<string> = []
+
+    if (listArgs.itemsPerPage) {
+      options.push(`itemsPerPage=${listArgs.itemsPerPage}`)
+    }
+
+    if (listArgs.page) {
+      options.push(`page=${listArgs.page}`)
+    }
+
+    if (listArgs.filters) {
+      for(const filter of listArgs.filters){
+        options.push(`${filter.key}=${filter.value}`)
+      }
+    }
+
+    return options
+  }
 }
 
 export default UrlBuilder

+ 3 - 0
tsconfig.json

@@ -6,6 +6,9 @@
     "esModuleInterop": true,
     "sourceMap": true,
     "experimentalDecorators": true,
+    "types": [
+      "@nuxtjs/date-fns"
+    ],
     "exclude": [
       "node_modules",
       ".nuxt"

+ 164 - 152
types/interfaces.d.ts

@@ -1,57 +1,65 @@
 import { Model, Query } from 'pinia-orm'
 import { Ability } from '@casl/ability'
 import { Store } from 'pinia'
-import { Context } from '@nuxt/types/app'
 import DataPersister from '~/services/data/dataPersister'
 import DataProvider from '~/services/data/dataProvider'
 import DataDeleter from '~/services/data/dataDeleter'
-import {ABILITIES, FORM_STATUS, GENDER, METADATA_TYPE, QUERY_TYPE, SUBMIT_TYPE, TYPE_ALERT} from '~/types/enums'
+import {
+  ABILITIES,
+  FORM_STATUS,
+  GENDER,
+  METADATA_TYPE,
+  QUERY_TYPE,
+  TYPE_ALERT,
+} from '~/types/enums'
 
 /**
  * Upgrade du @nuxt/types pour TypeScript
  */
 declare module '@nuxt/types' {
   interface Context {
-    $ability: Ability,
-    $dataPersister: DataPersister,
-    $dataProvider: DataProvider,
-    $dataDeleter: DataDeleter,
+    $ability: Ability
+    $dataPersister: DataPersister
+    $dataProvider: DataProvider
+    $dataDeleter: DataDeleter
   }
 }
 
 declare module '@vuex-orm/core' {
-  interface Query{
+  interface Query {
     getAllRelations: () => Array<string>
   }
 }
 
-interface IconItem{
-  name?: string,
-  avatarId?:number|null,
-  avatarByDefault?:string,
+interface IconItem {
+  name?: string
+  avatarId?: number | null
+  avatarByDefault?: string
 }
 
 interface ItemMenu {
-  title: string,
-  icon?: IconItem,
-  avatar?: number,
-  to?: string,
-  children?: ItemsMenu,
-  isExternalLink?: boolean,
-  actions?: ItemsMenu,
+  title: string
+  icon?: IconItem
+  avatar?: number
+  to?: string
+  // eslint-disable-next-line no-use-before-define
+  children?: ItemsMenu
+  isExternalLink?: boolean
+  // eslint-disable-next-line no-use-before-define
+  actions?: ItemsMenu
 }
 
-interface ItemsMenu extends Array<ItemMenu> {}
+type ItemsMenu = Array<ItemMenu>
 
 interface Menu {
-  getMenu : () => ItemMenu | null,
-  getHeaderMenu : () => ItemMenu | null,
+  getMenu: () => ItemMenu | null
+  getHeaderMenu: () => ItemMenu | null
 }
 
 interface AbilitiesType {
-  action: ABILITIES,
+  action: ABILITIES
 
-  subject: string,
+  subject: string
   /** an array of fields to which user has (or not) access */
   fields?: string[]
   /** an object of conditions which restricts the rule scope */
@@ -63,119 +71,119 @@ interface AbilitiesType {
 }
 
 interface formState {
-  violations: Array<string>,
-  readonly: boolean,
-  formStatus: FORM_STATUS,
-  dirty: boolean,
-  showConfirmToLeave: boolean,
-  goAfterLeave: string|null
+  violations: Array<string>
+  readonly: boolean
+  formStatus: FORM_STATUS
+  dirty: boolean
+  showConfirmToLeave: boolean
+  goAfterLeave: string | null
 }
 
 interface Alert {
-  type: TYPE_ALERT,
+  type: TYPE_ALERT
   messages: Array<string>
 }
 
 interface pageState {
-  alerts: Array<Alert>,
+  alerts: Array<Alert>
 }
 
 interface Historical {
-  future?: boolean,
-  past?: boolean,
-  present?: boolean,
-  dateStart?: string,
+  future?: boolean
+  past?: boolean
+  present?: boolean
+  dateStart?: string
   dateEnd?: string
 }
 
-interface baseAccessState{
-  id: number|null,
-  name: string|null,
-  givenName: string|null,
-  gender: GENDER|null,
-  avatarId: number|null
+interface baseAccessState {
+  id: number | null
+  name: string | null
+  givenName: string | null
+  gender: GENDER | null
+  avatarId: number | null
+}
+
+interface baseOrganizationState {
+  id: number | null
+  name: string | null
+  website?: string | null
 }
 
 interface OrignalAccessState extends baseAccessState {
-  isSuperAdminAccess: boolean,
+  isSuperAdminAccess: boolean
   organization: baseOrganizationState
 }
 
 interface accessState extends baseAccessState {
-  bearer: string|null,
-  switchId: number|null
-  activityYear: number|null
-  historical: Historical|Array<String>
+  bearer: string | null
+  switchId: number | null
+  activityYear: number | null
+  historical: Historical | Array<string>
   roles: Array<string>
   abilities: Array<AbilitiesType>
-  isAdminAccess: boolean|null
-  isSuperAdminAccess: boolean|null
-  isAdmin: boolean|null
-  isAdministratifManager: boolean|null
-  isPedagogicManager: boolean|null
-  isFinancialManager: boolean|null
-  isCaMember: boolean|null
-  isStudent: boolean|null
-  isTeacher: boolean|null
-  isMember: boolean|null
-  isOther: boolean|null
-  isGuardian: boolean|null
-  isPayor: boolean|null
-  hasLateralMenu: boolean|null
-  hasConfigurationMenu: boolean|null
-  hasAccessesMenu: boolean|null
-  hasFamilyMenu: boolean|null
+  isAdminAccess: boolean | null
+  isSuperAdminAccess: boolean | null
+  isAdmin: boolean | null
+  isAdministratifManager: boolean | null
+  isPedagogicManager: boolean | null
+  isFinancialManager: boolean | null
+  isCaMember: boolean | null
+  isStudent: boolean | null
+  isTeacher: boolean | null
+  isMember: boolean | null
+  isOther: boolean | null
+  isGuardian: boolean | null
+  isPayor: boolean | null
+  hasLateralMenu: boolean | null
+  hasConfigurationMenu: boolean | null
+  hasAccessesMenu: boolean | null
+  hasFamilyMenu: boolean | null
   multiAccesses: Array<baseOrganizationState>
   familyAccesses: Array<baseAccessState>
-  originalAccess: OrignalAccessState|null
-}
-
-interface baseOrganizationState {
-  id: number|null,
-  name: string|null,
-  website?: string|null
+  originalAccess: OrignalAccessState | null
 }
 
 interface organizationState extends baseOrganizationState {
-  id: number|null,
-  parametersId: number|null,
-  name: string|null,
-  product?: string|null,
-  currentActivityYear?: number|null,
-  modules?: Array<string>,
-  hasChildren?: boolean|null,
-  showAdherentList?: boolean|null,
-  legalStatus?: string|null,
-  networks: Array<string>,
-  parents: Array<baseOrganizationState>,
-}
-
-interface AnyJson extends Record<string, any> {}
-interface AnyStore extends Store<any> {}
+  id: number | null
+  parametersId: number | null
+  name: string | null
+  product?: string | null
+  currentActivityYear?: number | null
+  modules?: Array<string>
+  hasChildren?: boolean | null
+  showAdherentList?: boolean | null
+  legalStatus?: string | null
+  networks: Array<string>
+  parents: Array<baseOrganizationState>
+}
+
+type AnyJson = Record<string, any>
+type AnyStore = Store<any>
 
 interface EnumChoice {
-  value: string,
+  value: string
   label: string
 }
 
 interface UrlArgs {
-  readonly type: QUERY_TYPE,
-  readonly url?: string,
-  readonly baseUrl?: string,
-  readonly enumType?: string,
-  readonly model?: typeof Model,
-  readonly rootModel?: typeof Model,
-  readonly id?: any,
-  readonly idTemp?: any,
-  readonly rootId?: number,
-  readonly showProgress?: boolean,
-  readonly hook?: string,
+  readonly type: QUERY_TYPE
+  readonly url?: string
+  readonly baseUrl?: string
+  readonly enumType?: string
+  readonly model?: typeof Model
+  readonly rootModel?: typeof Model
+  readonly id?: any
+  readonly idTemp?: any
+  readonly rootId?: number
+  readonly showProgress?: boolean
+  readonly hook?: string
   readonly params?: AnyJson
 }
 
 interface ImageArgs {
-  readonly id: number,
-  readonly height: number,
+  readonly id: number
+  readonly height: number
   readonly width: number
 }
 
@@ -183,43 +191,43 @@ interface FileArgs {
   readonly fileId: number
 }
 
-interface Filter{
-  readonly key: string,
-  readonly value: string|boolean|number
+interface Filter {
+  readonly key: string
+  readonly value: string | boolean | number
 }
 
 interface ListArgs {
-  readonly itemsPerPage?: number,
+  readonly itemsPerPage?: number
   readonly page?: number
   readonly filters?: Array<Filter>
 }
 
 interface DataProviderArgs extends UrlArgs {
-  imgArgs?: ImageArgs,
-  listArgs?: ListArgs,
-  fileArgs?: FileArgs,
+  imgArgs?: ImageArgs
+  listArgs?: ListArgs
+  fileArgs?: FileArgs
 }
 interface DataPersisterArgs extends UrlArgs {
-  data?: AnyJson,
-  query?: Query,
+  data?: AnyJson
+  query?: Query
   file?: string
 }
-interface DataDeleterArgs extends UrlArgs {}
+type DataDeleterArgs = UrlArgs
 
-interface EnumChoices extends Array<EnumChoice> {}
+type EnumChoices = Array<EnumChoice>
 
 interface DataManager {
-  invoke(args: UrlArgs): Promise<any>,
+  invoke(args: UrlArgs): Promise<any>
 }
 
 interface HookProvider {
-  invoke(args: DataProviderArgs): Promise<any>,
+  invoke(args: DataProviderArgs): Promise<any>
 }
 interface HookPersister {
-  invoke(args: DataPersisterArgs): Promise<any>,
+  invoke(args: DataPersisterArgs): Promise<any>
 }
 interface HookDeleter {
-  invoke(args: DataDeleterArgs): Promise<any>,
+  invoke(args: DataDeleterArgs): Promise<any>
 }
 
 interface Processor {
@@ -227,75 +235,79 @@ interface Processor {
 }
 
 interface Normalizer {
-  normalize(args: DataPersisterArgs): any,
+  normalize(args: DataPersisterArgs): any
 }
 interface Denormalizer {
-  denormalize(data: any): any,
+  denormalize(data: any): any
 }
 
 interface DolibarrContractLine {
-  id: number,
-  contractId: number,
-  dateStart: Date,
-  dateEnd: Date,
-  serviceRef: string,
+  id: number
+  contractId: number
+  dateStart: Date
+  dateEnd: Date
+  serviceRef: string
   serviceLabel: string
 }
 
 interface DolibarrContract {
-  ref: string,
-  socId: number,
+  ref: string
+  socId: number
   lines: Array<DolibarrContractLine>
 }
 
 interface DolibarrBill {
-  id: number,
-  ref: string,
-  socId: number,
-  date: Date,
-  taxExcludedAmount: number,
-  taxIncludedAmount: number,
+  id: number
+  ref: string
+  socId: number
+  date: Date
+  taxExcludedAmount: number
+  taxIncludedAmount: number
   paid: boolean
 }
 
 interface DolibarrAccount {
-  organizationId: number,
-  socId: number,
-  clientNumber: string,
-  product: 'PRODUCT_ARTIST' | 'PRODUCT_ARTIST_PREMIUM' | 'PRODUCT_SCHOOL' |
-      'PRODUCT_SCHOOL_PREMIUM' | 'PRODUCT_MANAGER',
-  contract: DolibarrContract,
+  organizationId: number
+  socId: number
+  clientNumber: string
+  product:
+    | 'PRODUCT_ARTIST'
+    | 'PRODUCT_ARTIST_PREMIUM'
+    | 'PRODUCT_SCHOOL'
+    | 'PRODUCT_SCHOOL_PREMIUM'
+    | 'PRODUCT_MANAGER'
+  contract: DolibarrContract
   bills: Array<DolibarrBill>
 }
 
 interface MobytUserStatus {
-  organizationId: number,
-  active: boolean,
-  amount: number,
+  organizationId: number
+  active: boolean
+  amount: number
   money: number
 }
 
-interface ApiResponse{
-  data: AnyJson,
-  metadata: HydraMetadata
-}
-
 interface HydraMetadata {
-  readonly totalItems?: number,
-  firstPage?: number,
-  lastPage?: number,
-  nextPage?: number,
-  previousPage?: number,
+  readonly totalItems?: number
+  firstPage?: number
+  lastPage?: number
+  nextPage?: number
+  previousPage?: number
   type?: METADATA_TYPE
 }
 
+interface ApiResponse {
+  data: AnyJson
+  metadata: HydraMetadata
+}
+
 interface MercureEntityUpdate {
-  iri: string,
-  operation: 'create' | 'delete' | 'update',
+  iri: string
+  operation: 'create' | 'delete' | 'update'
   data: any
 }
 
 interface sseState {
-  connected: boolean,
-  events: Array<MercureEntityUpdate>,
+  connected: boolean
+  events: Array<MercureEntityUpdate>
 }