@communecter/cocolight-api-client 1.0.22 → 1.0.24

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.
@@ -792,17 +792,17 @@ class EndpointApi {
792
792
 
793
793
  /**
794
794
  * Récupérer les contributeurs non administrables : Récupère les contributeurs sans droits d’admin.
795
- * Constant : GET_CONTRIBUTORS
796
- * @param {import("./EndpointApi.types").GetContributorsData} data - Données envoyées à l'API
795
+ * Constant : GET_CONTRIBUTORS_NO_ADMIN
796
+ * @param {import("./EndpointApi.types").GetContributorsNoAdminData} data - Données envoyées à l'API
797
797
  * @returns {Promise<Object>} - Les données de réponse.
798
798
  * @throws {ApiResponseError} - En cas d'erreur détectée dans la réponse.
799
799
  * @throws {Error} - En cas d'erreur inattendue.
800
800
  */
801
- async getContributors(data) {
801
+ async getContributorsNoAdmin(data) {
802
802
  if (!data || typeof data !== "object") {
803
803
  throw new TypeError("Le paramètre data doit être un objet.");
804
804
  }
805
- return this.call("GET_CONTRIBUTORS", data);
805
+ return this.call("GET_CONTRIBUTORS_NO_ADMIN", data);
806
806
  }
807
807
 
808
808
  /**
@@ -1332,6 +1332,22 @@ class EndpointApi {
1332
1332
  return this.callIsConnected("INVITE_EVENT", data);
1333
1333
  }
1334
1334
 
1335
+ /**
1336
+ * Suivre un utilisateur ou un élément : Suivre un utilisateur ou un élément.
1337
+ * Constant : FOLLOW
1338
+ * @param {import("./EndpointApi.types").FollowData} data - Données envoyées à l'API
1339
+ * @returns {Promise<Object>} - Les données de réponse.
1340
+ * @throws {ApiResponseError} - En cas d'erreur détectée dans la réponse.
1341
+ * @throws {ApiAuthenticationError} - En cas d'erreur d'authentification.
1342
+ * @throws {Error} - En cas d'erreur inattendue.
1343
+ */
1344
+ async follow(data) {
1345
+ if (!data || typeof data !== "object") {
1346
+ throw new TypeError("Le paramètre data doit être un objet.");
1347
+ }
1348
+ return this.callIsConnected("FOLLOW", data);
1349
+ }
1350
+
1335
1351
  }
1336
1352
 
1337
1353
  export default EndpointApi;
@@ -1809,7 +1809,7 @@ export interface GetSubscribersAdminData {
1809
1809
  }
1810
1810
 
1811
1811
 
1812
- export interface GetContributorsData {
1812
+ export interface GetContributorsNoAdminData {
1813
1813
  /**
1814
1814
  * Nom ou terme recherché
1815
1815
  */
@@ -2116,7 +2116,7 @@ export interface DisconnectData {
2116
2116
  /**
2117
2117
  * Type de connexion
2118
2118
  */
2119
- connectType: "admin" | "member" | "contributor" | "attendee" | "friend";
2119
+ connectType: "members" | "contributors" | "attendees" | "friends" | "followers";
2120
2120
  [k: string]: unknown;
2121
2121
  }
2122
2122
 
@@ -3461,3 +3461,24 @@ export interface InviteEventData {
3461
3461
  };
3462
3462
  [k: string]: unknown;
3463
3463
  }
3464
+
3465
+
3466
+ export interface FollowData {
3467
+ /**
3468
+ * ID de l'élément à suivre (projet, organisation...)
3469
+ */
3470
+ childId: string;
3471
+ /**
3472
+ * Type de l'élément à suivre
3473
+ */
3474
+ childType: "citoyens";
3475
+ /**
3476
+ * Type de l'élément parent (projet, organisation...)
3477
+ */
3478
+ parentType: "citoyens" | "organizations" | "projects" | "events";
3479
+ /**
3480
+ * ID de l'élément parent
3481
+ */
3482
+ parentId: string;
3483
+ [k: string]: unknown;
3484
+ }
package/src/api/Event.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { ApiError } from "../error.js";
1
2
  import BaseEntity from "./BaseEntity.js";
2
3
 
3
4
  export class Event extends BaseEntity {
@@ -38,7 +39,7 @@ export class Event extends BaseEntity {
38
39
 
39
40
  async _add(payload) {
40
41
  if (!this._calledFromSave) {
41
- throw new Error("utilisation invalide de _add, utilisez save");
42
+ throw new ApiError("utilisation invalide de _add, utilisez save");
42
43
  }
43
44
 
44
45
  payload.id = this._newId?.();
@@ -62,8 +63,12 @@ export class Event extends BaseEntity {
62
63
  }
63
64
 
64
65
  async _update(payload) {
66
+ if(!this.isAdmin()){
67
+ throw new ApiError("Vous n'avez pas les droits pour modifier cet événement", 403);
68
+ }
69
+
65
70
  if (!this._calledFromSave) {
66
- throw new Error("utilisation invalide de _update, utilisez save");
71
+ throw new ApiError("utilisation invalide de _update, utilisez save");
67
72
  }
68
73
 
69
74
  if (payload.id) delete payload.id;
@@ -87,23 +92,23 @@ export class Event extends BaseEntity {
87
92
  }
88
93
 
89
94
  async getOrganizations() {
90
- throw new Error(`getOrganizations n'existe pas dans ${this.constructor.name}`);
95
+ throw new ApiError(`getOrganizations n'existe pas dans ${this.constructor.name}`);
91
96
  }
92
97
 
93
98
  async getProjects() {
94
- throw new Error(`getProjects n'existe pas dans ${this.constructor.name}`);
99
+ throw new ApiError(`getProjects n'existe pas dans ${this.constructor.name}`);
95
100
  }
96
101
 
97
102
  async getEvents() {
98
- throw new Error(`getEvents - les sous-events ne sont pas encore implémentés dans ${this.constructor.name}`);
103
+ throw new ApiError(`getEvents - les sous-events ne sont pas encore implémentés dans ${this.constructor.name}`);
99
104
  }
100
105
 
101
106
  async getPois() {
102
- throw new Error(`getPois n'existe pas dans ${this.constructor.name}`);
107
+ throw new ApiError(`getPois n'existe pas dans ${this.constructor.name}`);
103
108
  }
104
109
 
105
110
  async getBadgesIssuer() {
106
- throw new Error(`getBadgesIssuer n'existe pas dans ${this.constructor.name}`);
111
+ throw new ApiError(`getBadgesIssuer n'existe pas dans ${this.constructor.name}`);
107
112
  }
108
113
 
109
114
  async getNews(data = {}) {
@@ -115,19 +120,19 @@ export class Event extends BaseEntity {
115
120
  }
116
121
 
117
122
  async project() {
118
- throw new Error(`project n'existe pas dans ${this.constructor.name}`);
123
+ throw new ApiError(`project n'existe pas dans ${this.constructor.name}`);
119
124
  }
120
125
 
121
126
  async poi() {
122
- throw new Error(`poi n'existe pas dans ${this.constructor.name}`);
127
+ throw new ApiError(`poi n'existe pas dans ${this.constructor.name}`);
123
128
  }
124
129
 
125
130
  async event() {
126
- throw new Error(`les sous-events ne sont pas encore implémentés dans ${this.constructor.name}`);
131
+ throw new ApiError(`les sous-events ne sont pas encore implémentés dans ${this.constructor.name}`);
127
132
  }
128
133
 
129
134
  async badge() {
130
- throw new Error(`badge n'existe pas dans ${this.constructor.name}`);
135
+ throw new ApiError(`badge n'existe pas dans ${this.constructor.name}`);
131
136
  }
132
137
 
133
138
  /**
@@ -141,4 +146,26 @@ export class Event extends BaseEntity {
141
146
  return super.news(newsData);
142
147
  }
143
148
 
149
+ /**
150
+ * Suivre un événement.
151
+ * Cette action permet à l'utilisateur de suivre un événement.
152
+ *
153
+ * @returns {Promise<Object>} - Résultat de l'action de suivi.
154
+ * @throws {ApiError} - Si l'utilisateur n'est pas connecté ou si l'entité ne supporte pas l'action.
155
+ */
156
+ async follow() {
157
+ return super.follow();
158
+ }
159
+
160
+ /**
161
+ * Se désabonne d'un événement.
162
+ *
163
+ * @returns {Promise<Object>} - Résultat de la désinscription.
164
+ * @throws {ApiError} - Si l'utilisateur n'est pas connecté ou si l'entité n'est pas enregistrée.
165
+ */
166
+ async unfollow() {
167
+ return super.unfollow();
168
+ }
169
+
170
+
144
171
  }
@@ -1,4 +1,4 @@
1
- import { ApiResponseError } from "../error.js";
1
+ import { ApiError, ApiResponseError } from "../error.js";
2
2
  import BaseEntity from "./BaseEntity.js";
3
3
 
4
4
  export class Organization extends BaseEntity {
@@ -52,7 +52,7 @@ export class Organization extends BaseEntity {
52
52
 
53
53
  async _add(payload) {
54
54
  if (!this._calledFromSave) {
55
- throw new Error("utilisation invalide de _add, utilisez save");
55
+ throw new ApiError("utilisation invalide de _add, utilisez save");
56
56
  }
57
57
 
58
58
  payload.id = this._newId?.();
@@ -76,8 +76,12 @@ export class Organization extends BaseEntity {
76
76
  }
77
77
 
78
78
  async _update(payload) {
79
+ if(!this.isAdmin()){
80
+ throw new ApiError("Vous n'avez pas les droits pour modifier cette organisation", 403);
81
+ }
82
+
79
83
  if (!this._calledFromSave) {
80
- throw new Error("utilisation invalide de _update, utilisez save");
84
+ throw new ApiError("utilisation invalide de _update, utilisez save");
81
85
  }
82
86
 
83
87
  if (payload.id) delete payload.id;
@@ -106,7 +110,7 @@ export class Organization extends BaseEntity {
106
110
 
107
111
 
108
112
  async getOrganizations() {
109
- throw new Error("getOrganizations n'existe pas dans Organization");
113
+ throw new ApiError("getOrganizations n'existe pas dans Organization");
110
114
  }
111
115
 
112
116
  async getProjects(data = {}) {
@@ -114,7 +118,7 @@ export class Organization extends BaseEntity {
114
118
  }
115
119
 
116
120
  async getEvents() {
117
- throw new Error("getEvents pas encore implémenté dans Organization");
121
+ throw new ApiError("getEvents pas encore implémenté dans Organization");
118
122
  }
119
123
 
120
124
  async getPois(data = {}) {
@@ -138,25 +142,55 @@ export class Organization extends BaseEntity {
138
142
  * Constant : GET_MEMBERS_ADMIN / GET_MEMBERS_NO_ADMIN
139
143
  * @param {Object} data - Les données de requête.
140
144
  * @param {Object} options - Options supplémentaires.
145
+ * @param {boolean} options.toBeValidated - Indique si les membres doivent être validés.
141
146
  * @param {boolean} options.isAdmin - Indique si l'utilisateur est admin.
147
+ * @param {boolean} options.isAdminPending - Indique si l'utilisateur est en attente de validation pour être admin.
142
148
  * @param {boolean} options.isInviting - Indique si l'utilisateur est en attente d'invitation.
143
149
  * @param {Array} options.roles - Liste des rôles à filtrer.
144
150
  * @returns {Promise<Object>} - Un objet contenant le nombre de membres et la liste des membres.
151
+ * @throws {ApiResponseError} - Si une erreur se produit lors de la récupération des contributeurs.
152
+ *
153
+ * @example
154
+ * // Récupérer tous les membres
155
+ * const members = await organization.getMembers();
156
+ *
157
+ * // Récupérer les membres avec validation en attente
158
+ * const membersToBeValidated = await organization.getMembers({}, { toBeValidated: true });
159
+ *
160
+ * // Récupérer les membres avec un rôle spécifique
161
+ * const membersWithRole = await organization.getMembers({}, { roles: ['admin'] });
162
+ *
163
+ * // Récupérer les membres en attente d'invitation
164
+ * const invitingMembers = await organization.getMembers({}, { isInviting: true });
165
+ *
166
+ * // Récupérer les membres admin
167
+ * const adminMembers = await organization.getMembers({}, { isAdmin: true });
168
+ *
169
+ * // Récupérer les membres admin et en attente d'invitation
170
+ * const adminInvitingMembers = await organization.getMembers({}, { isAdmin: true, isInviting: true });
171
+ *
172
+ * // Récupérer les membres avec validation en attente et admin
173
+ * const adminToBeValidatedMembers = await organization.getMembers({}, { toBeValidated: true, isAdmin: true });
174
+ *
175
+ * // Récupérer les membres en attente de validation pour être admin
176
+ * const adminPendingMembers = await organization.getMembers({}, { isAdminPending: true });
177
+ *
178
+ *
145
179
  */
146
180
  async getMembers(data = {}, options = {}) {
147
- const { isAdmin, isInviting, roles = [] } = options;
181
+ const { toBeValidated, isAdmin, isAdminPending, isInviting, roles = [] } = options;
148
182
 
149
183
  if(this.isMe){
150
184
  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
185
  // data.filters = {
153
186
  // [`links.memberOf.${this.id}`]: { "$exists": true },
154
187
  // [`links.memberOf.${this.id}.toBeValidated`]: { "$exists": false },
155
188
  // [`links.memberOf.${this.id}.isInviting`]: { "$exists": false }
156
189
  // };
190
+ data.filters = this._buildLinkFilters(this.id, { linkType: "memberOf", toBeValidated, isAdmin, isAdminPending, isInviting, roles });
157
191
  } else {
158
192
  delete data?.pathParams;
159
- data.filters = this._buildMemberFilters(this.id, { isAdmin, isInviting, roles });
193
+ data.filters = this._buildLinkFilters(this.id, { linkType: "memberOf", toBeValidated: "false", isAdmin, isInviting, roles });
160
194
  }
161
195
 
162
196
  const fetchFn = this.isMe
@@ -172,43 +206,11 @@ export class Organization extends BaseEntity {
172
206
  const rawList = this._linkEntities(arrayObjet.results);
173
207
 
174
208
  return {
175
- count: arrayObjet.count?.poi ?? 0,
209
+ count: arrayObjet.count,
176
210
  results: rawList
177
211
  };
178
212
  }
179
213
 
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
-
212
214
  /**
213
215
  * Crée une instance de projet et récupère son profil si nécessaire.
214
216
  *
@@ -217,7 +219,9 @@ export class Organization extends BaseEntity {
217
219
  * @throws {Error} Si une erreur se produit lors de la création du projet.
218
220
  */
219
221
  async project(projectData = {}) {
220
- // TODO: Vérifier si l'utilisateur est admin de l'organisation
222
+ if(!this.isAdmin()){
223
+ throw new ApiError("Vous n'avez pas les droits pour créer un projet dans cette organisation", 403);
224
+ }
221
225
  return super.project(projectData);
222
226
  }
223
227
 
@@ -229,7 +233,9 @@ export class Organization extends BaseEntity {
229
233
  * @throws {Error} Si une erreur se produit lors de la création du POI.
230
234
  */
231
235
  async poi(poiData = {}) {
232
- // TODO: Vérifier si l'utilisateur est admin de l'organisation
236
+ if(!this.isAdmin()){
237
+ throw new ApiError("Vous n'avez pas les droits pour créer un projet dans cette organisation", 403);
238
+ }
233
239
  return super.poi(poiData);
234
240
  }
235
241
 
@@ -241,7 +247,9 @@ export class Organization extends BaseEntity {
241
247
  * @throws {Error} Si une erreur se produit lors de la création de l'événement.
242
248
  */
243
249
  async event(eventData = {}) {
244
- // TODO: Vérifier si l'utilisateur est admin de l'organisation
250
+ if(!this.isAdmin()){
251
+ throw new ApiError("Vous n'avez pas les droits pour créer un projet dans cette organisation", 403);
252
+ }
245
253
  return super.event(eventData);
246
254
  }
247
255
 
@@ -253,7 +261,9 @@ export class Organization extends BaseEntity {
253
261
  * @throws {Error} Si une erreur se produit lors de la création du badge.
254
262
  */
255
263
  async badge(badgeData = {}) {
256
- // TODO: Vérifier si l'utilisateur est admin de l'organisation
264
+ if(!this.isAdmin()){
265
+ throw new ApiError("Vous n'avez pas les droits pour créer un projet dans cette organisation", 403);
266
+ }
257
267
  return super.badge(badgeData);
258
268
  }
259
269
 
@@ -265,7 +275,81 @@ export class Organization extends BaseEntity {
265
275
  * @throws {Error} Si une erreur se produit lors de la création de la news.
266
276
  */
267
277
  async news(newsData = {}) {
278
+ // TODO: qui peut créer une news sur l'organisation ?
268
279
  return super.news(newsData);
269
280
  }
281
+
282
+ /**
283
+ * ───────────────────────────────
284
+ * Lien utilisateur ↔ organisation
285
+ * (rejoindre, valider, quitter, devenir admin)
286
+ * ───────────────────────────────
287
+ */
288
+
289
+
290
+ /**
291
+ * Envoie une demande pour rejoindre l'organisation en tant que membre.
292
+ * L'action est soumise à validation par un administrateur de l'organisation.
293
+ *
294
+ * @returns {Promise<Object>} - Résultat de la requête d'adhésion.
295
+ * @throws {ApiError} - Si l'utilisateur n'est pas connecté ou si l'entité ne supporte pas l'action.
296
+ */
297
+ async requestToJoin(){
298
+ return super.requestToJoin();
299
+ }
300
+
301
+ /**
302
+ * Envoie une demande pour rejoindre l'organisation en tant qu'administrateur.
303
+ * L'action est soumise à validation par un administrateur existant.
304
+ *
305
+ * @returns {Promise<Object>} - Résultat de la requête d'administration.
306
+ * @throws {ApiError} - Si l'utilisateur n'est pas connecté ou si l'entité ne supporte pas l'action.
307
+ */
308
+ async requestToJoinAdmin(){
309
+ return super.requestToJoinAdmin();
310
+ }
311
+
312
+ /**
313
+ * Accepte une invitation à rejoindre l'organisation.
314
+ * Cette action valide un lien en attente avec l'option `isInviting`.
315
+ *
316
+ * @returns {Promise<Object>} - Résultat de la validation du lien.
317
+ * @throws {ApiError} - Si aucune invitation n'est en attente ou si l'entité ne supporte pas l'action.
318
+ */
319
+ async acceptInvitation(){
320
+ return super.acceptInvitation();
321
+ }
322
+
323
+ /**
324
+ * Quitte l'organisation, que ce soit en tant que membre ou administrateur.
325
+ * Cette action supprime le lien entre l'utilisateur et l'organisation.
326
+ *
327
+ * @returns {Promise<Object>} - Résultat de la déconnexion.
328
+ * @throws {ApiError} - Si l'utilisateur n'est pas connecté ou non membre.
329
+ */
330
+ async leave() {
331
+ return super.leave();
332
+ }
333
+
334
+ /**
335
+ * Suivre une organisation.
336
+ * Cette action permet à l'utilisateur de suivre l'organisation.
337
+ *
338
+ * @returns {Promise<Object>} - Résultat de l'action de suivi.
339
+ * @throws {ApiError} - Si l'utilisateur n'est pas connecté ou si l'entité ne supporte pas l'action.
340
+ */
341
+ async follow() {
342
+ return super.follow();
343
+ }
344
+
345
+ /**
346
+ * Se désabonne d'une organisation.
347
+ *
348
+ * @returns {Promise<Object>} - Résultat de la désinscription.
349
+ * @throws {ApiError} - Si l'utilisateur n'est pas connecté ou si l'entité n'est pas enregistrée.
350
+ */
351
+ async unfollow() {
352
+ return super.unfollow();
353
+ }
270
354
 
271
355
  }
package/src/api/Poi.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { ApiError } from "../error.js";
1
2
  import BaseEntity from "./BaseEntity.js";
2
3
 
3
4
  export class Poi extends BaseEntity {
@@ -39,7 +40,7 @@ export class Poi extends BaseEntity {
39
40
 
40
41
  async _add(payload) {
41
42
  if (!this._calledFromSave) {
42
- throw new Error("utilisation invalide de _add, utilisez save");
43
+ throw new ApiError("utilisation invalide de _add, utilisez save");
43
44
  }
44
45
 
45
46
  payload.id = this._newId?.();
@@ -63,8 +64,11 @@ export class Poi extends BaseEntity {
63
64
  }
64
65
 
65
66
  async _update(payload) {
67
+ if(!this.isAuthor()){
68
+ throw new ApiError("Vous n'avez pas les droits pour modifier ce POI", 403);
69
+ }
66
70
  if (!this._calledFromSave) {
67
- throw new Error("utilisation invalide de _update, utilisez save");
71
+ throw new ApiError("utilisation invalide de _update, utilisez save");
68
72
  }
69
73
 
70
74
  if (payload.id) delete payload.id;
@@ -101,23 +105,23 @@ export class Poi extends BaseEntity {
101
105
  }
102
106
 
103
107
  async getOrganizations() {
104
- throw new Error(`getOrganizations n'existe pas dans ${this.constructor.name}`);
108
+ throw new ApiError(`getOrganizations n'existe pas dans ${this.constructor.name}`);
105
109
  }
106
110
 
107
111
  async getProjects() {
108
- throw new Error(`getProjects n'existe pas dans ${this.constructor.name}`);
112
+ throw new ApiError(`getProjects n'existe pas dans ${this.constructor.name}`);
109
113
  }
110
114
 
111
115
  async getEvents() {
112
- throw new Error(`getEvents n'existe pas dans${this.constructor.name}`);
116
+ throw new ApiError(`getEvents n'existe pas dans${this.constructor.name}`);
113
117
  }
114
118
 
115
119
  async getPois() {
116
- throw new Error(`getPois n'existe pas dans ${this.constructor.name}`);
120
+ throw new ApiError(`getPois n'existe pas dans ${this.constructor.name}`);
117
121
  }
118
122
 
119
123
  async getBadgesIssuer() {
120
- throw new Error(`getBadgesIssuer n'existe pas dans ${this.constructor.name}`);
124
+ throw new ApiError(`getBadgesIssuer n'existe pas dans ${this.constructor.name}`);
121
125
  }
122
126
 
123
127
  async getNews(data = {}) {
@@ -129,19 +133,19 @@ export class Poi extends BaseEntity {
129
133
  }
130
134
 
131
135
  async project() {
132
- throw new Error(`project n'existe pas dans ${this.constructor.name}`);
136
+ throw new ApiError(`project n'existe pas dans ${this.constructor.name}`);
133
137
  }
134
138
 
135
139
  async poi() {
136
- throw new Error(`poi n'existe pas dans ${this.constructor.name}`);
140
+ throw new ApiError(`poi n'existe pas dans ${this.constructor.name}`);
137
141
  }
138
142
 
139
143
  async event() {
140
- throw new Error(`event n'existe pas dans ${this.constructor.name}`);
144
+ throw new ApiError(`event n'existe pas dans ${this.constructor.name}`);
141
145
  }
142
146
 
143
147
  async badge() {
144
- throw new Error(`badge n'existe pas dans ${this.constructor.name}`);
148
+ throw new ApiError(`badge n'existe pas dans ${this.constructor.name}`);
145
149
  }
146
150
 
147
151
  /**
@@ -149,10 +153,32 @@ export class Poi extends BaseEntity {
149
153
  *
150
154
  * @param {Object} newsData - Les données nécessaires pour initialiser la news.
151
155
  * @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.
156
+ * @throws {ApiError} Si une erreur se produit lors de la création de la news.
153
157
  */
154
158
  async news(newsData = {}) {
155
159
  return super.news(newsData);
156
160
  }
161
+
162
+ /**
163
+ * Suivre un POI.
164
+ * Cette action permet à l'utilisateur de suivre un POI.
165
+ *
166
+ * @returns {Promise<Object>} - Résultat de l'action de suivi.
167
+ * @throws {ApiError} - Si l'utilisateur n'est pas connecté ou si l'entité ne supporte pas l'action.
168
+ */
169
+ async follow() {
170
+ return super.follow();
171
+ }
172
+
173
+ /**
174
+ * Se désabonne d'un POI.
175
+ *
176
+ * @returns {Promise<Object>} - Résultat de la désinscription.
177
+ * @throws {ApiError} - Si l'utilisateur n'est pas connecté ou si l'entité n'est pas enregistrée.
178
+ */
179
+ async unfollow() {
180
+ return super.unfollow();
181
+ }
182
+
157
183
 
158
184
  }