@communecter/cocolight-api-client 1.0.81 → 1.0.83
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.
- package/dist/cocolight-api-client.browser.js +2 -2
- package/dist/cocolight-api-client.cjs +1 -1
- package/dist/cocolight-api-client.mjs.js +1 -1
- package/dist/cocolight-api-client.vite.mjs.js +1 -1
- package/dist/cocolight-api-client.vite.mjs.js.map +1 -1
- package/package.json +1 -1
- package/src/api/BaseEntity.ts +57 -24
- package/src/api/User.ts +128 -117
- package/types/api/BaseEntity.d.ts +33 -1
- package/types/api/User.d.ts +30 -25
package/package.json
CHANGED
package/src/api/BaseEntity.ts
CHANGED
|
@@ -3209,6 +3209,63 @@ export class BaseEntity<TServerData = any> {
|
|
|
3209
3209
|
return arrayObjet as Record<string, any>;
|
|
3210
3210
|
}
|
|
3211
3211
|
|
|
3212
|
+
|
|
3213
|
+
/**
|
|
3214
|
+
* Recherche des membres (utilisateurs ou organisations) liés à l'entité courante.
|
|
3215
|
+
*
|
|
3216
|
+
* Cette méthode effectue une recherche par autocomplétion parmi les membres de l'entité
|
|
3217
|
+
* (organisation, projet, événement). Les résultats sont filtrés selon le mode de recherche
|
|
3218
|
+
* et retournés sous forme d'entités User ou Organization liées à l'entité parente.
|
|
3219
|
+
*
|
|
3220
|
+
* @param {SearchMemberAutocompleteData} data - Paramètres de recherche
|
|
3221
|
+
* @param {string} data.search - Terme recherché (nom, slug, etc.)
|
|
3222
|
+
* @param {"personOnly" | "organizationOnly" | "mixte"} data.searchMode - Mode de recherche :
|
|
3223
|
+
* - `"personOnly"` : recherche uniquement parmi les utilisateurs
|
|
3224
|
+
* - `"organizationOnly"` : recherche uniquement parmi les organisations
|
|
3225
|
+
* - `"mixte"` : recherche parmi les utilisateurs et organisations
|
|
3226
|
+
* @returns {Promise<(User | Organization)[]>} Liste des entités correspondantes, liées à l'entité parente
|
|
3227
|
+
* @throws {ApiError} Si le type d'entité n'est pas supporté (badges, news, poi, comments)
|
|
3228
|
+
*
|
|
3229
|
+
* @example
|
|
3230
|
+
* ```typescript
|
|
3231
|
+
* // Rechercher des utilisateurs dans une organisation
|
|
3232
|
+
* const org = await me.organization({ slug: "myOrg" });
|
|
3233
|
+
* const users = await org.searchMembers({ search: "jean", searchMode: "personOnly" });
|
|
3234
|
+
* users.forEach(user => console.log(user.data.name));
|
|
3235
|
+
*
|
|
3236
|
+
* // Rechercher des organisations membres d'un projet
|
|
3237
|
+
* const project = await me.project({ slug: "myProject" });
|
|
3238
|
+
* const orgs = await project.searchMembers({ search: "asso", searchMode: "organizationOnly" });
|
|
3239
|
+
* ```
|
|
3240
|
+
*
|
|
3241
|
+
* @remarks
|
|
3242
|
+
* Les entités retournées sont automatiquement liées à l'entité parente via `_linkEntities`,
|
|
3243
|
+
* ce qui permet d'utiliser les méthodes comme `sendRequestToJoinParent()`, `isAdminPending()`, etc.
|
|
3244
|
+
*/
|
|
3245
|
+
async searchMembers(data: SearchMemberAutocompleteData): Promise<(User | Organization)[]> {
|
|
3246
|
+
// TODO: j'ai l'impression que searchMode : "organizationOnly" ne renvois pas que des organisations
|
|
3247
|
+
const result = await this.endpointApi.searchMemberAutocomplete(data);
|
|
3248
|
+
if (!result || !Array.isArray(result)) {
|
|
3249
|
+
return [];
|
|
3250
|
+
}
|
|
3251
|
+
|
|
3252
|
+
const t = this.getEntityType();
|
|
3253
|
+
if (t === "badges" || t === "news" || t === "poi" || t === "comments") {
|
|
3254
|
+
throw new ApiError(`Le type d'entité "${t}" n'est pas supporté par searchMemberAutocomplete.`, 400);
|
|
3255
|
+
}
|
|
3256
|
+
|
|
3257
|
+
result.forEach(item => {
|
|
3258
|
+
for (const key of Object.keys(item)) {
|
|
3259
|
+
if (!["id", "name", "slug", "profilThumbImageUrl", "profilMarkerImageUrl", "type", "collection"].includes(key)) {
|
|
3260
|
+
delete item[key];
|
|
3261
|
+
}
|
|
3262
|
+
}
|
|
3263
|
+
});
|
|
3264
|
+
|
|
3265
|
+
const rawList = this._linkEntities(result);
|
|
3266
|
+
return rawList;
|
|
3267
|
+
}
|
|
3268
|
+
|
|
3212
3269
|
/**
|
|
3213
3270
|
* Soumet une demande pour rejoindre l'entité courante (ex. organisation, projet, événement...).
|
|
3214
3271
|
* Si une invitation est en attente, elle est automatiquement acceptée.
|
|
@@ -4088,30 +4145,6 @@ export class BaseEntity<TServerData = any> {
|
|
|
4088
4145
|
return paginator.next() as Promise<PaginatorPage<any>>;
|
|
4089
4146
|
}
|
|
4090
4147
|
|
|
4091
|
-
async searchMembers(data: SearchMemberAutocompleteData) {
|
|
4092
|
-
// TODO: j'ai l'impression que searchMode : "organizationOnly" ne renvois pas que des organisations
|
|
4093
|
-
const result = await this.endpointApi.searchMemberAutocomplete(data);
|
|
4094
|
-
if (!result || !Array.isArray(result)) {
|
|
4095
|
-
return [];
|
|
4096
|
-
}
|
|
4097
|
-
|
|
4098
|
-
const t = this.getEntityType();
|
|
4099
|
-
if (t === "badges" || t === "news" || t === "poi" || t === "comments") {
|
|
4100
|
-
throw new ApiError(`Le type d'entité "${t}" n'est pas supporté par searchMemberAutocomplete.`, 400);
|
|
4101
|
-
}
|
|
4102
|
-
|
|
4103
|
-
result.forEach(item => {
|
|
4104
|
-
for (const key of Object.keys(item)) {
|
|
4105
|
-
if (!["id", "name", "slug", "profilThumbImageUrl", "profilMarkerImageUrl", "type", "collection"].includes(key)) {
|
|
4106
|
-
delete item[key];
|
|
4107
|
-
}
|
|
4108
|
-
}
|
|
4109
|
-
});
|
|
4110
|
-
|
|
4111
|
-
const rawList = this._linkEntities(result);
|
|
4112
|
-
return rawList;
|
|
4113
|
-
}
|
|
4114
|
-
|
|
4115
4148
|
}
|
|
4116
4149
|
|
|
4117
4150
|
export default BaseEntity;
|
package/src/api/User.ts
CHANGED
|
@@ -24,6 +24,18 @@ import type { EntityTypes } from "@/types/entities.js";
|
|
|
24
24
|
type ApiClient = import("../ApiClient.js").default;
|
|
25
25
|
type UserItemNormalized = import("./serverDataType/User.js").UserItemNormalized;
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Interface représentant le lien entre un utilisateur et une entité parente.
|
|
29
|
+
* Utilisée pour typer les données de relation (membre, admin, invitations, etc.)
|
|
30
|
+
*/
|
|
31
|
+
interface ParentLink {
|
|
32
|
+
isAdmin?: boolean;
|
|
33
|
+
isAdminPending?: boolean;
|
|
34
|
+
isInviting?: boolean;
|
|
35
|
+
isAdminInviting?: boolean;
|
|
36
|
+
toBeValidated?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
27
39
|
export class User extends BaseEntity<UserItemNormalized> {
|
|
28
40
|
|
|
29
41
|
static override entityType = "citoyens" as const;
|
|
@@ -890,37 +902,88 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
890
902
|
return super.entityBySlug(slug);
|
|
891
903
|
}
|
|
892
904
|
|
|
905
|
+
// ────────────────────────────────
|
|
906
|
+
// Actions sur l'utilisateur par rapport à l'entité parente
|
|
907
|
+
// ────────────────────────────────
|
|
908
|
+
|
|
893
909
|
/**
|
|
894
|
-
* Valide les préconditions
|
|
910
|
+
* Valide les préconditions pour les méthodes nécessitant d'être membre.
|
|
895
911
|
* @private
|
|
896
912
|
* @param methodName - Nom de la méthode appelante (pour les messages d'erreur).
|
|
897
913
|
* @param expectedTypes - Types d'entité parent autorisés.
|
|
898
914
|
* @throws {ApiError} 401 - Si l'utilisateur n'est pas connecté.
|
|
899
|
-
* @throws {ApiError} 401 - Si l'utilisateur connecté n'est pas administrateur de l'entité parente.
|
|
900
915
|
* @throws {ApiError} 404 - Si l'utilisateur n'est pas enregistré.
|
|
901
916
|
* @throws {ApiError} 404 - Si l'entité parente n'est pas enregistrée.
|
|
917
|
+
* @throws {ApiError} 401 - Si l'utilisateur connecté n'est pas membre de l'entité parente.
|
|
902
918
|
* @throws {ApiError} 400 - Si le type d'entité parent n'est pas valide.
|
|
903
919
|
*/
|
|
904
|
-
private
|
|
920
|
+
private _validateMemberPreconditions(methodName: string, expectedTypes: string[]): void {
|
|
905
921
|
if (!this.userId) {
|
|
906
922
|
throw new ApiError(`Vous devez être connecté pour ${methodName}.`, 401);
|
|
907
923
|
}
|
|
908
924
|
|
|
909
|
-
if(!this.parent?.isAdmin()){
|
|
910
|
-
throw new ApiError("Vous devez être administrateur pour effectuer cette action.", 401);
|
|
911
|
-
}
|
|
912
|
-
|
|
913
925
|
if (!this.id) {
|
|
914
926
|
throw new ApiError(`${this.constructor.name} non enregistrée.`, 404);
|
|
915
927
|
}
|
|
916
928
|
|
|
917
|
-
if(!this.parent?.id){
|
|
929
|
+
if (!this.parent?.id) {
|
|
918
930
|
throw new ApiError("L'entité parente n'est pas enregistrée.", 404);
|
|
919
931
|
}
|
|
920
932
|
|
|
921
933
|
if (!expectedTypes.includes(this.parent.getEntityType())) {
|
|
922
934
|
throw new ApiError(`L'entité doit être de type : ${expectedTypes.join(", ")}, reçu : ${this.parent.getEntityType()}`, 400);
|
|
923
935
|
}
|
|
936
|
+
|
|
937
|
+
// Vérifier que l'utilisateur connecté a le bon rôle selon le type d'entité
|
|
938
|
+
// Pour les events, tout utilisateur connecté peut agir (pas besoin d'être participant)
|
|
939
|
+
const parentType = this.parent.getEntityType();
|
|
940
|
+
|
|
941
|
+
if (parentType === "events") {
|
|
942
|
+
// Pour les événements, être connecté suffit (déjà vérifié ci-dessus)
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
let hasRole = false;
|
|
947
|
+
|
|
948
|
+
switch (parentType) {
|
|
949
|
+
case "organizations":
|
|
950
|
+
hasRole = this.parent.isMember();
|
|
951
|
+
break;
|
|
952
|
+
case "projects":
|
|
953
|
+
hasRole = this.parent.isContributor();
|
|
954
|
+
break;
|
|
955
|
+
default:
|
|
956
|
+
hasRole = false;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
if (!hasRole) {
|
|
960
|
+
const roleNames: Record<string, string> = {
|
|
961
|
+
organizations: "membre",
|
|
962
|
+
projects: "contributeur"
|
|
963
|
+
};
|
|
964
|
+
const roleName = roleNames[parentType] || "membre";
|
|
965
|
+
throw new ApiError(`Vous devez être ${roleName} pour effectuer cette action.`, 401);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* Valide les préconditions pour les méthodes nécessitant d'être administrateur.
|
|
971
|
+
* @private
|
|
972
|
+
* @param methodName - Nom de la méthode appelante (pour les messages d'erreur).
|
|
973
|
+
* @param expectedTypes - Types d'entité parent autorisés.
|
|
974
|
+
* @throws {ApiError} 401 - Si l'utilisateur n'est pas connecté.
|
|
975
|
+
* @throws {ApiError} 404 - Si l'utilisateur n'est pas enregistré.
|
|
976
|
+
* @throws {ApiError} 404 - Si l'entité parente n'est pas enregistrée.
|
|
977
|
+
* @throws {ApiError} 401 - Si l'utilisateur connecté n'est pas membre de l'entité parente.
|
|
978
|
+
* @throws {ApiError} 401 - Si l'utilisateur connecté n'est pas administrateur de l'entité parente.
|
|
979
|
+
* @throws {ApiError} 400 - Si le type d'entité parent n'est pas valide.
|
|
980
|
+
*/
|
|
981
|
+
private _validateAdminPreconditions(methodName: string, expectedTypes: string[]): void {
|
|
982
|
+
this._validateMemberPreconditions(methodName, expectedTypes);
|
|
983
|
+
|
|
984
|
+
if (!this.parent?.isAdmin()) {
|
|
985
|
+
throw new ApiError("Vous devez être administrateur pour effectuer cette action.", 401);
|
|
986
|
+
}
|
|
924
987
|
}
|
|
925
988
|
|
|
926
989
|
|
|
@@ -930,13 +993,24 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
930
993
|
* @returns Le lien parent de l'utilisateur ou `null` s'il n'existe pas.
|
|
931
994
|
* @private
|
|
932
995
|
*/
|
|
933
|
-
private _getParentLinkForUser():
|
|
996
|
+
private _getParentLinkForUser(): ParentLink | null {
|
|
934
997
|
const { connectTypeDisconnect } = this.parent!._getLinkMeta();
|
|
935
998
|
const userId = this!.id;
|
|
936
999
|
if (!userId) return null;
|
|
937
1000
|
return this.parent?.serverData?.links?.[connectTypeDisconnect]?.[userId] || null;
|
|
938
1001
|
}
|
|
939
1002
|
|
|
1003
|
+
/**
|
|
1004
|
+
* Rafraîchit l'utilisateur et l'entité parente après une action.
|
|
1005
|
+
* @private
|
|
1006
|
+
*/
|
|
1007
|
+
private async _refreshWithParent(): Promise<void> {
|
|
1008
|
+
await this.refresh();
|
|
1009
|
+
if (this.parent) {
|
|
1010
|
+
await this.parent.refresh();
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
940
1014
|
/**
|
|
941
1015
|
* Vérifie si l'utilisateur est administrateur de l'entité parente.
|
|
942
1016
|
*
|
|
@@ -978,7 +1052,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
978
1052
|
* }
|
|
979
1053
|
*/
|
|
980
1054
|
override isAdmin(): boolean {
|
|
981
|
-
this.
|
|
1055
|
+
this._validateMemberPreconditions("isAdmin", ["organizations", "projects"]);
|
|
982
1056
|
const parentLink = this._getParentLinkForUser();
|
|
983
1057
|
return this._validateUserLink(parentLink) && parentLink?.isAdmin === true;
|
|
984
1058
|
}
|
|
@@ -1009,7 +1083,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1009
1083
|
* }
|
|
1010
1084
|
*/
|
|
1011
1085
|
override isMember(): boolean {
|
|
1012
|
-
this.
|
|
1086
|
+
this._validateMemberPreconditions("isMember", ["organizations"]);
|
|
1013
1087
|
const parentLink = this._getParentLinkForUser();
|
|
1014
1088
|
return this._validateUserLink(parentLink);
|
|
1015
1089
|
}
|
|
@@ -1040,7 +1114,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1040
1114
|
* }
|
|
1041
1115
|
*/
|
|
1042
1116
|
override isContributor(): boolean {
|
|
1043
|
-
this.
|
|
1117
|
+
this._validateMemberPreconditions("isContributor", ["projects"]);
|
|
1044
1118
|
const parentLink = this._getParentLinkForUser();
|
|
1045
1119
|
return this._validateUserLink(parentLink);
|
|
1046
1120
|
}
|
|
@@ -1071,7 +1145,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1071
1145
|
* }
|
|
1072
1146
|
*/
|
|
1073
1147
|
override isAttendee(): boolean {
|
|
1074
|
-
this.
|
|
1148
|
+
this._validateMemberPreconditions("isAttendee", ["events"]);
|
|
1075
1149
|
const parentLink = this._getParentLinkForUser();
|
|
1076
1150
|
return this._validateUserLink(parentLink);
|
|
1077
1151
|
}
|
|
@@ -1094,7 +1168,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1094
1168
|
* ```
|
|
1095
1169
|
*/
|
|
1096
1170
|
isInviting(): boolean {
|
|
1097
|
-
this.
|
|
1171
|
+
this._validateMemberPreconditions("isInviting", ["organizations", "projects", "events"]);
|
|
1098
1172
|
const parentLink = this._getParentLinkForUser();
|
|
1099
1173
|
if (!parentLink) return false;
|
|
1100
1174
|
return parentLink?.isInviting === true;
|
|
@@ -1118,10 +1192,10 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1118
1192
|
* ```
|
|
1119
1193
|
*/
|
|
1120
1194
|
isInvitingAdmin(): boolean {
|
|
1121
|
-
this.
|
|
1195
|
+
this._validateMemberPreconditions("isInvitingAdmin", ["organizations", "projects"]);
|
|
1122
1196
|
const parentLink = this._getParentLinkForUser();
|
|
1123
1197
|
if (!parentLink) return false;
|
|
1124
|
-
return parentLink?.isAdminInviting === true && parentLink?.isAdmin === true;
|
|
1198
|
+
return (parentLink?.isAdminInviting === true || parentLink?.isInviting === true) && parentLink?.isAdmin === true;
|
|
1125
1199
|
}
|
|
1126
1200
|
|
|
1127
1201
|
/**
|
|
@@ -1144,7 +1218,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1144
1218
|
* ```
|
|
1145
1219
|
*/
|
|
1146
1220
|
isAdminPending(): boolean {
|
|
1147
|
-
this.
|
|
1221
|
+
this._validateMemberPreconditions("isAdminPending", ["organizations", "projects"]);
|
|
1148
1222
|
const parentLink = this._getParentLinkForUser();
|
|
1149
1223
|
return parentLink?.isAdmin === true && parentLink?.isAdminPending === true;
|
|
1150
1224
|
}
|
|
@@ -1169,16 +1243,11 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1169
1243
|
* ```
|
|
1170
1244
|
*/
|
|
1171
1245
|
isToBeValidated(): boolean {
|
|
1172
|
-
this.
|
|
1246
|
+
this._validateMemberPreconditions("isToBeValidated", ["organizations", "projects", "events"]);
|
|
1173
1247
|
const parentLink = this._getParentLinkForUser();
|
|
1174
1248
|
return parentLink?.toBeValidated === true;
|
|
1175
1249
|
}
|
|
1176
1250
|
|
|
1177
|
-
|
|
1178
|
-
// ────────────────────────────────
|
|
1179
|
-
// Actions d'admin sur l'utilisateur par rapport à l'entité parente
|
|
1180
|
-
// ────────────────────────────────
|
|
1181
|
-
|
|
1182
1251
|
/**
|
|
1183
1252
|
* Envoie une demande pour rejoindre l'entité parente.
|
|
1184
1253
|
*
|
|
@@ -1186,6 +1255,8 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1186
1255
|
* vers l'organisation ou le projet parent. Si l'utilisateur n'a pas encore de lien,
|
|
1187
1256
|
* une demande de connexion est créée.
|
|
1188
1257
|
*
|
|
1258
|
+
* @param {Object} [options] - Options de la méthode
|
|
1259
|
+
* @param {boolean} [options.admin=false] - Si true, utilise "admin" comme connectType au lieu du type par défaut (connectTypeConnect)
|
|
1189
1260
|
* @returns {Promise<unknown>} La réponse de l'API après création de la demande
|
|
1190
1261
|
* @throws {ApiError} Si l'utilisateur n'est pas connecté, pas admin, ou si le parent n'est pas défini
|
|
1191
1262
|
* @throws {ApiError} Si l'utilisateur est déjà en attente de validation
|
|
@@ -1193,15 +1264,25 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1193
1264
|
*
|
|
1194
1265
|
* @example
|
|
1195
1266
|
* ```typescript
|
|
1196
|
-
* // Un admin récupère les membres et envoie une invitation
|
|
1267
|
+
* // Un admin récupère les membres et envoie une invitation (type par défaut)
|
|
1197
1268
|
* const org = await me.organization({ slug: "myOrg" });
|
|
1198
1269
|
* const users = await org.getMembers();
|
|
1199
1270
|
* const user = users.results[0];
|
|
1200
1271
|
* await user.sendRequestToJoinParent();
|
|
1272
|
+
*
|
|
1273
|
+
* // Avec le type admin explicite
|
|
1274
|
+
* await user.sendRequestToJoinParent({ admin: true });
|
|
1201
1275
|
* ```
|
|
1202
1276
|
*/
|
|
1203
|
-
async sendRequestToJoinParent(): Promise<unknown> {
|
|
1204
|
-
|
|
1277
|
+
async sendRequestToJoinParent({ admin }: { admin: boolean } = { admin: false }): Promise<unknown> {
|
|
1278
|
+
// Validation selon le type d'invitation : admin requis pour inviter en tant qu'admin
|
|
1279
|
+
if (admin) {
|
|
1280
|
+
// Invitation admin : uniquement orga/project, seul un admin peut le faire
|
|
1281
|
+
this._validateAdminPreconditions("sendRequestToJoinParent", ["organizations", "projects"]);
|
|
1282
|
+
} else {
|
|
1283
|
+
// Invitation simple : orga/project/event, membre/contributeur/connecté peut le faire
|
|
1284
|
+
this._validateMemberPreconditions("sendRequestToJoinParent", ["organizations", "projects", "events"]);
|
|
1285
|
+
}
|
|
1205
1286
|
|
|
1206
1287
|
const { connectTypeConnect } = this.parent!._getLinkMeta();
|
|
1207
1288
|
|
|
@@ -1212,7 +1293,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1212
1293
|
|
|
1213
1294
|
const t = this.parent!.getEntityType();
|
|
1214
1295
|
|
|
1215
|
-
//
|
|
1296
|
+
// Narrow de type pour TypeScript
|
|
1216
1297
|
const parentType = t as ConnectData["parentType"];
|
|
1217
1298
|
|
|
1218
1299
|
const data: ConnectData = {
|
|
@@ -1220,21 +1301,17 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1220
1301
|
childType: "citoyens",
|
|
1221
1302
|
parentType,
|
|
1222
1303
|
parentId: this.parent!.id!,
|
|
1223
|
-
connectType: connectTypeConnect
|
|
1304
|
+
connectType: admin ? "admin" : connectTypeConnect
|
|
1224
1305
|
};
|
|
1225
1306
|
|
|
1226
1307
|
const retour = await this.callIsConnected(() => this.endpointApi.connect(data));
|
|
1227
|
-
|
|
1228
|
-
await this.refresh();
|
|
1229
|
-
if (this.parent) {
|
|
1230
|
-
await this.parent.refresh();
|
|
1231
|
-
}
|
|
1308
|
+
await this._refreshWithParent();
|
|
1232
1309
|
return retour;
|
|
1233
1310
|
}
|
|
1234
1311
|
|
|
1235
|
-
// Cas : déjà en attente
|
|
1236
|
-
if (parentLink.
|
|
1237
|
-
throw new ApiError("
|
|
1312
|
+
// Cas : déjà en attente d'acceptation
|
|
1313
|
+
if (parentLink.isInviting || parentLink?.isAdminInviting) {
|
|
1314
|
+
throw new ApiError("Une invitation est déjà en attente d'acceptation.", 400);
|
|
1238
1315
|
}
|
|
1239
1316
|
|
|
1240
1317
|
// Cas par défaut : rien à faire
|
|
@@ -1262,7 +1339,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1262
1339
|
* ```
|
|
1263
1340
|
*/
|
|
1264
1341
|
async validateMemberRequest(): Promise<unknown> {
|
|
1265
|
-
this.
|
|
1342
|
+
this._validateAdminPreconditions("validateMemberRequest", ["organizations", "projects"]);
|
|
1266
1343
|
|
|
1267
1344
|
const parentLink = this._getParentLinkForUser();
|
|
1268
1345
|
|
|
@@ -1283,64 +1360,10 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1283
1360
|
};
|
|
1284
1361
|
|
|
1285
1362
|
const retour = await this.callIsConnected(() => this.endpointApi.linkValidate(data));
|
|
1286
|
-
|
|
1287
|
-
await this.refresh();
|
|
1288
|
-
if (this.parent) {
|
|
1289
|
-
await this.parent.refresh();
|
|
1290
|
-
}
|
|
1363
|
+
await this._refreshWithParent();
|
|
1291
1364
|
return retour;
|
|
1292
1365
|
}
|
|
1293
1366
|
|
|
1294
|
-
/**
|
|
1295
|
-
* Valide une invitation en attente d'acceptation.
|
|
1296
|
-
*
|
|
1297
|
-
* Cette méthode permet à un admin de valider une invitation envoyée à un utilisateur
|
|
1298
|
-
* qui est en attente (`isInviting: true`). Après validation, l'utilisateur devient
|
|
1299
|
-
* membre actif de l'entité parente.
|
|
1300
|
-
*
|
|
1301
|
-
* @returns {Promise<unknown>} La réponse de l'API après validation
|
|
1302
|
-
* @throws {ApiError} Si l'utilisateur n'est pas connecté, pas admin, ou si le parent n'est pas défini
|
|
1303
|
-
* @throws {ApiError} Si l'utilisateur n'a pas d'invitation en attente
|
|
1304
|
-
*
|
|
1305
|
-
* @example
|
|
1306
|
-
* ```typescript
|
|
1307
|
-
* // Un admin valide une invitation en attente
|
|
1308
|
-
* const org = await me.organization({ slug: "myOrg" });
|
|
1309
|
-
* const members = await org.getMembers();
|
|
1310
|
-
* const invitedUser = members.results.find(u => u.serverData.links?.memberOf?.[org.id]?.isInviting);
|
|
1311
|
-
* await invitedUser.validateInvitation();
|
|
1312
|
-
* ```
|
|
1313
|
-
*/
|
|
1314
|
-
// async validateInvitation(): Promise<unknown> {
|
|
1315
|
-
// this._validateRoleCheckPreconditions("validateInvitation", ["organizations", "projects"]);
|
|
1316
|
-
|
|
1317
|
-
// const parentLink = this._getParentLinkForUser();
|
|
1318
|
-
|
|
1319
|
-
// if (!parentLink?.isInviting) {
|
|
1320
|
-
// throw new ApiError("Cet utilisateur n'a pas d'invitation en attente.", 400);
|
|
1321
|
-
// }
|
|
1322
|
-
|
|
1323
|
-
// const t = this.parent!.getEntityType();
|
|
1324
|
-
|
|
1325
|
-
// const parentType = t as LinkValidateData["parentType"];
|
|
1326
|
-
|
|
1327
|
-
// const data: LinkValidateData = {
|
|
1328
|
-
// childId: this.id!,
|
|
1329
|
-
// childType: "citoyens",
|
|
1330
|
-
// parentType,
|
|
1331
|
-
// parentId: this.parent!.id!,
|
|
1332
|
-
// linkOption: "isInviting"
|
|
1333
|
-
// };
|
|
1334
|
-
|
|
1335
|
-
// const retour = await this.callIsConnected(() => this.endpointApi.linkValidate(data));
|
|
1336
|
-
// // Refresh l'utilisateur membre et l'entité parente
|
|
1337
|
-
// await this.refresh();
|
|
1338
|
-
// if (this.parent) {
|
|
1339
|
-
// await this.parent.refresh();
|
|
1340
|
-
// }
|
|
1341
|
-
// return retour;
|
|
1342
|
-
// }
|
|
1343
|
-
|
|
1344
1367
|
/**
|
|
1345
1368
|
* Valide une demande d'admin en attente.
|
|
1346
1369
|
*
|
|
@@ -1362,7 +1385,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1362
1385
|
* ```
|
|
1363
1386
|
*/
|
|
1364
1387
|
async validateAdminRequest(): Promise<unknown> {
|
|
1365
|
-
this.
|
|
1388
|
+
this._validateAdminPreconditions("validateAdminRequest", ["organizations", "projects"]);
|
|
1366
1389
|
|
|
1367
1390
|
const parentLink = this._getParentLinkForUser();
|
|
1368
1391
|
|
|
@@ -1383,11 +1406,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1383
1406
|
};
|
|
1384
1407
|
|
|
1385
1408
|
const retour = await this.callIsConnected(() => this.endpointApi.linkValidate(data));
|
|
1386
|
-
|
|
1387
|
-
await this.refresh();
|
|
1388
|
-
if (this.parent) {
|
|
1389
|
-
await this.parent.refresh();
|
|
1390
|
-
}
|
|
1409
|
+
await this._refreshWithParent();
|
|
1391
1410
|
return retour;
|
|
1392
1411
|
}
|
|
1393
1412
|
|
|
@@ -1411,7 +1430,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1411
1430
|
* ```
|
|
1412
1431
|
*/
|
|
1413
1432
|
async removeFromParent(): Promise<unknown> {
|
|
1414
|
-
this.
|
|
1433
|
+
this._validateAdminPreconditions("removeFromParent", ["organizations", "projects"]);
|
|
1415
1434
|
|
|
1416
1435
|
const parentLink = this._getParentLinkForUser();
|
|
1417
1436
|
|
|
@@ -1434,11 +1453,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1434
1453
|
};
|
|
1435
1454
|
|
|
1436
1455
|
const retour = await this.callIsConnected(() => this.endpointApi.disconnect(data));
|
|
1437
|
-
|
|
1438
|
-
await this.refresh();
|
|
1439
|
-
if (this.parent) {
|
|
1440
|
-
await this.parent.refresh();
|
|
1441
|
-
}
|
|
1456
|
+
await this._refreshWithParent();
|
|
1442
1457
|
return retour;
|
|
1443
1458
|
}
|
|
1444
1459
|
|
|
@@ -1463,7 +1478,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1463
1478
|
* ```
|
|
1464
1479
|
*/
|
|
1465
1480
|
async promoteToAdmin(): Promise<unknown> {
|
|
1466
|
-
this.
|
|
1481
|
+
this._validateAdminPreconditions("promoteToAdmin", ["organizations", "projects"]);
|
|
1467
1482
|
|
|
1468
1483
|
const parentLink = this._getParentLinkForUser();
|
|
1469
1484
|
|
|
@@ -1471,7 +1486,11 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1471
1486
|
throw new ApiError("Cet utilisateur n'est pas membre de cette entité.", 400);
|
|
1472
1487
|
}
|
|
1473
1488
|
|
|
1474
|
-
if (parentLink
|
|
1489
|
+
if (parentLink?.isAdmin && (parentLink?.isInviting || parentLink?.isAdminInviting)) {
|
|
1490
|
+
throw new ApiError("Cet utilisateur est déjà en cours d'invitation en tant qu'admin.", 400);
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
if (parentLink?.isAdmin && !parentLink?.isInviting && !parentLink?.isAdminInviting) {
|
|
1475
1494
|
throw new ApiError("Cet utilisateur est déjà admin.", 400);
|
|
1476
1495
|
}
|
|
1477
1496
|
|
|
@@ -1488,11 +1507,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1488
1507
|
};
|
|
1489
1508
|
|
|
1490
1509
|
const retour = await this.callIsConnected(() => this.endpointApi.connect(data));
|
|
1491
|
-
|
|
1492
|
-
await this.refresh();
|
|
1493
|
-
if (this.parent) {
|
|
1494
|
-
await this.parent.refresh();
|
|
1495
|
-
}
|
|
1510
|
+
await this._refreshWithParent();
|
|
1496
1511
|
return retour;
|
|
1497
1512
|
}
|
|
1498
1513
|
|
|
@@ -1517,7 +1532,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1517
1532
|
* ```
|
|
1518
1533
|
*/
|
|
1519
1534
|
async demoteFromAdmin(): Promise<unknown> {
|
|
1520
|
-
this.
|
|
1535
|
+
this._validateAdminPreconditions("demoteFromAdmin", ["organizations", "projects"]);
|
|
1521
1536
|
|
|
1522
1537
|
const parentLink = this._getParentLinkForUser();
|
|
1523
1538
|
|
|
@@ -1543,11 +1558,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1543
1558
|
};
|
|
1544
1559
|
|
|
1545
1560
|
const retour = await this.callIsConnected(() => this.endpointApi.demoteAdmin(data));
|
|
1546
|
-
|
|
1547
|
-
await this.refresh();
|
|
1548
|
-
if (this.parent) {
|
|
1549
|
-
await this.parent.refresh();
|
|
1550
|
-
}
|
|
1561
|
+
await this._refreshWithParent();
|
|
1551
1562
|
return retour;
|
|
1552
1563
|
}
|
|
1553
1564
|
|
|
@@ -1081,6 +1081,39 @@ export declare class BaseEntity<TServerData = any> {
|
|
|
1081
1081
|
docType?: "image" | "file";
|
|
1082
1082
|
};
|
|
1083
1083
|
}): Promise<Record<string, any>>;
|
|
1084
|
+
/**
|
|
1085
|
+
* Recherche des membres (utilisateurs ou organisations) liés à l'entité courante.
|
|
1086
|
+
*
|
|
1087
|
+
* Cette méthode effectue une recherche par autocomplétion parmi les membres de l'entité
|
|
1088
|
+
* (organisation, projet, événement). Les résultats sont filtrés selon le mode de recherche
|
|
1089
|
+
* et retournés sous forme d'entités User ou Organization liées à l'entité parente.
|
|
1090
|
+
*
|
|
1091
|
+
* @param {SearchMemberAutocompleteData} data - Paramètres de recherche
|
|
1092
|
+
* @param {string} data.search - Terme recherché (nom, slug, etc.)
|
|
1093
|
+
* @param {"personOnly" | "organizationOnly" | "mixte"} data.searchMode - Mode de recherche :
|
|
1094
|
+
* - `"personOnly"` : recherche uniquement parmi les utilisateurs
|
|
1095
|
+
* - `"organizationOnly"` : recherche uniquement parmi les organisations
|
|
1096
|
+
* - `"mixte"` : recherche parmi les utilisateurs et organisations
|
|
1097
|
+
* @returns {Promise<(User | Organization)[]>} Liste des entités correspondantes, liées à l'entité parente
|
|
1098
|
+
* @throws {ApiError} Si le type d'entité n'est pas supporté (badges, news, poi, comments)
|
|
1099
|
+
*
|
|
1100
|
+
* @example
|
|
1101
|
+
* ```typescript
|
|
1102
|
+
* // Rechercher des utilisateurs dans une organisation
|
|
1103
|
+
* const org = await me.organization({ slug: "myOrg" });
|
|
1104
|
+
* const users = await org.searchMembers({ search: "jean", searchMode: "personOnly" });
|
|
1105
|
+
* users.forEach(user => console.log(user.data.name));
|
|
1106
|
+
*
|
|
1107
|
+
* // Rechercher des organisations membres d'un projet
|
|
1108
|
+
* const project = await me.project({ slug: "myProject" });
|
|
1109
|
+
* const orgs = await project.searchMembers({ search: "asso", searchMode: "organizationOnly" });
|
|
1110
|
+
* ```
|
|
1111
|
+
*
|
|
1112
|
+
* @remarks
|
|
1113
|
+
* Les entités retournées sont automatiquement liées à l'entité parente via `_linkEntities`,
|
|
1114
|
+
* ce qui permet d'utiliser les méthodes comme `sendRequestToJoinParent()`, `isAdminPending()`, etc.
|
|
1115
|
+
*/
|
|
1116
|
+
searchMembers(data: SearchMemberAutocompleteData): Promise<(User | Organization)[]>;
|
|
1084
1117
|
/**
|
|
1085
1118
|
* Soumet une demande pour rejoindre l'entité courante (ex. organisation, projet, événement...).
|
|
1086
1119
|
* Si une invitation est en attente, elle est automatiquement acceptée.
|
|
@@ -1381,6 +1414,5 @@ export declare class BaseEntity<TServerData = any> {
|
|
|
1381
1414
|
*/
|
|
1382
1415
|
costumEventRequestLoadContextTag(data?: Partial<Omit<CostumEventRequestLoadContextTagData, "pathParams">>): Promise<unknown>;
|
|
1383
1416
|
coformAnswersSearch(data?: Partial<CoformAnswersSearchData>): Promise<PaginatorPage<any>>;
|
|
1384
|
-
searchMembers(data: SearchMemberAutocompleteData): Promise<any[]>;
|
|
1385
1417
|
}
|
|
1386
1418
|
export default BaseEntity;
|