@communecter/cocolight-api-client 1.0.18 → 1.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,6 @@
1
- import { ApiError } from "../error.js";
2
- import { DraftStateMixin } from "../mixin/DraftStateMixin.js";
3
- import { EntityMixin } from "../mixin/EntityMixin.js";
4
- import { MutualEntityMixin } from "../mixin/MutualEntityMixin.js";
5
- import { NewsMixin } from "../mixin/NewsMixin.js";
6
- import { UtilMixin } from "../mixin/UtilMixin.js";
7
-
8
- // Organization.js
9
- export class Organization {
10
- #draftData = {};
11
- #initialDraftData = {};
12
- #serverData = null;
1
+ import BaseEntity from "./BaseEntity.js";
13
2
 
3
+ export class Organization extends BaseEntity {
14
4
  static entityType = "organizations";
15
5
 
16
6
  static SCHEMA_CONSTANTS = [
@@ -25,7 +15,7 @@ export class Organization {
25
15
 
26
16
  static ADD_BLOCKS = new Map([
27
17
  ["ADD_ORGANIZATION", "addOrganization"],
28
- ["PROFIL_IMAGE", ""]
18
+ ["PROFIL_IMAGE", "updateImageProfil"]
29
19
  ]);
30
20
 
31
21
  static UPDATE_BLOCKS = new Map([
@@ -37,219 +27,66 @@ export class Organization {
37
27
  ["PROFIL_IMAGE", "updateImageProfil"]
38
28
  ]);
39
29
 
40
- /**
41
- * Crée une instance de Organization.
42
- *
43
- * @param {ApiClient|User} parent - Instance de ApiClient ou User.
44
- * @param {Object} [data={}] - Données de l'organisation.
45
- * @param {Object} [deps={}] - Dépendances injectées.
46
- * @param {function|object} deps.EndpointApi - Classe ou instance de EndpointApi pour les appels API.
47
- * @param {function} deps.User - Classe User pour la gestion des utilisateurs.
48
- * @param {function} deps.Project - Classe Project pour la gestion des projets.
49
- * @param {function} deps.News - Classe News pour la gestion des actualités.
50
- *
51
- * @throws {ApiError} Si le parent n'est pas valide ou si les dépendances ne sont pas injectées correctement.
52
- */
53
-
54
- constructor(parent, data = {}, deps = {}) {
55
- this.__entityTag = "Organization";
56
-
57
- if (!deps.EndpointApi) throw new ApiError("EndpointApi class must be injected to avoid circular dependency.");
58
- if (!deps.User) throw new ApiError("User class must be injected.");
59
- if (!deps.Project) throw new ApiError("Project class must be injected.");
60
- if (!deps.News) throw new ApiError("News class must be injected.");
61
-
62
- if (!parent) throw new ApiError("Parent is required.");
63
-
64
- this.deps = deps;
65
-
66
- this.EndpointApiClass = deps.EndpointApi;
67
-
68
- if (parent?.__entityTag === "ApiClient") {
69
- this.apiClient = parent;
70
- this.parent = null;
71
- } else if (parent?.__entityTag === "User") {
72
- this.apiClient = parent.apiClient;
73
- this.parent = parent;
74
- } else {
75
- throw new ApiError("Invalid parent for Organization.");
76
- }
77
-
78
- this.endpointApi = typeof deps.EndpointApi === "function"
79
- ? new deps.EndpointApi(this.apiClient)
80
- : (typeof deps.EndpointApi === "object"
81
- ? deps.EndpointApi
82
- : (() => { throw new ApiError("deps.EndpointApi must be a class or instance."); })());
83
-
84
- this.#serverData = null;
85
-
86
- const { draft, proxy } = this._buildDraftAndProxy({
87
- data: { ...data, ...this.defaultFields },
88
- serverData: this.#serverData,
89
- constant: Organization.SCHEMA_CONSTANTS,
90
- apiClient: this.apiClient,
91
- transforms: this.transforms,
92
- removeFields: this.removeFields
93
- });
94
-
95
- this.#initialDraftData = JSON.parse(JSON.stringify(draft)); // snapshot propre
96
- this.#draftData = draft;
97
- this.data = proxy;
98
- }
99
-
100
- // Getters en lecture seule pour chaque propriété
101
- get id() {
102
- return this.#draftData.id || null;
103
- }
104
-
105
- _id(newId) {
106
- this.#draftData.id = newId;
107
- }
108
-
109
- get slug() {
110
- return this.#draftData.slug || null;
111
- }
112
-
113
- get isConnected() {
114
- return this.apiClient.isConnected;
115
- }
116
-
117
- _setData(newData) {
118
- this.#serverData = { ...newData };
119
-
120
- const { draft, proxy } = this._buildDraftAndProxy({
121
- data: { ...newData, ...this.defaultFields },
122
- serverData: this.#serverData,
123
- constant: Organization.SCHEMA_CONSTANTS,
124
- apiClient: this.apiClient,
125
- transforms: this.transforms,
126
- removeFields: this.removeFields
127
- });
128
- this.#initialDraftData = JSON.parse(JSON.stringify(draft));
129
- this.#draftData = draft;
130
- this.data = proxy;
131
- }
132
-
133
- get userId() {
134
- return this.apiClient.userId;
135
- }
136
-
137
- get draftData() {
138
- return this.#draftData;
139
- }
140
-
141
- get initialDraftData() {
142
- return this.#initialDraftData;
143
- }
144
-
145
- get serverData() {
146
- return this.#serverData;
147
- }
148
-
149
- get isMe() {
150
- return this.isConnected && this.userId === this.parent?.id;
151
- }
152
-
153
- getEntityType() {
154
- return Organization.entityType;
155
- }
156
-
157
- static fromServerData(data, parent, deps) {
158
- const instance = new Organization(parent, {}, deps);
159
- instance.#serverData = { ...data };
160
-
161
- const { draft, proxy } = instance._buildDraftAndProxy({
162
- data: { ...data, ...instance.defaultFields },
163
- serverData: instance.#serverData,
164
- constant: Organization.SCHEMA_CONSTANTS,
165
- apiClient: instance.apiClient,
166
- transforms: instance.transforms,
167
- removeFields: instance.removeFields
168
- });
169
-
170
- instance.#draftData = draft;
171
- instance.data = proxy;
172
-
173
- return instance;
174
- }
175
-
176
- async refresh() {
177
- if (!this.id) throw new ApiError("Impossible de rafraîchir sans ID.");
178
- return this.get();
179
- }
30
+ defaultFields = {
31
+ typeElement: this.getEntityType()
32
+ };
180
33
 
181
- async save() {
34
+ removeFields = [
35
+ "typeElement"
36
+ ];
182
37
 
183
- if(!this.isConnected){
184
- throw new ApiError("Impossible de sauvegarder sans être connecté.");
185
- }
38
+ // role = admin c'est bizarre car en faite c'est gérer dans links sur user et l'orga
39
+ // links.members.${this.userId}.isAdmin === true
40
+ transforms = {
41
+ github: (val, full) => full?.socialNetwork?.github,
42
+ gitlab: (val, full) => full?.socialNetwork?.gitlab,
43
+ facebook: (val, full) => full?.socialNetwork?.facebook,
44
+ twitter: (val, full) => full?.socialNetwork?.twitter,
45
+ instagram: (val, full) => full?.socialNetwork?.instagram,
46
+ diaspora: (val, full) => full?.socialNetwork?.diaspora,
47
+ mastodon: (val, full) => full?.socialNetwork?.mastodon,
48
+ telegram: (val, full) => full?.socialNetwork?.telegram,
49
+ signal: (val, full) => full?.socialNetwork?.signal
50
+ };
186
51
 
187
- const payload = { ...this.#draftData };
188
-
189
- if (!this.id) {
190
- await this._add(payload);
191
- // this._updateInitialDraftSnapshot();
192
- await this.refresh();
193
- return this.#serverData;
194
- } else {
195
- const hasChanged = await this._update(payload);
196
- if (hasChanged) {
197
- // this._updateInitialDraftSnapshot();
198
- await this.refresh();
199
- }
200
- return this.#serverData;
52
+ async _add(payload) {
53
+ if (!this._calledFromSave) {
54
+ throw new Error("utilisation invalide de _add, utilisez save");
201
55
  }
202
-
203
- }
204
56
 
205
- async _add(payload){
206
- // si pas d'id on le crée
207
- payload.id = this._newId();
208
- // on enlève le slug mais il ne devrait pas être là
209
- if(payload.slug){
210
- delete payload.slug;
211
- }
57
+ payload.id = this._newId?.();
58
+ if (payload.slug) delete payload.slug;
212
59
 
213
60
  for (const [constant, methodName] of Organization.ADD_BLOCKS) {
214
61
  const blockData = this._extractChangedFieldsFromSchema(
215
62
  this.apiClient,
216
63
  constant,
217
- { ...payload, ...this.defaultFields},
64
+ { ...payload, ...this.defaultFields },
218
65
  () => {}
219
66
  );
220
67
  if (blockData && Object.keys(blockData).length > 0) {
221
68
  const data = await this[methodName](blockData);
222
-
223
69
  if (!this.id && data?.map?.id) {
224
- this.#draftData.id = data.map.id;
225
- this.#draftData.slug = data.map.slug;
226
- // on met à jour le slug dans le draftData
227
-
228
- // faire ça ou alors resfresh() pour re-synchroniser
229
- // this.#serverData = data.map;
70
+ this._draftData.id = data.map.id;
71
+ this._draftData.slug = data.map.slug;
230
72
  }
231
73
  }
232
74
  }
233
75
  }
234
76
 
235
- async _update(payload){
236
- // on enlève l'id car il existe déjà dans les appels API je laisse slug car il peut être changer en update ici
237
- // if(payload.slug){
238
- // delete payload.slug;
239
- // }
240
- if(payload.id){
241
- delete payload.id;
77
+ async _update(payload) {
78
+ if (!this._calledFromSave) {
79
+ throw new Error("utilisation invalide de _update, utilisez save");
242
80
  }
243
81
 
82
+ if (payload.id) delete payload.id;
244
83
  let hasChanged = false;
245
84
 
246
-
247
- // Sinon, on fait les updates en blocs
248
85
  for (const [constant, methodName] of Organization.UPDATE_BLOCKS) {
249
86
  const blockData = this._extractChangedFieldsFromSchema(
250
87
  this.apiClient,
251
88
  constant,
252
- { ...payload, ...this.defaultFields},
89
+ { ...payload, ...this.defaultFields },
253
90
  () => this.initialDraftData,
254
91
  this.removeFields
255
92
  );
@@ -258,58 +95,100 @@ export class Organization {
258
95
  hasChanged = true;
259
96
  }
260
97
  }
261
-
98
+
262
99
  return hasChanged;
263
100
  }
264
101
 
265
- addOrganization(data = {}) {
102
+ async addOrganization(data = {}) {
266
103
  return this.callIsConnected(() => this.endpointApi.addOrganization(data));
267
104
  }
268
105
 
269
- _updateInitialDraftSnapshot() {
270
- this.#initialDraftData = JSON.parse(JSON.stringify(this.#draftData));
106
+
107
+ async getOrganizations() {
108
+ throw new Error("getOrganizations n'existe pas dans Organization");
271
109
  }
272
110
 
273
- hasChanges() {
274
- return JSON.stringify(this.#draftData) !== JSON.stringify(this.#initialDraftData);
111
+ async getProjects(data = {}) {
112
+ return super.getProjects(data);
275
113
  }
276
114
 
277
- defaultFields = {
278
- typeElement: this.getEntityType()
279
- };
115
+ async getEvents() {
116
+ throw new Error("getEvents pas encore implémenté dans Organization");
117
+ }
280
118
 
281
- removeFields = [
282
- "typeElement"
283
- ];
284
-
285
- // role = admin c'est bizarre car en faite c'est gérer dans links sur user et l'orga
286
- // links.members.${this.userId}.isAdmin === true
287
- transforms = {
288
- github: (val, full) => full?.socialNetwork?.github,
289
- gitlab: (val, full) => full?.socialNetwork?.gitlab,
290
- facebook: (val, full) => full?.socialNetwork?.facebook,
291
- twitter: (val, full) => full?.socialNetwork?.twitter,
292
- instagram: (val, full) => full?.socialNetwork?.instagram,
293
- diaspora: (val, full) => full?.socialNetwork?.diaspora,
294
- mastodon: (val, full) => full?.socialNetwork?.mastodon,
295
- telegram: (val, full) => full?.socialNetwork?.telegram,
296
- signal: (val, full) => full?.socialNetwork?.signal
297
- };
119
+ async getPois(data = {}) {
120
+ return super.getPois(data);
121
+ }
298
122
 
299
- async project(projectData = {}, ) {
300
- try {
301
- const project = new this.deps.Project(this, projectData, { User: this.deps.User, News: this.deps.News, EndpointApi : this.deps.EndpointApi });
302
- if (projectData.id || projectData.slug) {
303
- await project.get();
304
- }
305
- return project;
306
- } catch (error) {
307
- this.apiClient._logger.error(`[Api.${this.__entityTag}.project] Erreur lors de la création d'une instance project :`, error.message);
308
- throw error;
309
- }
123
+ async getBadgesIssuer(data = {}) {
124
+ return super.getBadgesIssuer(data);
310
125
  }
311
126
 
312
- }
127
+ async getNews(data = {}) {
128
+ return super.getNews(data);
129
+ }
130
+
131
+ async getSubscribers(data = {}) {
132
+ return super.getSubscribers(data);
133
+ }
134
+
135
+ /**
136
+ * Crée une instance de projet et récupère son profil si nécessaire.
137
+ *
138
+ * @param {Object} projectData - Les données nécessaires pour initialiser le projet.
139
+ * @returns {Promise<Project>} Une promesse qui résout l'objet Projet créé.
140
+ * @throws {Error} Si une erreur se produit lors de la création du projet.
141
+ */
142
+ async project(projectData = {}) {
143
+ // TODO: Vérifier si l'utilisateur est admin de l'organisation
144
+ return super.project(projectData);
145
+ }
146
+
147
+ /**
148
+ * Crée une instance de POI et la récupère si nécessaire.
149
+ *
150
+ * @param {Object} poiData - Les données nécessaires pour initialiser le POI.
151
+ * @returns {Promise<Poi>} Une promesse qui résout l'objet POI créé.
152
+ * @throws {Error} Si une erreur se produit lors de la création du POI.
153
+ */
154
+ async poi(poiData = {}) {
155
+ // TODO: Vérifier si l'utilisateur est admin de l'organisation
156
+ return super.poi(poiData);
157
+ }
158
+
159
+ /**
160
+ * Crée une instance d'événement et la récupère si nécessaire.
161
+ *
162
+ * @param {Object} eventData - Les données nécessaires pour initialiser l'événement.
163
+ * @returns {Promise<Event>} Une promesse qui résout l'objet Événement créé.
164
+ * @throws {Error} Si une erreur se produit lors de la création de l'événement.
165
+ */
166
+ async event(eventData = {}) {
167
+ // TODO: Vérifier si l'utilisateur est admin de l'organisation
168
+ return super.event(eventData);
169
+ }
170
+
171
+ /**
172
+ * Crée une instance de badge et la récupère si nécessaire.
173
+ *
174
+ * @param {Object} badgeData - Les données nécessaires pour initialiser le badge.
175
+ * @returns {Promise<Badge>} Une promesse qui résout l'objet Badge créé.
176
+ * @throws {Error} Si une erreur se produit lors de la création du badge.
177
+ */
178
+ async badge(badgeData = {}) {
179
+ // TODO: Vérifier si l'utilisateur est admin de l'organisation
180
+ return super.badge(badgeData);
181
+ }
313
182
 
314
- // Incorporation du mixin dans Organization
315
- Object.assign(Organization.prototype, UtilMixin, MutualEntityMixin, EntityMixin, NewsMixin, DraftStateMixin);
183
+ /**
184
+ * Crée une instance de news et la récupère si nécessaire.
185
+ *
186
+ * @param {Object} newsData - Les données nécessaires pour initialiser la news.
187
+ * @returns {Promise<News>} Une promesse qui résout l'objet News créé.
188
+ * @throws {Error} Si une erreur se produit lors de la création de la news.
189
+ */
190
+ async news(newsData = {}) {
191
+ return super.news(newsData);
192
+ }
193
+
194
+ }
package/src/api/Poi.js ADDED
@@ -0,0 +1,158 @@
1
+ import BaseEntity from "./BaseEntity.js";
2
+
3
+ export class Poi extends BaseEntity {
4
+ static entityType = "poi";
5
+
6
+ static SCHEMA_CONSTANTS = [
7
+ "ADD_POI",
8
+ "UPDATE_BLOCK_DESCRIPTION",
9
+ "UPDATE_BLOCK_INFO",
10
+ "UPDATE_BLOCK_LOCALITY",
11
+ "UPDATE_BLOCK_SLUG",
12
+ "PROFIL_IMAGE"
13
+ ];
14
+
15
+ static ADD_BLOCKS = new Map([
16
+ ["ADD_POI", "addPoi"],
17
+ ["PROFIL_IMAGE", "updateImageProfil"]
18
+ ]);
19
+
20
+ static UPDATE_BLOCKS = new Map([
21
+ ["UPDATE_BLOCK_DESCRIPTION", "updateDescription"],
22
+ ["UPDATE_BLOCK_LOCALITY", "updateLocality"],
23
+ ["UPDATE_BLOCK_INFO", "updateInfo"],
24
+ ["UPDATE_BLOCK_SLUG", "updateSlug"],
25
+ ["PROFIL_IMAGE", "updateImageProfil"]
26
+ ]);
27
+
28
+ defaultFields = {
29
+ typeElement: this.getEntityType()
30
+ };
31
+
32
+ removeFields = [
33
+ "typeElement"
34
+ ];
35
+
36
+ transforms = {
37
+
38
+ };
39
+
40
+ async _add(payload) {
41
+ if (!this._calledFromSave) {
42
+ throw new Error("utilisation invalide de _add, utilisez save");
43
+ }
44
+
45
+ payload.id = this._newId?.();
46
+ if (payload.slug) delete payload.slug;
47
+
48
+ for (const [constant, methodName] of Poi.ADD_BLOCKS) {
49
+ const blockData = this._extractChangedFieldsFromSchema(
50
+ this.apiClient,
51
+ constant,
52
+ { ...payload, ...this.defaultFields },
53
+ () => {}
54
+ );
55
+ if (blockData && Object.keys(blockData).length > 0) {
56
+ const data = await this[methodName](blockData);
57
+ if (!this.id && data?.map?.id) {
58
+ this._draftData.id = data.map.id;
59
+ this._draftData.slug = data.map.slug;
60
+ }
61
+ }
62
+ }
63
+ }
64
+
65
+ async _update(payload) {
66
+ if (!this._calledFromSave) {
67
+ throw new Error("utilisation invalide de _update, utilisez save");
68
+ }
69
+
70
+ if (payload.id) delete payload.id;
71
+ let hasChanged = false;
72
+
73
+ for (const [constant, methodName] of Poi.UPDATE_BLOCKS) {
74
+ const blockData = this._extractChangedFieldsFromSchema(
75
+ this.apiClient,
76
+ constant,
77
+ { ...payload, ...this.defaultFields },
78
+ () => this.initialDraftData,
79
+ this.removeFields
80
+ );
81
+ if (blockData && Object.keys(blockData).length > 0) {
82
+ await this[methodName](blockData);
83
+ hasChanged = true;
84
+ }
85
+ }
86
+
87
+ return hasChanged;
88
+ }
89
+
90
+ async addPoi(data = {}) {
91
+
92
+ if (!this.isMe) {
93
+ data.parent = {};
94
+ data.parent[`${this.parent.id}`] = {
95
+ type: this.parent.getEntityType(),
96
+ name: this.parent.name
97
+ };
98
+ }
99
+
100
+ return this.callIsConnected(() => this.endpointApi.addPoi(data));
101
+ }
102
+
103
+ async getOrganizations() {
104
+ throw new Error(`getOrganizations n'existe pas dans ${this.constructor.name}`);
105
+ }
106
+
107
+ async getProjects() {
108
+ throw new Error(`getProjects n'existe pas dans ${this.constructor.name}`);
109
+ }
110
+
111
+ async getEvents() {
112
+ throw new Error(`getEvents n'existe pas dans${this.constructor.name}`);
113
+ }
114
+
115
+ async getPois() {
116
+ throw new Error(`getPois n'existe pas dans ${this.constructor.name}`);
117
+ }
118
+
119
+ async getBadgesIssuer() {
120
+ throw new Error(`getBadgesIssuer n'existe pas dans ${this.constructor.name}`);
121
+ }
122
+
123
+ async getNews(data = {}) {
124
+ return super.getNews(data);
125
+ }
126
+
127
+ async getSubscribers(data = {}) {
128
+ return super.getSubscribers(data);
129
+ }
130
+
131
+ async project() {
132
+ throw new Error(`project n'existe pas dans ${this.constructor.name}`);
133
+ }
134
+
135
+ async poi() {
136
+ throw new Error(`poi n'existe pas dans ${this.constructor.name}`);
137
+ }
138
+
139
+ async event() {
140
+ throw new Error(`event n'existe pas dans ${this.constructor.name}`);
141
+ }
142
+
143
+ async badge() {
144
+ throw new Error(`badge n'existe pas dans ${this.constructor.name}`);
145
+ }
146
+
147
+ /**
148
+ * Crée une instance de news et la récupère si nécessaire.
149
+ *
150
+ * @param {Object} newsData - Les données nécessaires pour initialiser la news.
151
+ * @returns {Promise<News>} Une promesse qui résout l'objet News créé.
152
+ * @throws {Error} Si une erreur se produit lors de la création de la news.
153
+ */
154
+ async news(newsData = {}) {
155
+ return super.news(newsData);
156
+ }
157
+
158
+ }