@communecter/cocolight-api-client 1.0.134 → 1.0.136
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.ts +26 -0
- package/src/api/Action.ts +4 -8
- package/src/api/Answer.ts +152 -1
- package/src/api/BaseEntity.ts +295 -16
- package/src/api/Comment.ts +26 -1
- package/src/api/EndpointApi.types.ts +12 -0
- package/src/api/News.ts +26 -1
- package/src/api/Organization.ts +1 -10
- package/src/endpoints.module.ts +1 -1
- package/types/Api.d.ts +18 -0
- package/types/api/Action.d.ts +3 -1
- package/types/api/Answer.d.ts +74 -1
- package/types/api/BaseEntity.d.ts +184 -12
- package/types/api/Comment.d.ts +16 -0
- package/types/api/EndpointApi.types.d.ts +12 -0
- package/types/api/News.d.ts +16 -0
- package/types/endpoints.module.d.ts +304 -0
package/types/Api.d.ts
CHANGED
|
@@ -79,6 +79,24 @@ export default class Api {
|
|
|
79
79
|
* Retourne l'instance d'EndpointApi.
|
|
80
80
|
*/
|
|
81
81
|
get endpointApi(): EndpointApi;
|
|
82
|
+
/**
|
|
83
|
+
* Recherche des tags correspondant à un mot-clé.
|
|
84
|
+
*
|
|
85
|
+
* Wrap de `SEARCH_TAGS` (auth=none) — accessible même non connecté.
|
|
86
|
+
* Méthode exposée sur la facade `Api` (pas d'entité hôte naturelle pour
|
|
87
|
+
* un index global de tags).
|
|
88
|
+
*
|
|
89
|
+
* @param q - Mot-clé de recherche (au moins 1 caractère).
|
|
90
|
+
* @returns Tableau de résultats : soit `[{tag}]` si aucun match (echo du
|
|
91
|
+
* terme), soit `[{_id, tag, field_length}, ...]` avec les tags
|
|
92
|
+
* existants triés par `field_length`.
|
|
93
|
+
* @throws {ApiError} 400 si `q` vide.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* const results = await api.searchTags("permac");
|
|
97
|
+
* results.forEach(t => console.log(t.tag, t.field_length));
|
|
98
|
+
*/
|
|
99
|
+
searchTags(q: string): Promise<unknown>;
|
|
82
100
|
/**
|
|
83
101
|
* Déconnecte l'utilisateur et réinitialise la session.
|
|
84
102
|
*/
|
package/types/api/Action.d.ts
CHANGED
|
@@ -282,7 +282,9 @@ export declare class Action extends BaseEntity<ActionItemNormalized> {
|
|
|
282
282
|
*/
|
|
283
283
|
archive(): Promise<unknown>;
|
|
284
284
|
/**
|
|
285
|
-
* Helper privé :
|
|
285
|
+
* Helper privé : délègue à `BaseEntity.updateField()` pour un path donné.
|
|
286
|
+
* Bénéficie du normalize automatique (R0 Date → isoDate, R1 collapse setType,
|
|
287
|
+
* R2 pull + empty → "", R6 drop setType vide).
|
|
286
288
|
*/
|
|
287
289
|
private _updatePath;
|
|
288
290
|
/**
|
package/types/api/Answer.d.ts
CHANGED
|
@@ -136,6 +136,34 @@ export declare class Answer extends BaseEntity<AnswerItemNormalized> {
|
|
|
136
136
|
* Les autres sont calculés/posés par le backend.
|
|
137
137
|
*/
|
|
138
138
|
removeFields: string[];
|
|
139
|
+
/**
|
|
140
|
+
* {@inheritDoc BaseEntity#_isAdminViaHierarchy}
|
|
141
|
+
*
|
|
142
|
+
* Override Answer : la hiérarchie d'Answer passe par son **parent instance
|
|
143
|
+
* Form** (pas par `serverData.parent` direct comme pour `events`/`projects`/`poi`).
|
|
144
|
+
*
|
|
145
|
+
* Chaîne : `Answer → parent (Form) → form.serverData.parent ({[orgId]: {type, name}}) → check userContext.links`.
|
|
146
|
+
*
|
|
147
|
+
* Si le parent n'est pas un Form (cas `api.answer({id})` direct sans contexte),
|
|
148
|
+
* renvoie `false` — impossible de vérifier la hiérarchie sans le Form.
|
|
149
|
+
*
|
|
150
|
+
* @protected
|
|
151
|
+
*/
|
|
152
|
+
protected _isAdminViaHierarchy(): boolean;
|
|
153
|
+
/**
|
|
154
|
+
* {@inheritDoc BaseEntity#isAuthor}
|
|
155
|
+
*
|
|
156
|
+
* Override Answer : le champ d'autorité est `serverData.user` (pas `creator`
|
|
157
|
+
* comme la version par défaut de BaseEntity). Le `user` peut être :
|
|
158
|
+
* - un `string` (ID MongoDB brut renvoyé par le backend)
|
|
159
|
+
* - une instance `User` (après `_transformServerData` qui le link en entité)
|
|
160
|
+
*
|
|
161
|
+
* Les pré-conditions (connexion, id, serverData) sont vérifiées comme dans
|
|
162
|
+
* la version de base — `silent: true` (défaut) renvoie `false` au lieu de throw.
|
|
163
|
+
*/
|
|
164
|
+
isAuthor(options?: {
|
|
165
|
+
silent?: boolean;
|
|
166
|
+
}): boolean;
|
|
139
167
|
/**
|
|
140
168
|
* Transforme les champs imbriqués (user, context etc.) en instances d'entités.
|
|
141
169
|
* @param data - Les données brutes du serveur.
|
|
@@ -183,15 +211,53 @@ export declare class Answer extends BaseEntity<AnswerItemNormalized> {
|
|
|
183
211
|
* - `serverData` et `draftData` sont vidés (sans casser la réactivité)
|
|
184
212
|
* - `_isDeleted = true` → toute mutation ultérieure (`save`, `get`, etc.) throw
|
|
185
213
|
*
|
|
214
|
+
* **Guard** : autorisation côté client si l'utilisateur courant est :
|
|
215
|
+
* - l'**auteur** de l'Answer (`serverData.user === userId`), OU
|
|
216
|
+
* - **admin** d'un parent du Form (org/project) via la hiérarchie
|
|
217
|
+
* (`form.serverData.parent[orgId]` × `userContext.links.memberOf[orgId].isAdmin`).
|
|
218
|
+
*
|
|
219
|
+
* Le check utilise `isAuthorOrAdmin({checkHierarchy: true})` qui s'appuie sur
|
|
220
|
+
* l'override `Answer._isAdminViaHierarchy` (remonte via parent instance Form).
|
|
221
|
+
*
|
|
222
|
+
* **Pré-requis** :
|
|
223
|
+
* - `this.parent` doit être un Form (cas `form.answer({id})`)
|
|
224
|
+
* - `userContext` (User connecté) doit avoir `serverData.links` chargés (cas `api.me()`)
|
|
225
|
+
* Sans ces pré-requis, seul `isAuthor` peut autoriser.
|
|
226
|
+
*
|
|
186
227
|
* @param reason - Raison libre transmise au backend (audit). Défaut : `"delete coform answer"`.
|
|
187
228
|
* @throws {ApiError} 400 si l'Answer n'a pas d'id (jamais sauvegardée).
|
|
229
|
+
* @throws {ApiError} 403 si ni auteur ni admin du parent.
|
|
188
230
|
*
|
|
189
231
|
* @example
|
|
190
232
|
* const answer = await form.answer({ id: "..." });
|
|
191
|
-
* await answer.delete();
|
|
233
|
+
* await answer.delete(); // OK si auteur OU admin org/project parent du Form
|
|
192
234
|
* answer._isDeleted; // true
|
|
193
235
|
*/
|
|
194
236
|
delete(reason?: string): Promise<void>;
|
|
237
|
+
/**
|
|
238
|
+
* {@inheritDoc BaseEntity#deleteFile}
|
|
239
|
+
*
|
|
240
|
+
* Override avec **cleanup local** : après suppression backend, retire le
|
|
241
|
+
* `docId` des structures uploader normalisées dans `serverData.answers` et
|
|
242
|
+
* `_draftData.answers` (format `{updateDate, files: {docId: docPath}}`
|
|
243
|
+
* produit par `processUploads()` et `_transformServerData`).
|
|
244
|
+
*
|
|
245
|
+
* Le caller n'a pas besoin de refetch — `answer.serverData.answers[*][*].files`
|
|
246
|
+
* reflète directement l'état post-suppression.
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* const files = await answer.getFiles({ subKey: "sf.input", docType: "image" });
|
|
250
|
+
* await answer.deleteFile(files[0].docId);
|
|
251
|
+
* // answer.serverData.answers[sf][input].files[files[0].docId] === undefined
|
|
252
|
+
*/
|
|
253
|
+
deleteFile(docId: string): Promise<void>;
|
|
254
|
+
/**
|
|
255
|
+
* Walk `answers[subFormId][inputId]` et retire `docId` des structures
|
|
256
|
+
* `{updateDate, files: {docId: docPath}}` (format canonique uploader).
|
|
257
|
+
* Mutation in-place pour préserver la réactivité.
|
|
258
|
+
* @private
|
|
259
|
+
*/
|
|
260
|
+
private _removeDocIdFromUploaderFields;
|
|
195
261
|
/**
|
|
196
262
|
* Récupère la liste des fichiers attachés à un input précis de cette Answer
|
|
197
263
|
* via `COFORM_GET_ANSWER_FILES`.
|
|
@@ -223,6 +289,13 @@ export declare class Answer extends BaseEntity<AnswerItemNormalized> {
|
|
|
223
289
|
/**
|
|
224
290
|
* Upload un fichier rattaché à cette Answer via `COFORM_UPLOAD_ANSWER_FILE`.
|
|
225
291
|
*
|
|
292
|
+
* **Building block du pipeline** : conçu pour être utilisé via
|
|
293
|
+
* `processUploads()` suivi de `save()`. L'Answer créée par le premier upload
|
|
294
|
+
* est en état "placeholder" côté backend (champ `user` non posé) — `save()`
|
|
295
|
+
* finalise. Appeler `get()` ou `delete()` (via l'entité) sur une Answer
|
|
296
|
+
* upload-only sans save échouera : le backend la considère comme orpheline
|
|
297
|
+
* (`editDeniedReason: "not_owner"`, stub sans `data.id`).
|
|
298
|
+
*
|
|
226
299
|
* **Cas premier upload (Answer sans id)** : le backend crée l'Answer et
|
|
227
300
|
* renvoie `answerId`. La méthode pose alors `this._draftData.id = answerId`
|
|
228
301
|
* — les uploads suivants utiliseront cet id, et un `save()` ultérieur passera
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { UpdateSettingsData, UpdateBlockDescriptionData, UpdateBlockInfoData, UpdateBlockSocialData, UpdateBlockLocalityData, GetNewsData, GetGalleryData, GlobalAutocompleteCostumData, CostumEventRequestActorsData, CostumEventRequestSubeventsData, CostumEventRequestDatesData, CostumEventRequestElementEventData, CostumEventRequestCategoriesData, CostumEventRequestEventData, CostumEventRequestLinkTlToEventData, CostumEventRequestLoadContextTagData, GetOrganizationsAdminData, GetOrganizationsNoAdminData, GetProjectsAdminData, GetProjectsNoAdminData, GetPoisAdminData, GetPoisNoAdminData, GetSubscribersData, GetBadgesData, CoformAnswersSearchData, SearchMemberAutocompleteData, GetEventsData, CostumFilterCoformData, GetCountriesData, SearchZonesData, CoformAnswersByFormsData, FundingEnvelopeData, CoremuOperationData } from "./EndpointApi.types.js";
|
|
1
|
+
import type { UpdateSettingsData, UpdateBlockDescriptionData, UpdateBlockInfoData, UpdateBlockSocialData, UpdateBlockLocalityData, GetNewsData, GetGalleryData, GlobalAutocompleteCostumData, CostumEventRequestActorsData, CostumEventRequestSubeventsData, CostumEventRequestDatesData, CostumEventRequestElementEventData, CostumEventRequestCategoriesData, CostumEventRequestEventData, CostumEventRequestLinkTlToEventData, CostumEventRequestLoadContextTagData, GetOrganizationsAdminData, GetOrganizationsNoAdminData, GetProjectsAdminData, GetProjectsNoAdminData, GetPoisAdminData, GetPoisNoAdminData, GetSubscribersData, GetBadgesData, CoformAnswersSearchData, SearchMemberAutocompleteData, GetEventsData, CostumFilterCoformData, GetCountriesData, SearchZonesData, CoformAnswersByFormsData, FundingEnvelopeData, CoremuOperationData, UpdatePathValueData } from "./EndpointApi.types.js";
|
|
2
2
|
import type { TransformsMap } from "../types/entities.js";
|
|
3
3
|
import type { CountryItem } from "./serverDataType/Country.js";
|
|
4
4
|
import type { ZoneItemNormalized } from "./serverDataType/Zone.js";
|
|
@@ -72,6 +72,43 @@ type ParentLike = BaseEntity<any> & {
|
|
|
72
72
|
* - `navigator-tl` → `/costum/navigator/gettl`
|
|
73
73
|
*/
|
|
74
74
|
export type SearchCostumVariant = "default" | "navigator-tl";
|
|
75
|
+
/**
|
|
76
|
+
* Types de coercion backend supportés par `UPDATE_PATH_VALUE.setType`.
|
|
77
|
+
*
|
|
78
|
+
* Référence côté backend : `string_set_type` (PHP) accepte ces 5 valeurs +
|
|
79
|
+
* tout autre string (passthrough — pas de coercion). Le `& Record<never, never>`
|
|
80
|
+
* garde l'autocomplete des literals tout en acceptant des strings custom.
|
|
81
|
+
*
|
|
82
|
+
* - `"int"` → `intval()` (PHP)
|
|
83
|
+
* - `"float"` → `floatval()`
|
|
84
|
+
* - `"boolean"` / `"bool"` → `FILTER_VALIDATE_BOOLEAN` (alias)
|
|
85
|
+
* - `"isoDate"` → parse multi-format → `MongoDate`
|
|
86
|
+
* Formats acceptés : ISO 8601 natif, `m-d-Y`, `d-m-Y`, `{sec, usec}` legacy,
|
|
87
|
+
* string `"now"` (date actuelle), slashes auto-convertis en tirets.
|
|
88
|
+
* - `"timestamp"` → parse → Unix seconds (`int`)
|
|
89
|
+
*/
|
|
90
|
+
export type SetTypeValue = "int" | "float" | "boolean" | "bool" | "isoDate" | "timestamp" | (string & Record<never, never>);
|
|
91
|
+
/**
|
|
92
|
+
* Magic values reconnues par `UPDATE_PATH_VALUE` côté backend.
|
|
93
|
+
* Utilisable comme `value` ou `path` selon le cas.
|
|
94
|
+
*/
|
|
95
|
+
export declare const UPDATE_PATH_MAGIC: {
|
|
96
|
+
/**
|
|
97
|
+
* `value: "updatedTime"` → backend remplace par `time()` Unix seconds courant
|
|
98
|
+
* (utile pour `lastEditedAt`, audit trail, etc. sans avoir à fournir un timestamp côté client).
|
|
99
|
+
*/
|
|
100
|
+
readonly CURRENT_TIME: "updatedTime";
|
|
101
|
+
/**
|
|
102
|
+
* `value: "now"` avec `setType: "isoDate"` → résolu côté backend en `MongoDate(now)`.
|
|
103
|
+
*/
|
|
104
|
+
readonly NOW: "now";
|
|
105
|
+
/**
|
|
106
|
+
* `path: "allToRoot"` → la `value` (qui doit être un objet) est exposée à la
|
|
107
|
+
* racine de l'entité : chaque clé devient un champ racine. Combiner avec
|
|
108
|
+
* `updatePartial: true` pour un merge avec préservation des autres champs.
|
|
109
|
+
*/
|
|
110
|
+
readonly PATH_ALL_TO_ROOT: "allToRoot";
|
|
111
|
+
};
|
|
75
112
|
type EndpointApiCtor = {
|
|
76
113
|
new (apiClient: ApiClient): EndpointApi;
|
|
77
114
|
};
|
|
@@ -562,6 +599,117 @@ export declare class BaseEntity<TServerData = any> {
|
|
|
562
599
|
qqfilename: string;
|
|
563
600
|
qqtotalfilesize: number;
|
|
564
601
|
}>;
|
|
602
|
+
/**
|
|
603
|
+
* Supprime un document (fichier ou image) par son `docId` MongoDB via
|
|
604
|
+
* `DELETE_DOCUMENT_BY_ID`.
|
|
605
|
+
*
|
|
606
|
+
* Méthode générique exposée sur toutes les entités — le endpoint backend
|
|
607
|
+
* opère par docId seul, sans contexte parent requis. Disponible ici pour
|
|
608
|
+
* être découvrable et **override-able** par les entités qui veulent un
|
|
609
|
+
* cleanup local après suppression (ex: `News.deleteFile` pourrait retirer
|
|
610
|
+
* l'id de `mediaImg.images` côté serverData).
|
|
611
|
+
*
|
|
612
|
+
* Ne met PAS à jour `serverData` après suppression — le caller doit
|
|
613
|
+
* invalider son cache local s'il en a un (cas typique : React Query).
|
|
614
|
+
*
|
|
615
|
+
* @param docId - ID MongoDB du document (24 hex)
|
|
616
|
+
* @throws {ApiError} 400 si `docId` invalide.
|
|
617
|
+
*
|
|
618
|
+
* @example
|
|
619
|
+
* // Depuis une Answer (suppression d'un fichier uploader)
|
|
620
|
+
* const files = await answer.getFiles({ subKey: "sf.input", docType: "image" });
|
|
621
|
+
* await answer.deleteFile(files[0].docId);
|
|
622
|
+
*
|
|
623
|
+
* @example
|
|
624
|
+
* // Depuis n'importe quelle entité qui possède un docId
|
|
625
|
+
* await news.deleteFile(imageDocId);
|
|
626
|
+
*/
|
|
627
|
+
deleteFile(docId: string): Promise<void>;
|
|
628
|
+
/**
|
|
629
|
+
* Met à jour un champ unique (ou multi-fields via `updatePartial`) sur cette
|
|
630
|
+
* entité via `UPDATE_PATH_VALUE`.
|
|
631
|
+
*
|
|
632
|
+
* **Cas d'usage couverts** :
|
|
633
|
+
* - `$set` simple : `entity.updateField("name", "Nouveau nom")`
|
|
634
|
+
* - `$unset` : `entity.updateField("description", null)`
|
|
635
|
+
* - `$push` array : `entity.updateField("tags", "x", { arrayForm: true })`
|
|
636
|
+
* - `$pull` array : `entity.updateField("tags.3", null, { pull: "tags" })`
|
|
637
|
+
* - `$pullAll` array : `entity.updateField("tags", ["a","b"], { arrayForm: true, pull: "tags" })`
|
|
638
|
+
* - Coercion type : `entity.updateField("credits", 100, { setType: "int" })`
|
|
639
|
+
* - Date auto : `entity.updateField("startDate", new Date())` → setType "isoDate" + ISO string
|
|
640
|
+
* - Multi-field merge : `entity.updateField("address", {...}, { updatePartial: true })`
|
|
641
|
+
* - Auth sub-form : `entity.updateField("...", value, { formParentId: "..." })`
|
|
642
|
+
*
|
|
643
|
+
* **Magic values** :
|
|
644
|
+
* - `value: "updatedTime"` → backend remplace par `time()` Unix seconds
|
|
645
|
+
* - `value: "now"` + `setType: "isoDate"` → résout en date actuelle
|
|
646
|
+
* - `path: "allToRoot"` → value exposée à la racine de l'entité
|
|
647
|
+
*
|
|
648
|
+
* Le payload est normalisé via `_normalizeUpdatePathPayload` avant envoi
|
|
649
|
+
* (cf. les 4 règles documentées sur cette méthode).
|
|
650
|
+
*
|
|
651
|
+
* @param path - Chemin MongoDB dot-notation (ex: `"address.street"`, `"answers.aapStep1.depense.3"`).
|
|
652
|
+
* @param value - Valeur à poser. Accepte `Date` (auto-convertie en ISO + setType isoDate).
|
|
653
|
+
* @param opts - Options : `setType`, `arrayForm`, `pull`, `updatePartial`, `formParentId`, `edit`.
|
|
654
|
+
* @returns Réponse brute de l'API.
|
|
655
|
+
* @throws {ApiError} 404 si l'entité n'a pas d'id.
|
|
656
|
+
* @throws {ApiError} 400 si `value === undefined`, `path` vide, ou conflit `arrayForm` + `pull` sans value array, ou `updatePartial` sans value object.
|
|
657
|
+
*
|
|
658
|
+
* @example
|
|
659
|
+
* // Update simple
|
|
660
|
+
* await org.updateField("name", "Nouvelle organisation");
|
|
661
|
+
*
|
|
662
|
+
* @example
|
|
663
|
+
* // Date instance auto-convertie
|
|
664
|
+
* await action.updateField("startDate", new Date());
|
|
665
|
+
*
|
|
666
|
+
* @example
|
|
667
|
+
* // Multi-field merge (préserve les autres clés de address)
|
|
668
|
+
* await org.updateField("address", {
|
|
669
|
+
* street: "123 rue X",
|
|
670
|
+
* city: "Paris",
|
|
671
|
+
* }, { updatePartial: true });
|
|
672
|
+
*
|
|
673
|
+
* @example
|
|
674
|
+
* // Push dans array
|
|
675
|
+
* await project.updateField("tags", "permaculture", { arrayForm: true });
|
|
676
|
+
*
|
|
677
|
+
* @example
|
|
678
|
+
* // Pull from array (avec normalisation R2 : null → "")
|
|
679
|
+
* await project.updateField("oceco.milestones.3", null, { pull: "oceco.milestones" });
|
|
680
|
+
*/
|
|
681
|
+
updateField(path: string, value: unknown, opts?: {
|
|
682
|
+
setType?: SetTypeValue | Array<{
|
|
683
|
+
path: string;
|
|
684
|
+
type: SetTypeValue;
|
|
685
|
+
}>;
|
|
686
|
+
arrayForm?: boolean;
|
|
687
|
+
pull?: string;
|
|
688
|
+
updatePartial?: boolean;
|
|
689
|
+
formParentId?: string;
|
|
690
|
+
edit?: boolean;
|
|
691
|
+
}): Promise<unknown>;
|
|
692
|
+
/**
|
|
693
|
+
* Normalise le payload `updatePathValue` avant envoi au backend.
|
|
694
|
+
*
|
|
695
|
+
* Règles appliquées (4) :
|
|
696
|
+
* - **R0** : `value instanceof Date` → `value.toISOString()` + `setType: "isoDate"`
|
|
697
|
+
* (override d'un setType existant — l'intent `Date` est prioritaire).
|
|
698
|
+
* - **R1** : `setType: [{type:"isoDate"}, ...]` uniforme + `value: string` →
|
|
699
|
+
* collapse en `setType: "isoDate"` (forme scalaire préférée backend).
|
|
700
|
+
* - **R2** : `pull` présent + `value: ""|null|undefined` → force `value: ""`
|
|
701
|
+
* (le backend exige `value: string` quand `pull` est présent — contrainte
|
|
702
|
+
* schema `allOf`).
|
|
703
|
+
* - **R6** : `setType: []` array vide → drop silencieusement (évite wire
|
|
704
|
+
* format inutile, sécurise contre filtres qui ont tout retiré).
|
|
705
|
+
*
|
|
706
|
+
* Pour traiter une string ISO comme date, le caller doit passer `setType`
|
|
707
|
+
* explicitement (`"isoDate"` ou `[{path, type:"isoDate"}]`). Pas d'heuristique
|
|
708
|
+
* sur les strings pour éviter les faux positifs sur champs texte libre.
|
|
709
|
+
*
|
|
710
|
+
* @protected
|
|
711
|
+
*/
|
|
712
|
+
protected _normalizeUpdatePathPayload(payload: UpdatePathValueData): UpdatePathValueData;
|
|
565
713
|
/**
|
|
566
714
|
* Valide les entrées d'upload de fichiers.
|
|
567
715
|
*
|
|
@@ -938,15 +1086,24 @@ export declare class BaseEntity<TServerData = any> {
|
|
|
938
1086
|
*/
|
|
939
1087
|
private _extractUserContext;
|
|
940
1088
|
/**
|
|
941
|
-
* Vérifie si l'utilisateur est admin via la hiérarchie parent (logique généraliste)
|
|
942
|
-
*
|
|
1089
|
+
* Vérifie si l'utilisateur est admin via la hiérarchie parent (logique généraliste).
|
|
1090
|
+
*
|
|
1091
|
+
* Note : passé `protected` pour permettre l'override par les entités dont la
|
|
1092
|
+
* hiérarchie n'est pas un simple champ `serverData.parent` ou `.organizer`
|
|
1093
|
+
* (cf. `Answer._isAdminViaHierarchy` qui remonte via son parent instance Form).
|
|
1094
|
+
*
|
|
1095
|
+
* @protected
|
|
943
1096
|
*/
|
|
944
|
-
|
|
1097
|
+
protected _isAdminViaHierarchy(): boolean;
|
|
945
1098
|
/**
|
|
946
|
-
* Vérifie si l'utilisateur est admin d'un parent spécifique
|
|
947
|
-
*
|
|
1099
|
+
* Vérifie si l'utilisateur est admin d'un parent spécifique.
|
|
1100
|
+
*
|
|
1101
|
+
* Note : passé `protected` pour être utilisable par les overrides de
|
|
1102
|
+
* `_isAdminViaHierarchy()` (cf. `Answer._isAdminViaHierarchy`).
|
|
1103
|
+
*
|
|
1104
|
+
* @protected
|
|
948
1105
|
*/
|
|
949
|
-
|
|
1106
|
+
protected _isAdminOfParent(parentId: string, parentType: string): boolean;
|
|
950
1107
|
/**
|
|
951
1108
|
* Construit dynamiquement des filtres sur un lien entre entités
|
|
952
1109
|
*
|
|
@@ -1503,11 +1660,15 @@ export declare class BaseEntity<TServerData = any> {
|
|
|
1503
1660
|
*
|
|
1504
1661
|
* @param options - Options de vérification.
|
|
1505
1662
|
* @param options.silent - Si `true`, retourne `false` au lieu de lever une exception. Par défaut `true`.
|
|
1663
|
+
* @param options.checkHierarchy - Si `true`, propagé à `isAdmin` pour vérifier
|
|
1664
|
+
* également la hiérarchie parent (ex: `Answer.isAdmin({checkHierarchy: true})`
|
|
1665
|
+
* remonte vers org/project du Form parent).
|
|
1506
1666
|
* @returns - `true` si l'utilisateur est l'auteur ou administrateur, `false` sinon.
|
|
1507
1667
|
* @throws {ApiError} - Si `silent` est `false` et que les préconditions ne sont pas remplies.
|
|
1508
1668
|
*/
|
|
1509
1669
|
isAuthorOrAdmin(options?: {
|
|
1510
1670
|
silent?: boolean;
|
|
1671
|
+
checkHierarchy?: boolean;
|
|
1511
1672
|
}): boolean;
|
|
1512
1673
|
/**
|
|
1513
1674
|
* Vérifie si l'utilisateur est membre de l'entité.
|
|
@@ -1907,14 +2068,25 @@ export declare class BaseEntity<TServerData = any> {
|
|
|
1907
2068
|
*/
|
|
1908
2069
|
getCountries(data?: Partial<GetCountriesData>): Promise<CountryItem[]>;
|
|
1909
2070
|
/**
|
|
1910
|
-
*
|
|
2071
|
+
* Génère côté backend une nouvelle Answer placeholder rattachée au formulaire
|
|
2072
|
+
* donné (insert en BDD avec nouvel ObjectId) et retourne l'instance Answer
|
|
2073
|
+
* connectée (parent = `this`).
|
|
2074
|
+
*
|
|
2075
|
+
* **Note workflow** : l'Answer renvoyée est en état "placeholder" — pas de
|
|
2076
|
+
* `user` posé côté backend tant que `save()` n'a pas été appelé. Pour
|
|
2077
|
+
* récupérer plus tard via `coformAnswersById`, faire `save()` avec au moins
|
|
2078
|
+
* `answers` posés.
|
|
1911
2079
|
*
|
|
1912
|
-
* @param formId -
|
|
1913
|
-
* @returns
|
|
1914
|
-
* @throws {ApiError}
|
|
2080
|
+
* @param formId - ID du formulaire (24 hex)
|
|
2081
|
+
* @returns Instance `Answer` connectée à `this` (parent = entité courante)
|
|
2082
|
+
* @throws {ApiError} 400 si `formId` est absent ou invalide
|
|
1915
2083
|
*
|
|
2084
|
+
* @example
|
|
2085
|
+
* const org = await api.organization({ slug: "monOrga" });
|
|
2086
|
+
* const answer = await org.generateNewAnswerId(formId);
|
|
2087
|
+
* await answer.updateField(`${finder}.${org.id}`, { id: org.id, type: "organizations", name: org.serverData.name });
|
|
1916
2088
|
*/
|
|
1917
|
-
generateNewAnswerId(formId: string): Promise<
|
|
2089
|
+
generateNewAnswerId(formId: string): Promise<Answer>;
|
|
1918
2090
|
/**
|
|
1919
2091
|
* Associe un compte Discourse à l'utilisateur courant dans le contexte de l'instance.
|
|
1920
2092
|
* Injecte automatiquement le `costumSlug` via `_withCostumContext`.
|
package/types/api/Comment.d.ts
CHANGED
|
@@ -41,6 +41,22 @@ export declare class Comment extends BaseEntity<CommentItemNormalized> {
|
|
|
41
41
|
* @throws {ApiError} Si la news n'a pas d'ID (non enregistrée)
|
|
42
42
|
*/
|
|
43
43
|
addVote(status: string): Promise<unknown>;
|
|
44
|
+
/**
|
|
45
|
+
* Récupère la liste des votes (like, love, etc.) sur ce commentaire.
|
|
46
|
+
*
|
|
47
|
+
* Wrap de `SHOW_VOTE` avec auto-injection du `type` (`"comments"`) et de
|
|
48
|
+
* `this.id` dans `pathParams`. Le retour contient `vote` (votes individuels
|
|
49
|
+
* indexés par userId) et `voteCount` (compteurs par statut).
|
|
50
|
+
*
|
|
51
|
+
* @returns Réponse API : `{ _id, vote, voteCount }` ou variante d'erreur.
|
|
52
|
+
* @throws {ApiError} 404 si le commentaire n'a pas d'id (non enregistré).
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* const votes = await comment.getVotes();
|
|
56
|
+
* votes.voteCount?.like; // nombre de likes
|
|
57
|
+
* votes.vote?.[userId]; // vote détaillé d'un user
|
|
58
|
+
*/
|
|
59
|
+
getVotes(): Promise<unknown>;
|
|
44
60
|
/**
|
|
45
61
|
* Signale un abus sur ce commentaire
|
|
46
62
|
*
|
|
@@ -5150,6 +5150,18 @@ export interface UpdatePathValueData {
|
|
|
5150
5150
|
value: string | number | boolean | {
|
|
5151
5151
|
[k: string]: unknown;
|
|
5152
5152
|
} | unknown[] | null;
|
|
5153
|
+
/**
|
|
5154
|
+
* Mode multi-field merge : `value` doit être un objet, chaque clé devient un sub-path et est mise à jour individuellement (vs `$set` qui écrase l'objet entier). Les sous-clés à `null`/`""` sont supprimées (`$unset`). Combinable avec `setType: Array` pour coercion par sous-clé.
|
|
5155
|
+
*/
|
|
5156
|
+
updatePartial?: boolean;
|
|
5157
|
+
/**
|
|
5158
|
+
* ID du Form parent. Utilisé côté backend pour : (1) authorisation hiérarchique sur sub-forms (admin du Form parent autorisé à modifier les sub-inputs), (2) invalidation du cache de traduction du Form parent après modification.
|
|
5159
|
+
*/
|
|
5160
|
+
formParentId?: string;
|
|
5161
|
+
/**
|
|
5162
|
+
* Avec `arrayForm`, désactive le mode `$push` et force `$set` (écrase l'array entier). Cas legacy — préférer omettre `arrayForm` pour écraser un array.
|
|
5163
|
+
*/
|
|
5164
|
+
edit?: boolean;
|
|
5153
5165
|
[k: string]: unknown;
|
|
5154
5166
|
}
|
|
5155
5167
|
export interface DeleteDocumentByContextData {
|
package/types/api/News.d.ts
CHANGED
|
@@ -82,6 +82,22 @@ export declare class News extends BaseEntity<NewsItemNormalized> {
|
|
|
82
82
|
* @throws {ApiError} Si la news n'a pas d'ID (non enregistrée)
|
|
83
83
|
*/
|
|
84
84
|
addVote(status: string): Promise<unknown>;
|
|
85
|
+
/**
|
|
86
|
+
* Récupère la liste des votes (like, love, etc.) sur cette news.
|
|
87
|
+
*
|
|
88
|
+
* Wrap de `SHOW_VOTE` avec auto-injection du `type` (`"news"`) et de
|
|
89
|
+
* `this.id` dans `pathParams`. Le retour contient `vote` (votes individuels
|
|
90
|
+
* indexés par userId) et `voteCount` (compteurs par statut).
|
|
91
|
+
*
|
|
92
|
+
* @returns Réponse API : `{ _id, vote, voteCount }` ou variante d'erreur.
|
|
93
|
+
* @throws {ApiError} 404 si la news n'a pas d'id (non enregistrée).
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* const votes = await news.getVotes();
|
|
97
|
+
* votes.voteCount?.like; // nombre de likes
|
|
98
|
+
* votes.vote?.[userId]; // vote détaillé d'un user
|
|
99
|
+
*/
|
|
100
|
+
getVotes(): Promise<unknown>;
|
|
85
101
|
/**
|
|
86
102
|
* Signale un abus sur cette news
|
|
87
103
|
*
|