@communecter/cocolight-api-client 1.0.9 → 1.0.11
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/README.md +281 -1
- package/dist/405.cocolight-api-client.browser.js +1 -0
- package/dist/405.cocolight-api-client.cjs +1 -0
- package/dist/790.cocolight-api-client.mjs.js +1 -0
- package/dist/cocolight-api-client.browser.js +3 -3
- package/dist/cocolight-api-client.cjs +1 -1
- package/dist/cocolight-api-client.mjs.js +1 -1
- package/package.json +4 -2
- package/src/Api.js +59 -22
- package/src/ApiClient.js +95 -31
- package/src/api/News.js +129 -88
- package/src/api/Organization.js +248 -166
- package/src/api/Project.js +263 -172
- package/src/api/User.js +355 -49
- package/src/api/UserApi.js +25 -2
- package/src/endpoints.module.js +1 -1
- package/src/index.js +3 -1
- package/src/mixin/DraftStateMixin.js +176 -0
- package/src/mixin/EntityMixin.js +96 -35
- package/src/mixin/MutualEntityMixin.js +48 -0
- package/src/mixin/NewsMixin.js +35 -1
- package/src/mixin/UtilMixin.js +49 -1
- package/src/utils/FileStorageStrategy.node.js +60 -0
- package/src/utils/TokenStorage.js +93 -0
- package/src/utils/createDefaultTokenStorageStrategy.js +45 -0
package/src/api/News.js
CHANGED
|
@@ -1,51 +1,70 @@
|
|
|
1
1
|
import { ApiError } from "../error.js";
|
|
2
|
-
import {
|
|
2
|
+
import { DraftStateMixin } from "../mixin/DraftStateMixin.js";
|
|
3
3
|
import { UtilMixin } from "../mixin/UtilMixin.js";
|
|
4
4
|
|
|
5
5
|
// News.js
|
|
6
6
|
export class News {
|
|
7
|
-
// Champs privés pour protéger l'état
|
|
8
7
|
#draftData = {};
|
|
9
|
-
|
|
8
|
+
#initialDraftData = {};
|
|
10
9
|
#serverData = null;
|
|
11
10
|
|
|
11
|
+
static entityType = "news";
|
|
12
|
+
|
|
13
|
+
static SCHEMA_CONSTANTS = [
|
|
14
|
+
"ADD_NEWS"
|
|
15
|
+
];
|
|
16
|
+
|
|
12
17
|
/**
|
|
13
18
|
* Crée une instance de News.
|
|
14
19
|
* @param {(Organization|Project|User)} parent - L'instance de l'element parent (ex: Organization, Project, User).
|
|
15
|
-
* @param {Object}
|
|
20
|
+
* @param {Object} data - Objet contenant { id }
|
|
16
21
|
* @param {Object} deps - Dépendances injectées (ex: User).
|
|
17
22
|
* @param {EndpointApi} deps.EndpointApi - Classe EndpointApi pour éviter les dépendances circulaires.
|
|
18
23
|
* @param {User} deps.User - Classe User pour éviter les dépendances circulaires.
|
|
19
24
|
*/
|
|
20
25
|
|
|
21
26
|
constructor(parent, data = {}, deps = {}) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (!deps.User)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (!parent) {
|
|
29
|
-
throw new ApiError("Parent is required.");
|
|
30
|
-
}
|
|
27
|
+
this.__entityTag = "News";
|
|
28
|
+
|
|
29
|
+
if (!deps.EndpointApi) throw new ApiError("EndpointApi class must be injected to avoid circular dependency.");
|
|
30
|
+
if (!deps.User) throw new ApiError("User class must be injected.");
|
|
31
|
+
|
|
32
|
+
if (!parent) throw new ApiError("Parent is required.");
|
|
31
33
|
this.deps = deps;
|
|
32
|
-
this.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
this.endpointApi = new deps.EndpointApi(this.apiClient);
|
|
38
|
-
} else if (typeof deps.EndpointApi === "object") {
|
|
39
|
-
this.endpointApi = deps.EndpointApi;
|
|
34
|
+
this.EndpointApiClass = deps.EndpointApi;
|
|
35
|
+
|
|
36
|
+
if (parent?.__entityTag === "User" || parent?.__entityTag === "Organization" || parent?.__entityTag === "Project") {
|
|
37
|
+
this.apiClient = parent.apiClient;
|
|
38
|
+
this.parent = parent;
|
|
40
39
|
} else {
|
|
41
|
-
throw new ApiError("
|
|
40
|
+
throw new ApiError("Invalid parent for News.");
|
|
42
41
|
}
|
|
42
|
+
|
|
43
|
+
this.endpointApi = typeof deps.EndpointApi === "function"
|
|
44
|
+
? new deps.EndpointApi(this.apiClient)
|
|
45
|
+
: (typeof deps.EndpointApi === "object"
|
|
46
|
+
? deps.EndpointApi
|
|
47
|
+
: (() => { throw new ApiError("deps.EndpointApi must be a class or instance."); })());
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
this.#serverData = null;
|
|
43
51
|
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
const { draft, proxy } = this.buildDraftAndProxy({
|
|
53
|
+
data: { ...data, ...this.defaultFields },
|
|
54
|
+
serverData: this.#serverData,
|
|
55
|
+
constant: News.SCHEMA_CONSTANTS,
|
|
56
|
+
apiClient: this.apiClient,
|
|
57
|
+
transforms: this.transforms,
|
|
58
|
+
removeFields: this.removeFields
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
this.#initialDraftData = JSON.parse(JSON.stringify(draft)); // snapshot propre
|
|
62
|
+
this.#draftData = draft;
|
|
63
|
+
this.data = proxy;
|
|
46
64
|
|
|
47
65
|
}
|
|
48
66
|
|
|
67
|
+
|
|
49
68
|
// Getters en lecture seule pour chaque propriété
|
|
50
69
|
get id() {
|
|
51
70
|
return this.#draftData.id || null;
|
|
@@ -58,6 +77,10 @@ export class News {
|
|
|
58
77
|
get draftData() {
|
|
59
78
|
return this.#draftData;
|
|
60
79
|
}
|
|
80
|
+
|
|
81
|
+
get initialDraftData() {
|
|
82
|
+
return this.#initialDraftData;
|
|
83
|
+
}
|
|
61
84
|
|
|
62
85
|
get serverData() {
|
|
63
86
|
return this.#serverData;
|
|
@@ -71,18 +94,41 @@ export class News {
|
|
|
71
94
|
return this.isConnected && this.userId === this.parent.id;
|
|
72
95
|
}
|
|
73
96
|
|
|
97
|
+
_setData(newData) {
|
|
98
|
+
this.#serverData = { ...newData };
|
|
99
|
+
|
|
100
|
+
const { draft, proxy } = this.buildDraftAndProxy({
|
|
101
|
+
data: { ...newData, ...this.defaultFields },
|
|
102
|
+
serverData: this.#serverData,
|
|
103
|
+
constant: News.SCHEMA_CONSTANTS,
|
|
104
|
+
apiClient: this.apiClient,
|
|
105
|
+
transforms: this.transforms,
|
|
106
|
+
removeFields: this.removeFields
|
|
107
|
+
});
|
|
108
|
+
this.#initialDraftData = JSON.parse(JSON.stringify(draft));
|
|
109
|
+
this.#draftData = draft;
|
|
110
|
+
this.data = proxy;
|
|
111
|
+
}
|
|
112
|
+
|
|
74
113
|
getEntityType() {
|
|
75
|
-
return
|
|
114
|
+
return News.entityType;
|
|
76
115
|
}
|
|
77
116
|
|
|
78
117
|
static fromServerData(data, parent, deps) {
|
|
79
|
-
const instance = new News(parent, {
|
|
80
|
-
|
|
81
|
-
// Injecte les données serveur
|
|
118
|
+
const instance = new News(parent, {}, deps);
|
|
82
119
|
instance.#serverData = { ...data };
|
|
83
120
|
|
|
84
|
-
|
|
85
|
-
|
|
121
|
+
const { draft, proxy } = instance.buildDraftAndProxy({
|
|
122
|
+
data: { ...data, ...instance.defaultFields },
|
|
123
|
+
serverData: instance.#serverData,
|
|
124
|
+
constant: News.SCHEMA_CONSTANTS,
|
|
125
|
+
apiClient: instance.apiClient,
|
|
126
|
+
transforms: instance.transforms,
|
|
127
|
+
removeFields: instance.removeFields
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
instance.#draftData = draft;
|
|
131
|
+
instance.data = proxy;
|
|
86
132
|
|
|
87
133
|
return instance;
|
|
88
134
|
}
|
|
@@ -97,64 +143,23 @@ export class News {
|
|
|
97
143
|
* Constant : GET_NEWS_BY_ID
|
|
98
144
|
*/
|
|
99
145
|
async get() {
|
|
100
|
-
if(!this.id)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
146
|
+
if (!this.id) throw new ApiError("Impossible de rafraîchir sans ID.");
|
|
147
|
+
|
|
148
|
+
const newsArray = await this.callIsConnected(() =>
|
|
149
|
+
this.endpointApi.getNewsById({ ids: [this.id] })
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
if (newsArray && Array.isArray(newsArray) && newsArray.length === 1) {
|
|
153
|
+
const data = newsArray[0];
|
|
154
|
+
this.#serverData = { ...data };
|
|
155
|
+
|
|
156
|
+
this._setData(data);
|
|
157
|
+
|
|
107
158
|
return this.#serverData;
|
|
108
159
|
}
|
|
109
160
|
throw new ApiError(`Aucune actualité trouvée pour l'ID ${this.id}`);
|
|
110
161
|
}
|
|
111
162
|
|
|
112
|
-
_getDraftFromServerData(data) {
|
|
113
|
-
// je veux copier que certaine info si présente dans le draftData
|
|
114
|
-
// - newsArray[0].scope.type > draftData.scope
|
|
115
|
-
// - newsArray[0].text > draftData.text
|
|
116
|
-
// - newsArray[0].tags > draftData.tags
|
|
117
|
-
// - newsArray[0].mentions > draftData.mentions > draftData.mentions.count integer
|
|
118
|
-
// - newsArray[0].mediaImg > draftData.mediaImg > draftData.mediaImg.images > un array id
|
|
119
|
-
// - newsArray[0].mediaFile > draftData.mediaFile > draftData.mediaFile.files > un array id
|
|
120
|
-
const transformed = this._pickProps(
|
|
121
|
-
data,
|
|
122
|
-
["scope", "text", "tags", "mentions", "mediaImg", "mediaFile"],
|
|
123
|
-
{
|
|
124
|
-
scope: (val) => val?.type,
|
|
125
|
-
mentions: (val) =>
|
|
126
|
-
Array.isArray(val)
|
|
127
|
-
? val.map((mention) => ({
|
|
128
|
-
...mention,
|
|
129
|
-
count: parseInt(mention.count)
|
|
130
|
-
}))
|
|
131
|
-
: [],
|
|
132
|
-
mediaImg: (val) => {
|
|
133
|
-
const images = val?.images?.map((img) => img.id).filter(Boolean) || [];
|
|
134
|
-
return images.length > 0
|
|
135
|
-
? {
|
|
136
|
-
countImages: parseInt(val.countImages) || images.length,
|
|
137
|
-
images
|
|
138
|
-
}
|
|
139
|
-
: undefined;
|
|
140
|
-
},
|
|
141
|
-
mediaFile: (val) => {
|
|
142
|
-
const files = val?.files?.map((file) => file.id).filter(Boolean) || [];
|
|
143
|
-
return files.length > 0
|
|
144
|
-
? {
|
|
145
|
-
countFiles: parseInt(val.countFiles) || files.length,
|
|
146
|
-
files
|
|
147
|
-
}
|
|
148
|
-
: undefined;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
id: data.id,
|
|
155
|
-
...Object.fromEntries(Object.entries(transformed).filter(([, v]) => v !== undefined))
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
163
|
|
|
159
164
|
/**
|
|
160
165
|
* Ajouter une actualité : Ajoute une nouvelle actualité.
|
|
@@ -162,6 +167,10 @@ export class News {
|
|
|
162
167
|
*/
|
|
163
168
|
async save() {
|
|
164
169
|
|
|
170
|
+
if(!this.isConnected){
|
|
171
|
+
throw new ApiError("Impossible de sauvegarder sans être connecté.");
|
|
172
|
+
}
|
|
173
|
+
|
|
165
174
|
// si le texte est vide, on met un espace pour que le champ soit pris en compte car sur le serveur
|
|
166
175
|
// il y a une vérification de la taille du texte je pense
|
|
167
176
|
if(this.#draftData?.text === ""){
|
|
@@ -203,8 +212,8 @@ export class News {
|
|
|
203
212
|
if (!slug && !id) {
|
|
204
213
|
throw new ApiError("Vous devez fournir un slug ou un id pour ajouter une mention.");
|
|
205
214
|
}
|
|
206
|
-
const userInstance = new this.
|
|
207
|
-
const user =
|
|
215
|
+
const userInstance = new this.deps.User(this.apiClient, { id, slug }, { EndpointApi: this.endpointApi });
|
|
216
|
+
const user = userInstance.serverData;
|
|
208
217
|
if (!this.#draftData.mentions) {
|
|
209
218
|
this.#draftData.mentions = [];
|
|
210
219
|
}
|
|
@@ -229,6 +238,7 @@ export class News {
|
|
|
229
238
|
|
|
230
239
|
}
|
|
231
240
|
|
|
241
|
+
|
|
232
242
|
/**
|
|
233
243
|
* Ajouter une image à une actualité : Ajoute une images à une actualité.
|
|
234
244
|
* Constant : ADD_IMAGE_NEWS
|
|
@@ -278,9 +288,40 @@ export class News {
|
|
|
278
288
|
this.#draftData.id = null;
|
|
279
289
|
this._isDeleted = true;
|
|
280
290
|
}
|
|
281
|
-
|
|
291
|
+
|
|
292
|
+
_updateInitialDraftSnapshot() {
|
|
293
|
+
this.#initialDraftData = JSON.parse(JSON.stringify(this.#draftData));
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
hasChanges() {
|
|
297
|
+
return JSON.stringify(this.#draftData) !== JSON.stringify(this.#initialDraftData);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
defaultFields = {
|
|
301
|
+
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
removeFields = [
|
|
305
|
+
|
|
306
|
+
];
|
|
307
|
+
|
|
308
|
+
transforms = {
|
|
309
|
+
scope: val => val?.type,
|
|
310
|
+
mentions: val =>
|
|
311
|
+
Array.isArray(val)
|
|
312
|
+
? val.map(m => ({ ...m, count: parseInt(m.count) }))
|
|
313
|
+
: [],
|
|
314
|
+
mediaImg: val => {
|
|
315
|
+
const images = val?.images?.map(img => img.id).filter(Boolean) || [];
|
|
316
|
+
return images.length > 0 ? { countImages: images.length, images } : undefined;
|
|
317
|
+
},
|
|
318
|
+
mediaFile: val => {
|
|
319
|
+
const files = val?.files?.map(f => f.id).filter(Boolean) || [];
|
|
320
|
+
return files.length > 0 ? { countFiles: files.length, files } : undefined;
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
|
|
282
324
|
}
|
|
283
325
|
|
|
284
326
|
// Incorporation du mixin dans Organization
|
|
285
|
-
Object.assign(News.prototype, UtilMixin,
|
|
286
|
-
|
|
327
|
+
Object.assign(News.prototype, UtilMixin, DraftStateMixin);
|