@communecter/cocolight-api-client 1.0.20 → 1.0.22

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,3 +1,4 @@
1
+ import { ApiResponseError } from "../error.js";
1
2
  import BaseEntity from "./BaseEntity.js";
2
3
 
3
4
  export class Organization extends BaseEntity {
@@ -132,6 +133,82 @@ export class Organization extends BaseEntity {
132
133
  return super.getSubscribers(data);
133
134
  }
134
135
 
136
+ /**
137
+ * Récupérer les membres de l'organisation.
138
+ * Constant : GET_MEMBERS_ADMIN / GET_MEMBERS_NO_ADMIN
139
+ * @param {Object} data - Les données de requête.
140
+ * @param {Object} options - Options supplémentaires.
141
+ * @param {boolean} options.isAdmin - Indique si l'utilisateur est admin.
142
+ * @param {boolean} options.isInviting - Indique si l'utilisateur est en attente d'invitation.
143
+ * @param {Array} options.roles - Liste des rôles à filtrer.
144
+ * @returns {Promise<Object>} - Un objet contenant le nombre de membres et la liste des membres.
145
+ */
146
+ async getMembers(data = {}, options = {}) {
147
+ const { isAdmin, isInviting, roles = [] } = options;
148
+
149
+ if(this.isMe){
150
+ data.pathParams = { type: this.getEntityType(), id: this.id };
151
+ // NOTE : dans le schema je crois que si pas de data.filters alors le default ce fait avec data.pathParams
152
+ // data.filters = {
153
+ // [`links.memberOf.${this.id}`]: { "$exists": true },
154
+ // [`links.memberOf.${this.id}.toBeValidated`]: { "$exists": false },
155
+ // [`links.memberOf.${this.id}.isInviting`]: { "$exists": false }
156
+ // };
157
+ } else {
158
+ delete data?.pathParams;
159
+ data.filters = this._buildMemberFilters(this.id, { isAdmin, isInviting, roles });
160
+ }
161
+
162
+ const fetchFn = this.isMe
163
+ ? () => this.callIsMe(() => this.endpointApi.getMembersAdmin(data))
164
+ : () => this.endpointApi.getMembersNoAdmin(data);
165
+
166
+ const arrayObjet = await fetchFn();
167
+ if (!Array.isArray(arrayObjet.results)) {
168
+ throw new ApiResponseError("Erreur lors de la récupération des membres", 500, arrayObjet.results);
169
+ }
170
+
171
+ // lier les entités au objets
172
+ const rawList = this._linkEntities(arrayObjet.results);
173
+
174
+ return {
175
+ count: arrayObjet.count?.poi ?? 0,
176
+ results: rawList
177
+ };
178
+ }
179
+
180
+ _buildMemberFilters(id, { isAdmin, isInviting, roles }) {
181
+
182
+ if (typeof isAdmin !== "undefined" && typeof isAdmin !== "boolean") {
183
+ throw new TypeError("isAdmin doit être un booléen.");
184
+ }
185
+ if (typeof isInviting !== "undefined" && typeof isInviting !== "boolean") {
186
+ throw new TypeError("isInviting doit être un booléen.");
187
+ }
188
+ if (!Array.isArray(roles)) {
189
+ throw new TypeError("roles doit être un tableau de chaînes.");
190
+ }
191
+
192
+ const filters = {
193
+ [`links.memberOf.${id}`]: { $exists: true },
194
+ [`links.memberOf.${id}.toBeValidated`]: { $exists: false }
195
+ };
196
+
197
+ if (isInviting === true || isInviting === false) {
198
+ filters[`links.memberOf.${id}.isInviting`] = { $exists: isInviting };
199
+ }
200
+
201
+ if (isAdmin === true) {
202
+ filters[`links.memberOf.${id}.isAdmin`] = { $exists: true };
203
+ }
204
+
205
+ if (Array.isArray(roles) && roles.length > 0) {
206
+ filters[`links.memberOf.${id}.roles`] = { $in: roles };
207
+ }
208
+
209
+ return filters;
210
+ }
211
+
135
212
  /**
136
213
  * Crée une instance de projet et récupère son profil si nécessaire.
137
214
  *
package/src/api/User.js CHANGED
@@ -25,29 +25,14 @@ export class User extends BaseEntity {
25
25
  ["PROFIL_IMAGE", "updateImageProfil"]
26
26
  ]);
27
27
 
28
- /**
29
- * Champs par défaut pour les schemas json ou l'on extrait les fields. (pour les if/else/then)
30
- *
31
- * @property {Object} defaultFields - Un objet contenant les propriétés par défaut pour l'entité User.
32
- */
33
28
  defaultFields = {
34
29
  typeElement: this.getEntityType(),
35
30
  };
36
31
 
37
- /**
38
- * Champs à supprimer de draft lors de la construction du proxy.
39
- *
40
- * @property {Array<string>} removeFields - Un tableau de chaînes représentant les champs à supprimer.
41
- */
42
32
  removeFields = [
43
33
  "typeElement",
44
34
  ];
45
35
 
46
- /**
47
- * Transformateurs appliqués lors de la lecture du draft.
48
- *
49
- * @type {Object<string, function>}
50
- */
51
36
  transforms = {
52
37
  github: (val, full) => full?.socialNetwork?.github,
53
38
  gitlab: (val, full) => full?.socialNetwork?.gitlab,
@@ -95,8 +80,6 @@ export class User extends BaseEntity {
95
80
  if (!deps.News) throw new ApiError("News class must be injected.");
96
81
 
97
82
  super(parent, data, deps);
98
-
99
- // this.__entityTag = "User";
100
83
  }
101
84
 
102
85
  get slug() {
@@ -121,7 +104,7 @@ export class User extends BaseEntity {
121
104
  this._setData(data);
122
105
  return data;
123
106
  } else {
124
- const data = await this.getPublicProfile();
107
+ const data = await this._getPublicProfile();
125
108
  this._setData(data);
126
109
  return data;
127
110
  }
@@ -318,26 +301,24 @@ export class User extends BaseEntity {
318
301
  };
319
302
  }
320
303
 
321
- const arrayObjetOrganizations = await fetchFn();
304
+ const arrayObjet = await fetchFn();
322
305
 
323
- if (!Array.isArray(arrayObjetOrganizations.results)) {
324
- throw new ApiResponseError("Erreur lors de la récupération des organisations.", 500, arrayObjetOrganizations.results);
306
+ if (!Array.isArray(arrayObjet.results)) {
307
+ throw new ApiResponseError("Erreur lors de la récupération des organisations.", 500, arrayObjet.results);
325
308
  }
326
309
 
327
310
  // nettoyage du count
328
- delete arrayObjetOrganizations?.count?.spam;
311
+ delete arrayObjet?.count?.spam;
329
312
 
330
313
  // calcul du total
331
- const totalCount = Object.values(arrayObjetOrganizations.count || {}).reduce((acc, val) => acc + val, 0);
332
- arrayObjetOrganizations.count.total = totalCount;
314
+ const totalCount = Object.values(arrayObjet.count || {}).reduce((acc, val) => acc + val, 0);
315
+ arrayObjet.count.total = totalCount;
333
316
 
334
- const rawOrganizationsList = arrayObjetOrganizations.results.map(
335
- (d) => this.linkEntity?.(d.collection, d) ?? d
336
- );
317
+ const rawList = this._linkEntities(arrayObjet.results);
337
318
 
338
319
  return {
339
- count: arrayObjetOrganizations.count,
340
- results: rawOrganizationsList
320
+ count: arrayObjet.count,
321
+ results: rawList
341
322
  };
342
323
  }
343
324
 
@@ -379,19 +360,17 @@ export class User extends BaseEntity {
379
360
  data.pathParams = { id: this.id };
380
361
  }
381
362
 
382
- const arrayObjetFriends = await this.endpointApi.getFriendsAdmin(data);
383
- if(!Array.isArray(arrayObjetFriends.results)){
384
- throw new ApiResponseError("Erreur lors de la récupération des amis administrables.", 500, arrayObjetFriends);
363
+ const arrayObjet = await this.endpointApi.getFriendsAdmin(data);
364
+ if(!Array.isArray(arrayObjet.results)){
365
+ throw new ApiResponseError("Erreur lors de la récupération des amis administrables.", 500, arrayObjet);
385
366
 
386
367
  }
387
368
 
388
- const rawFriendsList = arrayObjetFriends.results.map(
389
- (d) => this.linkEntity?.(d.collection, d) ?? d
390
- );
369
+ const rawList = this._linkEntities(arrayObjet.results);
391
370
 
392
371
  return {
393
- count: arrayObjetFriends?.count?.citoyens ?? 0,
394
- results: rawFriendsList
372
+ count: arrayObjet?.count?.citoyens ?? 0,
373
+ results: rawList
395
374
  };
396
375
  }
397
376
 
@@ -412,19 +391,17 @@ export class User extends BaseEntity {
412
391
  };
413
392
  }
414
393
 
415
- const arrayObjetSubscriptions = await fetchFn();
416
- if (!Array.isArray(arrayObjetSubscriptions.results)) {
417
- throw new ApiResponseError("Erreur lors de la récupération des abonnements.", 500, arrayObjetSubscriptions.results);
394
+ const arrayObjet = await fetchFn();
395
+ if (!Array.isArray(arrayObjet.results)) {
396
+ throw new ApiResponseError("Erreur lors de la récupération des abonnements.", 500, arrayObjet.results);
418
397
  }
419
398
 
420
399
  // lier les entités au objets
421
- const rawSubscriptionsList = arrayObjetSubscriptions.results.map(
422
- (d) => this.linkEntity?.(d.collection, d) ?? d
423
- );
400
+ const rawList = this._linkEntities(arrayObjet.results);
424
401
 
425
402
  return {
426
- count: arrayObjetSubscriptions.count,
427
- results: rawSubscriptionsList
403
+ count: arrayObjet.count,
404
+ results: rawList
428
405
  };
429
406
  }
430
407
 
@@ -1,176 +0,0 @@
1
- // DraftStateMixin.js
2
- import { ApiError, ApiValidationError } from "../error.js";
3
-
4
- export const DraftStateMixin = {
5
-
6
- /**
7
- * Crée un proxy combinant draft + serveur, avec transformations facultatives.
8
- * @param {Object} server
9
- * @param {Object} draft
10
- * @param {Array} allowedFields - champs autorisés dans le draft
11
- * @param {Object} [transforms={}] - transformateurs de lecture
12
- * @param {Object} [options={}] - options
13
- * @returns {Proxy}
14
- */
15
- _createDraftProxy(apiClient, server = {}, draft = {}, allowedFields = [], transforms = {}, options = {}) {
16
- return new Proxy({}, {
17
- get: (_, prop) => {
18
- const val = prop in draft ? draft[prop] : server[prop];
19
- const transformer = transforms[prop];
20
- return typeof transformer === "function" ? transformer(val) : val;
21
- },
22
-
23
- set: (_, prop, value) => {
24
- if (!allowedFields.includes(prop)) {
25
- const message = `[DraftProxy] Le champ "${prop}" n'est pas autorisé.`;
26
- if (options.throwOnError) {
27
- throw new ApiValidationError(message, 400, null, {
28
- field: prop,
29
- value,
30
- allowedFields
31
- });
32
- }
33
- apiClient._logger.warn(message);
34
- return false;
35
- }
36
- draft[prop] = value;
37
- return true;
38
- },
39
-
40
- deleteProperty: (_, prop) => {
41
- if (!allowedFields.includes(prop)) return false;
42
- delete draft[prop];
43
- return true;
44
- },
45
-
46
- has: (_, prop) => prop in draft || prop in server,
47
- ownKeys: () => [...new Set([...Object.keys(server), ...Object.keys(draft)])],
48
- getOwnPropertyDescriptor: () => ({ enumerable: true, configurable: true })
49
- });
50
- },
51
-
52
- _extractWritableFields(schema = {}, data = {}, ctx = { defs: {}, visited: new Set() }) {
53
- if (!schema || typeof schema !== "object") return [];
54
- if (schema.$id && ctx.visited.has(schema.$id)) return [];
55
- if (schema.$id) ctx.visited.add(schema.$id);
56
- ctx.defs = schema.$defs || schema.definitions || ctx.defs;
57
-
58
- const fields = [];
59
-
60
- if (schema.$ref) {
61
- const refKey = schema.$ref.replace(/^#\/?(\$defs|definitions)\//, "");
62
- const resolved = ctx.defs?.[refKey];
63
- if (resolved) fields.push(...this._extractWritableFields(resolved, data, ctx));
64
- }
65
-
66
- if (schema.allOf) {
67
- schema.allOf.forEach(s => fields.push(...this._extractWritableFields(s, data, ctx)));
68
- }
69
-
70
- if (schema.if && schema.then) {
71
- const condition = schema.if?.properties;
72
- let matches = true;
73
- if (condition) {
74
- for (const key in condition) {
75
- const expected = condition[key]?.const;
76
- if (data[key] !== expected) {
77
- matches = false;
78
- break;
79
- }
80
- }
81
- }
82
- if (matches && schema.then) {
83
- fields.push(...this._extractWritableFields(schema.then, data, ctx));
84
- } else if (!matches && schema.else) {
85
- fields.push(...this._extractWritableFields(schema.else, data, ctx));
86
- }
87
- }
88
-
89
- if (schema.properties) {
90
- fields.push(...Object.entries(schema.properties)
91
- // eslint-disable-next-line no-unused-vars
92
- .filter(([_, def]) => def.readOnly !== true && def.const === undefined)
93
- .map(([key]) => key));
94
- }
95
-
96
- return [...new Set(fields)];
97
- },
98
-
99
- _buildDraftAndProxy({ data = {}, serverData = null, constant, apiClient, transforms = {}, throwOnError = true, removeFields = [] }) {
100
- const constants = Array.isArray(constant) ? constant : [constant];
101
- const combinedSchema = {
102
- allOf: [],
103
- $defs: {}
104
- };
105
-
106
- for (const key of constants) {
107
- const sch = apiClient.getRequestSchema(key);
108
- if (!sch) throw new ApiError(`Unable to find schema for ${key}.`);
109
-
110
- // Extraire et fusionner les $defs
111
- if (sch.$defs) {
112
- for (const [defKey, defVal] of Object.entries(sch.$defs)) {
113
- if (combinedSchema.$defs[defKey]) {
114
- apiClient._logger.warn(`Duplicate $defs key '${defKey}' from schema '${key}'`);
115
- } else {
116
- combinedSchema.$defs[defKey] = defVal;
117
- }
118
- }
119
- }
120
-
121
- combinedSchema.allOf.push(sch);
122
- }
123
- const draft = {};
124
- let allowed = this._extractWritableFields(combinedSchema, data);
125
-
126
- if (data.id && allowed.indexOf("id") === -1) {
127
- allowed.push("id");
128
- }
129
- if (data.slug && allowed.indexOf("slug") === -1) {
130
- allowed.push("slug");
131
- }
132
-
133
- allowed = allowed.filter(k => !removeFields.includes(k));
134
-
135
- for (const key of allowed) {
136
- const raw = data[key];
137
- const transformed = typeof transforms[key] === "function" ? transforms[key](raw, data) : raw;
138
- if (transformed !== undefined) draft[key] = transformed;
139
- }
140
-
141
- const proxy = this._createDraftProxy(apiClient, serverData, draft, allowed, transforms, { throwOnError });
142
-
143
- return { draft, proxy };
144
- },
145
-
146
- _extractChangedFieldsFromSchema(apiClient, constant, data = {}, getInitialDraft, removeFields = []) {
147
- const schema = apiClient.getRequestSchema(constant);
148
- let allowed = this._extractWritableFields(schema, data);
149
- const changed = {};
150
- const initialDraft = getInitialDraft?.() || {};
151
-
152
- // on enlève les champs qui ne sont pas dans le draft
153
- // ou qui sont dans removeFields
154
- allowed = allowed.filter(k => !removeFields.includes(k));
155
-
156
- for (const key of allowed) {
157
- // on verifie que le champ existe dans le draft
158
- // sinon on ne le prend pas en compte
159
-
160
- if (data[key] === undefined) continue;
161
-
162
- const current = data[key];
163
- const initial = initialDraft[key];
164
-
165
- const changedValue =
166
- JSON.stringify(current) !== JSON.stringify(initial);
167
-
168
- if (changedValue) {
169
- changed[key] = current;
170
- }
171
- }
172
-
173
- return Object.keys(changed).length > 0 ? changed : null;
174
- }
175
-
176
- };