@communecter/cocolight-api-client 1.0.82 → 1.0.84
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/Event.ts +1 -1
- package/src/api/Project.ts +1 -1
- package/src/api/User.ts +113 -111
- package/types/api/BaseEntity.d.ts +33 -1
- package/types/api/User.d.ts +21 -23
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/Event.ts
CHANGED
|
@@ -222,7 +222,7 @@ export class Event extends BaseEntity<EventItemNormalized> {
|
|
|
222
222
|
const { toBeValidated, isAdmin, isInviting, isAdminPending, roles = [] } = options;
|
|
223
223
|
|
|
224
224
|
if(this.isMe){
|
|
225
|
-
finalData.pathParams = {
|
|
225
|
+
finalData.pathParams = { id: this.id };
|
|
226
226
|
// NOTE : dans le schema je crois que si pas de finalData.filters alors le default ce fait avec finalData.pathParams
|
|
227
227
|
// finalData.filters = {
|
|
228
228
|
// [`links.events.${this.id}`]: { "$exists": true },
|
package/src/api/Project.ts
CHANGED
|
@@ -243,7 +243,7 @@ export class Project extends BaseEntity<ProjectItemNormalized> {
|
|
|
243
243
|
const { toBeValidated, isAdmin, isInviting, isAdminPending, roles = [] } = options;
|
|
244
244
|
|
|
245
245
|
if(this.isMe){
|
|
246
|
-
finalData.pathParams = {
|
|
246
|
+
finalData.pathParams = { id: this.id };
|
|
247
247
|
// NOTE : dans le schema je crois que si pas de finalData.filters alors le default ce fait avec finalData.pathParams
|
|
248
248
|
// finalData.filters = {
|
|
249
249
|
// [`links.projects.${this.id}`]: { "$exists": true },
|
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,7 +1192,7 @@ 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
1198
|
return (parentLink?.isAdminInviting === true || parentLink?.isInviting === true) && parentLink?.isAdmin === true;
|
|
@@ -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
|
*
|
|
@@ -1206,7 +1275,14 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1206
1275
|
* ```
|
|
1207
1276
|
*/
|
|
1208
1277
|
async sendRequestToJoinParent({ admin }: { admin: boolean } = { admin: false }): Promise<unknown> {
|
|
1209
|
-
|
|
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
|
+
}
|
|
1210
1286
|
|
|
1211
1287
|
const { connectTypeConnect } = this.parent!._getLinkMeta();
|
|
1212
1288
|
|
|
@@ -1217,7 +1293,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1217
1293
|
|
|
1218
1294
|
const t = this.parent!.getEntityType();
|
|
1219
1295
|
|
|
1220
|
-
//
|
|
1296
|
+
// Narrow de type pour TypeScript
|
|
1221
1297
|
const parentType = t as ConnectData["parentType"];
|
|
1222
1298
|
|
|
1223
1299
|
const data: ConnectData = {
|
|
@@ -1229,17 +1305,13 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1229
1305
|
};
|
|
1230
1306
|
|
|
1231
1307
|
const retour = await this.callIsConnected(() => this.endpointApi.connect(data));
|
|
1232
|
-
|
|
1233
|
-
await this.refresh();
|
|
1234
|
-
if (this.parent) {
|
|
1235
|
-
await this.parent.refresh();
|
|
1236
|
-
}
|
|
1308
|
+
await this._refreshWithParent();
|
|
1237
1309
|
return retour;
|
|
1238
1310
|
}
|
|
1239
1311
|
|
|
1240
|
-
// Cas : déjà en attente
|
|
1312
|
+
// Cas : déjà en attente d'acceptation
|
|
1241
1313
|
if (parentLink.isInviting || parentLink?.isAdminInviting) {
|
|
1242
|
-
throw new ApiError("
|
|
1314
|
+
throw new ApiError("Une invitation est déjà en attente d'acceptation.", 400);
|
|
1243
1315
|
}
|
|
1244
1316
|
|
|
1245
1317
|
// Cas par défaut : rien à faire
|
|
@@ -1267,7 +1339,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1267
1339
|
* ```
|
|
1268
1340
|
*/
|
|
1269
1341
|
async validateMemberRequest(): Promise<unknown> {
|
|
1270
|
-
this.
|
|
1342
|
+
this._validateAdminPreconditions("validateMemberRequest", ["organizations", "projects"]);
|
|
1271
1343
|
|
|
1272
1344
|
const parentLink = this._getParentLinkForUser();
|
|
1273
1345
|
|
|
@@ -1288,64 +1360,10 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1288
1360
|
};
|
|
1289
1361
|
|
|
1290
1362
|
const retour = await this.callIsConnected(() => this.endpointApi.linkValidate(data));
|
|
1291
|
-
|
|
1292
|
-
await this.refresh();
|
|
1293
|
-
if (this.parent) {
|
|
1294
|
-
await this.parent.refresh();
|
|
1295
|
-
}
|
|
1363
|
+
await this._refreshWithParent();
|
|
1296
1364
|
return retour;
|
|
1297
1365
|
}
|
|
1298
1366
|
|
|
1299
|
-
/**
|
|
1300
|
-
* Valide une invitation en attente d'acceptation.
|
|
1301
|
-
*
|
|
1302
|
-
* Cette méthode permet à un admin de valider une invitation envoyée à un utilisateur
|
|
1303
|
-
* qui est en attente (`isInviting: true`). Après validation, l'utilisateur devient
|
|
1304
|
-
* membre actif de l'entité parente.
|
|
1305
|
-
*
|
|
1306
|
-
* @returns {Promise<unknown>} La réponse de l'API après validation
|
|
1307
|
-
* @throws {ApiError} Si l'utilisateur n'est pas connecté, pas admin, ou si le parent n'est pas défini
|
|
1308
|
-
* @throws {ApiError} Si l'utilisateur n'a pas d'invitation en attente
|
|
1309
|
-
*
|
|
1310
|
-
* @example
|
|
1311
|
-
* ```typescript
|
|
1312
|
-
* // Un admin valide une invitation en attente
|
|
1313
|
-
* const org = await me.organization({ slug: "myOrg" });
|
|
1314
|
-
* const members = await org.getMembers();
|
|
1315
|
-
* const invitedUser = members.results.find(u => u.serverData.links?.memberOf?.[org.id]?.isInviting);
|
|
1316
|
-
* await invitedUser.validateInvitation();
|
|
1317
|
-
* ```
|
|
1318
|
-
*/
|
|
1319
|
-
// async validateInvitation(): Promise<unknown> {
|
|
1320
|
-
// this._validateRoleCheckPreconditions("validateInvitation", ["organizations", "projects"]);
|
|
1321
|
-
|
|
1322
|
-
// const parentLink = this._getParentLinkForUser();
|
|
1323
|
-
|
|
1324
|
-
// if (!parentLink?.isInviting) {
|
|
1325
|
-
// throw new ApiError("Cet utilisateur n'a pas d'invitation en attente.", 400);
|
|
1326
|
-
// }
|
|
1327
|
-
|
|
1328
|
-
// const t = this.parent!.getEntityType();
|
|
1329
|
-
|
|
1330
|
-
// const parentType = t as LinkValidateData["parentType"];
|
|
1331
|
-
|
|
1332
|
-
// const data: LinkValidateData = {
|
|
1333
|
-
// childId: this.id!,
|
|
1334
|
-
// childType: "citoyens",
|
|
1335
|
-
// parentType,
|
|
1336
|
-
// parentId: this.parent!.id!,
|
|
1337
|
-
// linkOption: "isInviting"
|
|
1338
|
-
// };
|
|
1339
|
-
|
|
1340
|
-
// const retour = await this.callIsConnected(() => this.endpointApi.linkValidate(data));
|
|
1341
|
-
// // Refresh l'utilisateur membre et l'entité parente
|
|
1342
|
-
// await this.refresh();
|
|
1343
|
-
// if (this.parent) {
|
|
1344
|
-
// await this.parent.refresh();
|
|
1345
|
-
// }
|
|
1346
|
-
// return retour;
|
|
1347
|
-
// }
|
|
1348
|
-
|
|
1349
1367
|
/**
|
|
1350
1368
|
* Valide une demande d'admin en attente.
|
|
1351
1369
|
*
|
|
@@ -1367,7 +1385,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1367
1385
|
* ```
|
|
1368
1386
|
*/
|
|
1369
1387
|
async validateAdminRequest(): Promise<unknown> {
|
|
1370
|
-
this.
|
|
1388
|
+
this._validateAdminPreconditions("validateAdminRequest", ["organizations", "projects"]);
|
|
1371
1389
|
|
|
1372
1390
|
const parentLink = this._getParentLinkForUser();
|
|
1373
1391
|
|
|
@@ -1388,11 +1406,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1388
1406
|
};
|
|
1389
1407
|
|
|
1390
1408
|
const retour = await this.callIsConnected(() => this.endpointApi.linkValidate(data));
|
|
1391
|
-
|
|
1392
|
-
await this.refresh();
|
|
1393
|
-
if (this.parent) {
|
|
1394
|
-
await this.parent.refresh();
|
|
1395
|
-
}
|
|
1409
|
+
await this._refreshWithParent();
|
|
1396
1410
|
return retour;
|
|
1397
1411
|
}
|
|
1398
1412
|
|
|
@@ -1416,7 +1430,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1416
1430
|
* ```
|
|
1417
1431
|
*/
|
|
1418
1432
|
async removeFromParent(): Promise<unknown> {
|
|
1419
|
-
this.
|
|
1433
|
+
this._validateAdminPreconditions("removeFromParent", ["organizations", "projects"]);
|
|
1420
1434
|
|
|
1421
1435
|
const parentLink = this._getParentLinkForUser();
|
|
1422
1436
|
|
|
@@ -1439,11 +1453,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1439
1453
|
};
|
|
1440
1454
|
|
|
1441
1455
|
const retour = await this.callIsConnected(() => this.endpointApi.disconnect(data));
|
|
1442
|
-
|
|
1443
|
-
await this.refresh();
|
|
1444
|
-
if (this.parent) {
|
|
1445
|
-
await this.parent.refresh();
|
|
1446
|
-
}
|
|
1456
|
+
await this._refreshWithParent();
|
|
1447
1457
|
return retour;
|
|
1448
1458
|
}
|
|
1449
1459
|
|
|
@@ -1468,7 +1478,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1468
1478
|
* ```
|
|
1469
1479
|
*/
|
|
1470
1480
|
async promoteToAdmin(): Promise<unknown> {
|
|
1471
|
-
this.
|
|
1481
|
+
this._validateAdminPreconditions("promoteToAdmin", ["organizations", "projects"]);
|
|
1472
1482
|
|
|
1473
1483
|
const parentLink = this._getParentLinkForUser();
|
|
1474
1484
|
|
|
@@ -1497,11 +1507,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1497
1507
|
};
|
|
1498
1508
|
|
|
1499
1509
|
const retour = await this.callIsConnected(() => this.endpointApi.connect(data));
|
|
1500
|
-
|
|
1501
|
-
await this.refresh();
|
|
1502
|
-
if (this.parent) {
|
|
1503
|
-
await this.parent.refresh();
|
|
1504
|
-
}
|
|
1510
|
+
await this._refreshWithParent();
|
|
1505
1511
|
return retour;
|
|
1506
1512
|
}
|
|
1507
1513
|
|
|
@@ -1526,7 +1532,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1526
1532
|
* ```
|
|
1527
1533
|
*/
|
|
1528
1534
|
async demoteFromAdmin(): Promise<unknown> {
|
|
1529
|
-
this.
|
|
1535
|
+
this._validateAdminPreconditions("demoteFromAdmin", ["organizations", "projects"]);
|
|
1530
1536
|
|
|
1531
1537
|
const parentLink = this._getParentLinkForUser();
|
|
1532
1538
|
|
|
@@ -1552,11 +1558,7 @@ export class User extends BaseEntity<UserItemNormalized> {
|
|
|
1552
1558
|
};
|
|
1553
1559
|
|
|
1554
1560
|
const retour = await this.callIsConnected(() => this.endpointApi.demoteAdmin(data));
|
|
1555
|
-
|
|
1556
|
-
await this.refresh();
|
|
1557
|
-
if (this.parent) {
|
|
1558
|
-
await this.parent.refresh();
|
|
1559
|
-
}
|
|
1561
|
+
await this._refreshWithParent();
|
|
1560
1562
|
return retour;
|
|
1561
1563
|
}
|
|
1562
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;
|
package/types/api/User.d.ts
CHANGED
|
@@ -342,17 +342,30 @@ export declare class User extends BaseEntity<UserItemNormalized> {
|
|
|
342
342
|
*/
|
|
343
343
|
entityBySlug(slug: string): Promise<EntityTypes>;
|
|
344
344
|
/**
|
|
345
|
-
* Valide les préconditions
|
|
345
|
+
* Valide les préconditions pour les méthodes nécessitant d'être membre.
|
|
346
|
+
* @private
|
|
347
|
+
* @param methodName - Nom de la méthode appelante (pour les messages d'erreur).
|
|
348
|
+
* @param expectedTypes - Types d'entité parent autorisés.
|
|
349
|
+
* @throws {ApiError} 401 - Si l'utilisateur n'est pas connecté.
|
|
350
|
+
* @throws {ApiError} 404 - Si l'utilisateur n'est pas enregistré.
|
|
351
|
+
* @throws {ApiError} 404 - Si l'entité parente n'est pas enregistrée.
|
|
352
|
+
* @throws {ApiError} 401 - Si l'utilisateur connecté n'est pas membre de l'entité parente.
|
|
353
|
+
* @throws {ApiError} 400 - Si le type d'entité parent n'est pas valide.
|
|
354
|
+
*/
|
|
355
|
+
private _validateMemberPreconditions;
|
|
356
|
+
/**
|
|
357
|
+
* Valide les préconditions pour les méthodes nécessitant d'être administrateur.
|
|
346
358
|
* @private
|
|
347
359
|
* @param methodName - Nom de la méthode appelante (pour les messages d'erreur).
|
|
348
360
|
* @param expectedTypes - Types d'entité parent autorisés.
|
|
349
361
|
* @throws {ApiError} 401 - Si l'utilisateur n'est pas connecté.
|
|
350
|
-
* @throws {ApiError} 401 - Si l'utilisateur connecté n'est pas administrateur de l'entité parente.
|
|
351
362
|
* @throws {ApiError} 404 - Si l'utilisateur n'est pas enregistré.
|
|
352
363
|
* @throws {ApiError} 404 - Si l'entité parente n'est pas enregistrée.
|
|
364
|
+
* @throws {ApiError} 401 - Si l'utilisateur connecté n'est pas membre de l'entité parente.
|
|
365
|
+
* @throws {ApiError} 401 - Si l'utilisateur connecté n'est pas administrateur de l'entité parente.
|
|
353
366
|
* @throws {ApiError} 400 - Si le type d'entité parent n'est pas valide.
|
|
354
367
|
*/
|
|
355
|
-
private
|
|
368
|
+
private _validateAdminPreconditions;
|
|
356
369
|
/**
|
|
357
370
|
* Récupère le lien parent pour l'utilisateur actuel.
|
|
358
371
|
*
|
|
@@ -360,6 +373,11 @@ export declare class User extends BaseEntity<UserItemNormalized> {
|
|
|
360
373
|
* @private
|
|
361
374
|
*/
|
|
362
375
|
private _getParentLinkForUser;
|
|
376
|
+
/**
|
|
377
|
+
* Rafraîchit l'utilisateur et l'entité parente après une action.
|
|
378
|
+
* @private
|
|
379
|
+
*/
|
|
380
|
+
private _refreshWithParent;
|
|
363
381
|
/**
|
|
364
382
|
* Vérifie si l'utilisateur est administrateur de l'entité parente.
|
|
365
383
|
*
|
|
@@ -605,26 +623,6 @@ export declare class User extends BaseEntity<UserItemNormalized> {
|
|
|
605
623
|
* ```
|
|
606
624
|
*/
|
|
607
625
|
validateMemberRequest(): Promise<unknown>;
|
|
608
|
-
/**
|
|
609
|
-
* Valide une invitation en attente d'acceptation.
|
|
610
|
-
*
|
|
611
|
-
* Cette méthode permet à un admin de valider une invitation envoyée à un utilisateur
|
|
612
|
-
* qui est en attente (`isInviting: true`). Après validation, l'utilisateur devient
|
|
613
|
-
* membre actif de l'entité parente.
|
|
614
|
-
*
|
|
615
|
-
* @returns {Promise<unknown>} La réponse de l'API après validation
|
|
616
|
-
* @throws {ApiError} Si l'utilisateur n'est pas connecté, pas admin, ou si le parent n'est pas défini
|
|
617
|
-
* @throws {ApiError} Si l'utilisateur n'a pas d'invitation en attente
|
|
618
|
-
*
|
|
619
|
-
* @example
|
|
620
|
-
* ```typescript
|
|
621
|
-
* // Un admin valide une invitation en attente
|
|
622
|
-
* const org = await me.organization({ slug: "myOrg" });
|
|
623
|
-
* const members = await org.getMembers();
|
|
624
|
-
* const invitedUser = members.results.find(u => u.serverData.links?.memberOf?.[org.id]?.isInviting);
|
|
625
|
-
* await invitedUser.validateInvitation();
|
|
626
|
-
* ```
|
|
627
|
-
*/
|
|
628
626
|
/**
|
|
629
627
|
* Valide une demande d'admin en attente.
|
|
630
628
|
*
|