@communecter/cocolight-api-client 1.0.74 → 1.0.76
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 +1 -1
- 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 +71 -5
- package/src/api/EndpointApi.ts +17 -1
- package/src/api/EndpointApi.types.ts +24 -0
- package/src/api/Organization.ts +117 -2
- package/src/endpoints.module.ts +1 -1
- package/types/api/BaseEntity.d.ts +29 -0
- package/types/api/EndpointApi.d.ts +11 -1
- package/types/api/EndpointApi.types.d.ts +22 -0
- package/types/api/Organization.d.ts +77 -0
- package/types/endpoints.module.d.ts +188 -0
package/package.json
CHANGED
package/src/api/BaseEntity.ts
CHANGED
|
@@ -320,6 +320,8 @@ export class BaseEntity<TServerData = any> {
|
|
|
320
320
|
static entityTag = "BaseEntity";
|
|
321
321
|
static entityType?: string;
|
|
322
322
|
static SCHEMA_CONSTANTS?: string | string[];
|
|
323
|
+
static VIRTUAL_SCHEMAS?: Record<string, any>;
|
|
324
|
+
static CUSTOM_FIELD_HANDLERS?: Map<string, { updateMethod: string; schemaConstant?: string }>;
|
|
323
325
|
|
|
324
326
|
/**
|
|
325
327
|
* Vérifie que l'objet n'a pas été supprimé.
|
|
@@ -548,12 +550,16 @@ export class BaseEntity<TServerData = any> {
|
|
|
548
550
|
const transformed = this._transformServerData(newData);
|
|
549
551
|
const incoming = (transformed ?? {});
|
|
550
552
|
if (this._serverData && isReactive(this._serverData)) {
|
|
551
|
-
// Delete
|
|
553
|
+
// Delete only properties that no longer exist in the incoming data to ensure fields removed on the server are also removed locally
|
|
552
554
|
for (const key of Object.keys(this._serverData)) {
|
|
553
|
-
|
|
555
|
+
if (!(key in incoming)) {
|
|
556
|
+
delete (this._serverData as any)[key];
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
// Update or add properties from the incoming data (preserves reactive signals)
|
|
560
|
+
for (const key of Object.keys(incoming)) {
|
|
561
|
+
(this._serverData as any)[key] = (incoming as any)[key];
|
|
554
562
|
}
|
|
555
|
-
// Assign new properties
|
|
556
|
-
Object.assign(this._serverData, incoming);
|
|
557
563
|
} else {
|
|
558
564
|
this._serverData = reactive({ ...incoming }) as TServerData & ReactiveData;
|
|
559
565
|
}
|
|
@@ -1483,7 +1489,15 @@ export class BaseEntity<TServerData = any> {
|
|
|
1483
1489
|
};
|
|
1484
1490
|
|
|
1485
1491
|
for (const key of constants) {
|
|
1486
|
-
|
|
1492
|
+
let sch = apiClient.getRequestSchema(key);
|
|
1493
|
+
|
|
1494
|
+
// Injecter le schéma virtuel si disponible
|
|
1495
|
+
const Ctor = this._getCtor();
|
|
1496
|
+
const virtualSchema = Ctor.VIRTUAL_SCHEMAS?.[key];
|
|
1497
|
+
if (virtualSchema) {
|
|
1498
|
+
sch = this._mergeSchemas(sch, virtualSchema);
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1487
1501
|
if (!sch) throw new ApiError(`Unable to find schema for ${key}.`, 404);
|
|
1488
1502
|
|
|
1489
1503
|
// Extraire et fusionner les $defs
|
|
@@ -1619,6 +1633,58 @@ export class BaseEntity<TServerData = any> {
|
|
|
1619
1633
|
return JSON.stringify(this._toRawDeep(current)) !== JSON.stringify(this._toRawDeep(initial));
|
|
1620
1634
|
}
|
|
1621
1635
|
|
|
1636
|
+
/**
|
|
1637
|
+
* Merge deux schémas JSON en combinant leurs propriétés.
|
|
1638
|
+
* @param base - Schéma de base (peut être null/undefined)
|
|
1639
|
+
* @param virtual - Schéma virtuel à fusionner
|
|
1640
|
+
* @returns Schéma combiné
|
|
1641
|
+
* @private
|
|
1642
|
+
*/
|
|
1643
|
+
private _mergeSchemas(base: any, virtual: any): any {
|
|
1644
|
+
if (!base) return virtual;
|
|
1645
|
+
if (!virtual) return base;
|
|
1646
|
+
|
|
1647
|
+
return {
|
|
1648
|
+
allOf: [base, virtual],
|
|
1649
|
+
$defs: { ...base.$defs, ...virtual.$defs }
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
/**
|
|
1654
|
+
* Vérifie si un champ a changé par rapport à l'état initial.
|
|
1655
|
+
* @param fieldName - Nom du champ
|
|
1656
|
+
* @returns true si le champ a changé
|
|
1657
|
+
* @protected
|
|
1658
|
+
*/
|
|
1659
|
+
protected _hasFieldChanged(fieldName: string): boolean {
|
|
1660
|
+
const current = this._draftData[fieldName];
|
|
1661
|
+
const initial = this._initialDraftData[fieldName];
|
|
1662
|
+
return this._compareValues(current, initial);
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
/**
|
|
1666
|
+
* Invoque un handler personnalisé pour un champ spécifique.
|
|
1667
|
+
* @param methodName - Nom de la méthode à appeler
|
|
1668
|
+
* @param value - Valeur du champ
|
|
1669
|
+
* @param fieldName - Nom du champ (pour les messages d'erreur)
|
|
1670
|
+
* @returns Résultat de l'appel de la méthode
|
|
1671
|
+
* @protected
|
|
1672
|
+
*/
|
|
1673
|
+
protected async _invokeCustomFieldHandler(
|
|
1674
|
+
methodName: string,
|
|
1675
|
+
value: any,
|
|
1676
|
+
fieldName: string
|
|
1677
|
+
): Promise<any> {
|
|
1678
|
+
const method = (this as any)[methodName];
|
|
1679
|
+
if (typeof method !== "function") {
|
|
1680
|
+
throw new ApiError(
|
|
1681
|
+
`Custom handler "${methodName}" not found for field "${fieldName}"`,
|
|
1682
|
+
500
|
|
1683
|
+
);
|
|
1684
|
+
}
|
|
1685
|
+
return await method.call(this, value);
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1622
1688
|
_extractChangedFieldsFromSchema(apiClient: ApiClient, constant: string, data: Record<string, any> = {}, getInitialDraft: () => Record<string, any> | void, removeFields: string[] = []): Record<string, any> | null {
|
|
1623
1689
|
const schema = apiClient.getRequestSchema(constant);
|
|
1624
1690
|
let allowed = this._extractWritableFields(schema, data);
|
package/src/api/EndpointApi.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { ApiAuthenticationError } from "../error.js";
|
|
3
3
|
|
|
4
4
|
import type ApiClient from "../ApiClient.js";
|
|
5
|
-
import type { PersonRegisterData, AuthenticateUrlData, RefreshTokenUrlData, PasswordRecoveryData, ServerExchangeTokenData, ChangePasswordData, DeleteAccountData, UpdateSettingsData, UpdateBlockDescriptionData, UpdateBlockInfoData, UpdateBlockSocialData, UpdateBlockLocalityData, UpdateBlockSlugData, CheckData, ProfilImageData, ProfilBannerData, GetElementsAboutData, MulticonnectData, GetNewsData, GetNewsByIdData, AddNewsData, AddImageNewsData, AddFileNewsData, DeleteNewsData, UpdateNewsData, ShareNewsData, GetCommentsData, AddCommentsData, DeleteCommentsData, UpdateCommentsData, SearchTagsData, ShowVoteData, GlobalAutocompleteData, CityAutocompleteData, CityAutocompleteByCountryData, SuggestionInputData, GetProjectsNoAdminData, GetProjectsAdminData, GetPoisNoAdminData, GetPoisAdminData, GetOrganizationsNoAdminData, GetOrganizationsAdminData, GetMembersNoAdminData, GetMembersAdminData, GetFriendsAdminData, GetSubscriptionsData, GetSubscriptionsAdminData, GetSubscribersData, GetSubscribersAdminData, GetContributorsNoAdminData, GetContributorsAdminData, GetBadgesData, GetBadgesFiltersData, ConnectData, DisconnectData, GetElementsKeyData, GetFavorisData, DeleteFavorisData, AddFavorisData, AddOrganizationData, AddProjectData, AddPoiData, AddEventData, DeletePoiData, DeleteEventData, DeleteElementData, AddImageElementData, LinkValidateData, SearchMemberAutocompleteData, GetNotificationsData, GetNotificationsCountData, NotificationUpdateData, MarkNotificationAsReadData, ActivitypubSearchData, ActivitypubLinkData, ActivitypubGetCommunityData, GetBadgeData, AddBadgesData, AssignBadgesData, GetEventsData, ShareEventsData, InviteEventData, FollowData, GetCostumJsonData, GlobalAutocompleteCostumData, CostumEventRequestActorsData, CostumEventRequestSubeventsData, CostumEventRequestElementEventData, CostumEventRequestCategoriesData, CostumEventRequestDatesData, CostumEventRequestEventData, CostumEventRequestLinkTlToEventData, CostumEventRequestLoadContextTagData, GetGalleryData, GetAttendeesNoAdminData, GetAttendeesAdminData, CoformAnswersSearchData, CoformAnswersByIdData, AddVoteData, AddReportAbuseData } from "./EndpointApi.types.js";
|
|
5
|
+
import type { PersonRegisterData, AuthenticateUrlData, RefreshTokenUrlData, PasswordRecoveryData, ServerExchangeTokenData, ChangePasswordData, DeleteAccountData, UpdateSettingsData, UpdateBlockDescriptionData, UpdateBlockInfoData, UpdateBlockSocialData, UpdateBlockLocalityData, UpdateBlockSlugData, CheckData, ProfilImageData, ProfilBannerData, GetElementsAboutData, MulticonnectData, GetNewsData, GetNewsByIdData, AddNewsData, AddImageNewsData, AddFileNewsData, DeleteNewsData, UpdateNewsData, ShareNewsData, GetCommentsData, AddCommentsData, DeleteCommentsData, UpdateCommentsData, SearchTagsData, ShowVoteData, GlobalAutocompleteData, CityAutocompleteData, CityAutocompleteByCountryData, SuggestionInputData, GetProjectsNoAdminData, GetProjectsAdminData, GetPoisNoAdminData, GetPoisAdminData, GetOrganizationsNoAdminData, GetOrganizationsAdminData, GetMembersNoAdminData, GetMembersAdminData, GetFriendsAdminData, GetSubscriptionsData, GetSubscriptionsAdminData, GetSubscribersData, GetSubscribersAdminData, GetContributorsNoAdminData, GetContributorsAdminData, GetBadgesData, GetBadgesFiltersData, ConnectData, DisconnectData, GetElementsKeyData, GetFavorisData, DeleteFavorisData, AddFavorisData, AddOrganizationData, AddProjectData, AddPoiData, AddEventData, DeletePoiData, DeleteEventData, DeleteElementData, AddImageElementData, LinkValidateData, SearchMemberAutocompleteData, GetNotificationsData, GetNotificationsCountData, NotificationUpdateData, MarkNotificationAsReadData, ActivitypubSearchData, ActivitypubLinkData, ActivitypubGetCommunityData, GetBadgeData, AddBadgesData, AssignBadgesData, GetEventsData, ShareEventsData, InviteEventData, FollowData, GetCostumJsonData, GlobalAutocompleteCostumData, CostumEventRequestActorsData, CostumEventRequestSubeventsData, CostumEventRequestElementEventData, CostumEventRequestCategoriesData, CostumEventRequestDatesData, CostumEventRequestEventData, CostumEventRequestLinkTlToEventData, CostumEventRequestLoadContextTagData, GetGalleryData, GetAttendeesNoAdminData, GetAttendeesAdminData, CoformAnswersSearchData, CoformAnswersByIdData, AddVoteData, AddReportAbuseData, UpdatePathValueData } from "./EndpointApi.types.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Classe EndpointApi générée automatiquement depuis endpoints-copie.json
|
|
@@ -1672,6 +1672,22 @@ export class EndpointApi {
|
|
|
1672
1672
|
return this.callIsConnected("ADD_REPORT_ABUSE", data);
|
|
1673
1673
|
}
|
|
1674
1674
|
|
|
1675
|
+
/**
|
|
1676
|
+
* Mettre à jour une valeur de chemin pour une entité : Met à jour une valeur spécifique dans le chemin donné pour une entité.
|
|
1677
|
+
* Constant : UPDATE_PATH_VALUE
|
|
1678
|
+
* @param data - Données envoyées à l'API
|
|
1679
|
+
* @returns Les données de réponse.
|
|
1680
|
+
* @throws {ApiResponseError} - En cas d'erreur détectée dans la réponse.
|
|
1681
|
+
* @throws {ApiAuthenticationError} - En cas d'erreur d'authentification.
|
|
1682
|
+
* @throws {Error} - En cas d'erreur inattendue.
|
|
1683
|
+
*/
|
|
1684
|
+
async updatePathValue(data: UpdatePathValueData): Promise<any> {
|
|
1685
|
+
if (!data || typeof data !== "object") {
|
|
1686
|
+
throw new TypeError("Le paramètre data doit être un objet.");
|
|
1687
|
+
}
|
|
1688
|
+
return this.callIsConnected("UPDATE_PATH_VALUE", data);
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1675
1691
|
}
|
|
1676
1692
|
|
|
1677
1693
|
export default EndpointApi;
|
|
@@ -4846,3 +4846,27 @@ export interface AddReportAbuseData {
|
|
|
4846
4846
|
};
|
|
4847
4847
|
[k: string]: unknown;
|
|
4848
4848
|
}
|
|
4849
|
+
|
|
4850
|
+
|
|
4851
|
+
export interface UpdatePathValueData {
|
|
4852
|
+
/**
|
|
4853
|
+
* ID de l’utilisateur
|
|
4854
|
+
*/
|
|
4855
|
+
id: string;
|
|
4856
|
+
/**
|
|
4857
|
+
* Collection de l’entité
|
|
4858
|
+
*/
|
|
4859
|
+
collection: "citoyens" | "organizations" | "projects" | "events" | "poi";
|
|
4860
|
+
/**
|
|
4861
|
+
* Chemin de la valeur à mettre à jour
|
|
4862
|
+
*/
|
|
4863
|
+
path: string;
|
|
4864
|
+
arrayForm?: boolean;
|
|
4865
|
+
/**
|
|
4866
|
+
* Valeur à mettre à jour (peut être un objet, un tableau, une chaîne, etc.)
|
|
4867
|
+
*/
|
|
4868
|
+
value: {
|
|
4869
|
+
[k: string]: unknown;
|
|
4870
|
+
};
|
|
4871
|
+
[k: string]: unknown;
|
|
4872
|
+
}
|
package/src/api/Organization.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
GetMembersAdminData,
|
|
8
8
|
GetMembersNoAdminData
|
|
9
9
|
} from "./EndpointApi.types.js";
|
|
10
|
+
import type { OpeningHoursEntry } from "./serverDataType/common.js";
|
|
10
11
|
import type { OrganizationItemNormalized } from "./serverDataType/Organization.js";
|
|
11
12
|
import type { User } from "./User.js";
|
|
12
13
|
|
|
@@ -23,9 +24,72 @@ export class Organization extends BaseEntity<OrganizationItemNormalized> {
|
|
|
23
24
|
"UPDATE_BLOCK_SOCIAL",
|
|
24
25
|
"UPDATE_BLOCK_LOCALITY",
|
|
25
26
|
"UPDATE_BLOCK_SLUG",
|
|
26
|
-
"PROFIL_IMAGE"
|
|
27
|
+
"PROFIL_IMAGE",
|
|
28
|
+
"VIRTUAL_OPENING_HOURS"
|
|
27
29
|
];
|
|
28
30
|
|
|
31
|
+
static override VIRTUAL_SCHEMAS = {
|
|
32
|
+
VIRTUAL_OPENING_HOURS: {
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: {
|
|
35
|
+
openingHours: {
|
|
36
|
+
type: "array",
|
|
37
|
+
description: "Horaires d'ouverture (7 jours de la semaine)",
|
|
38
|
+
minItems: 7,
|
|
39
|
+
maxItems: 7,
|
|
40
|
+
items: {
|
|
41
|
+
oneOf: [
|
|
42
|
+
{
|
|
43
|
+
type: "string",
|
|
44
|
+
const: ""
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
type: "object",
|
|
48
|
+
properties: {
|
|
49
|
+
dayOfWeek: {
|
|
50
|
+
type: "string",
|
|
51
|
+
enum: ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
|
|
52
|
+
description: "Jour de la semaine"
|
|
53
|
+
},
|
|
54
|
+
hours: {
|
|
55
|
+
type: "array",
|
|
56
|
+
description: "Liste des créneaux horaires",
|
|
57
|
+
items: {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties: {
|
|
60
|
+
opens: {
|
|
61
|
+
type: "string",
|
|
62
|
+
pattern: "^([01]\\d|2[0-3]):[0-5]\\d$",
|
|
63
|
+
description: "Heure d'ouverture (HH:MM)"
|
|
64
|
+
},
|
|
65
|
+
closes: {
|
|
66
|
+
type: "string",
|
|
67
|
+
pattern: "^([01]\\d|2[0-3]):[0-5]\\d$",
|
|
68
|
+
description: "Heure de fermeture (HH:MM)"
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
required: ["opens", "closes"],
|
|
72
|
+
additionalProperties: false
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
required: ["dayOfWeek", "hours"],
|
|
77
|
+
additionalProperties: false
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
static override CUSTOM_FIELD_HANDLERS = new Map([
|
|
87
|
+
["openingHours", {
|
|
88
|
+
updateMethod: "updateOpeningHours",
|
|
89
|
+
schemaConstant: "VIRTUAL_OPENING_HOURS"
|
|
90
|
+
}]
|
|
91
|
+
] as const);
|
|
92
|
+
|
|
29
93
|
static ADD_BLOCKS = new Map([
|
|
30
94
|
["ADD_ORGANIZATION", "addOrganization"],
|
|
31
95
|
["PROFIL_IMAGE", "updateImageProfil"]
|
|
@@ -99,6 +163,28 @@ export class Organization extends BaseEntity<OrganizationItemNormalized> {
|
|
|
99
163
|
if (payload.id) delete payload.id;
|
|
100
164
|
let hasChanged = false;
|
|
101
165
|
|
|
166
|
+
// 1. Traiter les champs personnalisés AVANT les block updates
|
|
167
|
+
const customHandlers = Organization.CUSTOM_FIELD_HANDLERS;
|
|
168
|
+
if (customHandlers) {
|
|
169
|
+
const processedFields = new Set<string>();
|
|
170
|
+
|
|
171
|
+
for (const [fieldName, config] of customHandlers) {
|
|
172
|
+
if (fieldName in payload && this._hasFieldChanged(fieldName)) {
|
|
173
|
+
await this._invokeCustomFieldHandler(
|
|
174
|
+
config.updateMethod,
|
|
175
|
+
payload[fieldName],
|
|
176
|
+
fieldName
|
|
177
|
+
);
|
|
178
|
+
processedFields.add(fieldName);
|
|
179
|
+
hasChanged = true;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Retirer les champs traités du payload pour éviter qu'ils soient traités par les blocks
|
|
184
|
+
processedFields.forEach(f => delete payload[f]);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// 2. Traiter les block updates normaux
|
|
102
188
|
for (const [constant, methodName] of Array.from(Organization.UPDATE_BLOCKS)) {
|
|
103
189
|
const blockData = this._extractChangedFieldsFromSchema(
|
|
104
190
|
this.apiClient,
|
|
@@ -338,7 +424,36 @@ export class Organization extends BaseEntity<OrganizationItemNormalized> {
|
|
|
338
424
|
// TODO: qui peut créer une news sur l'organisation ?
|
|
339
425
|
return super.news(newsData);
|
|
340
426
|
}
|
|
341
|
-
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Met à jour les horaires d'ouverture de l'organisation.
|
|
430
|
+
* Utilise UPDATE_PATH_VALUE pour modifier le champ openingHours.
|
|
431
|
+
*
|
|
432
|
+
* @param hours - Tableau de 7 entrées (une par jour de la semaine)
|
|
433
|
+
* @returns Résultat de l'appel API
|
|
434
|
+
* @throws {ApiError} Si l'organisation n'a pas d'ID
|
|
435
|
+
*
|
|
436
|
+
* @example
|
|
437
|
+
* const openingHours = [
|
|
438
|
+
* { dayOfWeek: "Mo", hours: [{ opens: "09:00", closes: "18:00" }] },
|
|
439
|
+
* { dayOfWeek: "Tu", hours: [{ opens: "09:00", closes: "18:00" }] },
|
|
440
|
+
* // ... pour les 7 jours
|
|
441
|
+
* ];
|
|
442
|
+
* await org.updateOpeningHours(openingHours);
|
|
443
|
+
*/
|
|
444
|
+
async updateOpeningHours(hours: OpeningHoursEntry[]): Promise<unknown> {
|
|
445
|
+
if (!this.id) {
|
|
446
|
+
throw new ApiError("L'organisation n'a pas d'ID, impossible de mettre à jour les horaires d'ouverture.", 400);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return this.endpointApi.updatePathValue({
|
|
450
|
+
id: this.id,
|
|
451
|
+
collection: "organizations",
|
|
452
|
+
path: "openingHours",
|
|
453
|
+
value: hours as unknown as { [k: string]: unknown }
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
342
457
|
/**
|
|
343
458
|
* ───────────────────────────────
|
|
344
459
|
* Lien utilisateur ↔ organisation
|