@communecter/cocolight-api-client 1.0.127 → 1.0.129

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.
@@ -3,6 +3,7 @@ import { BaseEntity } from "./BaseEntity.js";
3
3
  import { createSocialTransform, transformEntityRefs } from "../types/transforms.js";
4
4
 
5
5
 
6
+ import type { Action } from "./Action.js";
6
7
  import type { PaginatorPage, PaginatorState } from "./BaseEntity.js";
7
8
  import type { AddProjectData, GetContributorsAdminData, GetContributorsNoAdminData } from "./EndpointApi.types.js";
8
9
  import type { Organization } from "./Organization.js";
@@ -231,6 +232,11 @@ export class Project extends BaseEntity<ProjectItemNormalized> {
231
232
  * // Récupérer les contributeurs en attente d'invitation
232
233
  * const invitingContributors = await project.getContributors({}, { isInviting: true });
233
234
  *
235
+ * // Restreindre la recherche : uniquement les citoyens
236
+ * const onlyCitoyens = await project.getContributors({}, { searchType: "citoyens" });
237
+ *
238
+ * // Restreindre la recherche : uniquement les organisations
239
+ * const onlyOrgas = await project.getContributors({}, { searchType: "organizations" });
234
240
  */
235
241
  async getContributors(
236
242
  data: Partial<GetContributorsAdminData | GetContributorsNoAdminData> = {},
@@ -240,11 +246,19 @@ export class Project extends BaseEntity<ProjectItemNormalized> {
240
246
  isAdminPending?: boolean;
241
247
  isInviting?: boolean;
242
248
  roles?: any[];
249
+ searchType?: "all" | "citoyens" | "organizations";
243
250
  restoredState?: PaginatorState;
244
251
  } = {}
245
252
  ): Promise<PaginatorPage<User | Organization>> {
246
- data.searchType = this._getDefaultFromEndpoint("GET_CONTRIBUTORS_ADMIN", "searchType") as GetContributorsAdminData["searchType"];
247
- // data.searchBy = "ALL";
253
+ const allTypes = this._getDefaultFromEndpoint("GET_CONTRIBUTORS_ADMIN", "searchType") as GetContributorsAdminData["searchType"];
254
+ if (options.searchType === "citoyens") {
255
+ data.searchType = ["citoyens"];
256
+ } else if (options.searchType === "organizations") {
257
+ data.searchType = allTypes.filter(t => t !== "citoyens") as GetContributorsAdminData["searchType"];
258
+ } else {
259
+ // "all" ou omis : on initialise explicitement (le paginator exige searchType avant la validation AJV)
260
+ data.searchType = allTypes;
261
+ }
248
262
 
249
263
  const paginator = this._createPaginatorEngine({
250
264
  initialData: data,
@@ -342,10 +356,25 @@ export class Project extends BaseEntity<ProjectItemNormalized> {
342
356
  * Crée une instance de news et la récupère si nécessaire.
343
357
  */
344
358
  override async news(newsData: Parameters<BaseEntity<ProjectItemNormalized>["news"]>[0] = {}) {
345
- // TODO: qui peut créer une news sur le projet ?
359
+ if(!newsData?.id && !this.isContributor()){
360
+ throw new ApiError("Vous n'avez pas les droits pour créer une news dans ce projet", 403);
361
+ }
346
362
  return super.news(newsData);
347
363
  }
348
364
 
365
+ /**
366
+ * {@inheritDoc BaseEntity#action}
367
+ *
368
+ * Crée une instance d'Action liée à ce projet et la récupère si nécessaire.
369
+ */
370
+ override async action(actionData: Parameters<BaseEntity<ProjectItemNormalized>["action"]>[0] = {}) {
371
+ if(!actionData?.id && !this.isAdmin()){
372
+ throw new ApiError("Vous n'avez pas les droits pour créer une action dans ce projet", 403);
373
+ }
374
+ const entity = await this.entity("actions", actionData);
375
+ return entity as Action;
376
+ }
377
+
349
378
  /**
350
379
  * ───────────────────────────────
351
380
  * Lien utilisateur ↔ projet
package/src/api/User.ts CHANGED
@@ -113,6 +113,7 @@ export class User extends BaseEntity<UserItemNormalized> {
113
113
  Comment: typeof import("./Comment.js").Comment;
114
114
  Answer: typeof import("./Answer.js").Answer;
115
115
  Classified?: typeof import("./Classified.js").Classified;
116
+ Action?: typeof import("./Action.js").Action;
116
117
  }
117
118
  ) {
118
119
  if(!deps.EndpointApi){
@@ -1,5 +1,6 @@
1
1
  import ApiClient from "../ApiClient.js";
2
2
  import { ApiError, ApiResponseError } from "../error.js";
3
+ import { Action } from "./Action.js";
3
4
  import { Answer } from "./Answer.js";
4
5
  import { Badge } from "./Badge.js";
5
6
  import { Classified } from "./Classified.js";
@@ -68,7 +69,7 @@ export class UserApi {
68
69
  this.loggedUser = new User(
69
70
  this.client,
70
71
  response.data.user,
71
- { EndpointApi, Organization, Project, Event, Poi, Badge, News, Comment, Answer, Classified }
72
+ { EndpointApi, Organization, Project, Event, Poi, Badge, News, Comment, Answer, Classified, Action }
72
73
  );
73
74
  return this.loggedUser;
74
75
  });
@@ -90,7 +91,7 @@ export class UserApi {
90
91
  this.loggedUser = new User(
91
92
  this.client,
92
93
  { id: this.client.userId },
93
- { EndpointApi, Organization, Project, Event, Poi, Badge, News, Comment, Answer, Classified }
94
+ { EndpointApi, Organization, Project, Event, Poi, Badge, News, Comment, Answer, Classified, Action }
94
95
  );
95
96
 
96
97
  return this.loggedUser;
@@ -0,0 +1,177 @@
1
+ import type {
2
+ IdObject,
3
+ LinkContributorsRef,
4
+ ParentsMap,
5
+ DateValue,
6
+ } from "./common.js";
7
+ import type EJSONType from "../../EJSONType.js";
8
+
9
+ type ObjectIDCtor = typeof EJSONType["ObjectID"];
10
+ type ObjectID = InstanceType<ObjectIDCtor>;
11
+
12
+ /**
13
+ * Statuts supportés par une action (cf. COSTUM_PROJECT_ACTION_REQUEST_NEW).
14
+ */
15
+ export const ACTION_STATUSES = [
16
+ "todo",
17
+ "done",
18
+ "tracking",
19
+ "discuter",
20
+ "next",
21
+ "totest",
22
+ "disabled",
23
+ "closed"
24
+ ] as const;
25
+
26
+ export type ActionStatus = (typeof ACTION_STATUSES)[number];
27
+
28
+ export interface ActionLinksBlock {
29
+ contributors?: Record<string, LinkContributorsRef>;
30
+ [k: string]: unknown;
31
+ }
32
+
33
+ export interface ActionMilestoneRef {
34
+ milestoneId: string;
35
+ startDate?: DateValue;
36
+ endDate?: DateValue;
37
+ }
38
+
39
+ export interface ActionCounts {
40
+ contributors?: number;
41
+ [k: string]: unknown;
42
+ }
43
+
44
+ /**
45
+ * Historique des changements de statut (alimenté par /set_status côté backend).
46
+ * `update` est un MongoDate (DateValue côté Json, Date côté Normalized).
47
+ */
48
+ export interface ActionUpdateStatusEntryJson {
49
+ status: ActionStatus;
50
+ author: string;
51
+ update: DateValue;
52
+ }
53
+
54
+ export interface ActionUpdateStatusEntryNormalized {
55
+ status: ActionStatus;
56
+ author: string;
57
+ update: Date;
58
+ }
59
+
60
+ /**
61
+ * Sous-tâche d'une action. Stockée dans `tasks[]`.
62
+ */
63
+ export interface ActionTaskJson {
64
+ taskId?: string;
65
+ task?: string;
66
+ checked?: boolean;
67
+ userId?: string;
68
+ contributors?: Record<string, unknown>;
69
+ timeSpent?: number;
70
+ createdAt?: DateValue;
71
+ checkedAt?: DateValue;
72
+ [key: string]: unknown;
73
+ }
74
+
75
+ export interface ActionTaskNormalized {
76
+ taskId?: string;
77
+ task?: string;
78
+ checked?: boolean;
79
+ userId?: string;
80
+ contributors?: Record<string, unknown>;
81
+ timeSpent?: number;
82
+ createdAt?: Date;
83
+ checkedAt?: Date;
84
+ [key: string]: unknown;
85
+ }
86
+
87
+ /**
88
+ * Bloc media : galerie d'images + fichiers attachés (par IDs de documents).
89
+ */
90
+ export interface ActionMedia {
91
+ type?: string;
92
+ countImages?: number;
93
+ images?: string[];
94
+ files?: string[];
95
+ [k: string]: unknown;
96
+ }
97
+
98
+ export interface ActionMediaFile {
99
+ files?: string[];
100
+ [k: string]: unknown;
101
+ }
102
+
103
+ export interface ActionItemJson {
104
+ _id: IdObject;
105
+ collection: "actions";
106
+ name: string;
107
+ description?: string;
108
+ status?: ActionStatus;
109
+ created?: DateValue;
110
+ updated?: DateValue;
111
+ modified?: DateValue;
112
+ startDate?: DateValue;
113
+ endDate?: DateValue;
114
+ parentId: string;
115
+ parentType: string;
116
+ parent?: ParentsMap;
117
+ tags?: string[];
118
+ links?: ActionLinksBlock;
119
+ creator?: string;
120
+ idUserAuthor?: string;
121
+ credits?: string;
122
+ idParentRoom?: string;
123
+ milestone?: ActionMilestoneRef;
124
+ importance?: string;
125
+ counts?: ActionCounts;
126
+ url?: string;
127
+ min?: number;
128
+ max?: number;
129
+ timeSpent?: number;
130
+ tracking?: boolean;
131
+ updateStatus?: ActionUpdateStatusEntryJson[];
132
+ rc?: unknown[];
133
+ tasks?: ActionTaskJson[];
134
+ media?: ActionMedia;
135
+ mediaFile?: ActionMediaFile;
136
+ [key: string]: unknown;
137
+ }
138
+
139
+ export interface ActionItemNormalized {
140
+ id: string;
141
+ _id: ObjectID;
142
+ collection: "actions";
143
+ name: string;
144
+ description?: string;
145
+ status?: ActionStatus;
146
+ created?: Date;
147
+ updated?: Date;
148
+ modified?: Date;
149
+ startDate?: Date;
150
+ endDate?: Date;
151
+ parentId: string;
152
+ parentType: string;
153
+ parent?: ParentsMap;
154
+ tags?: string[];
155
+ links?: ActionLinksBlock;
156
+ creator?: string;
157
+ idUserAuthor?: string;
158
+ credits?: number;
159
+ idParentRoom?: string;
160
+ milestone?: Omit<ActionMilestoneRef, "startDate" | "endDate"> & {
161
+ startDate?: Date;
162
+ endDate?: Date;
163
+ };
164
+ importance?: string;
165
+ counts?: ActionCounts;
166
+ url?: string;
167
+ min?: number;
168
+ max?: number;
169
+ timeSpent?: number;
170
+ tracking?: boolean;
171
+ updateStatus?: ActionUpdateStatusEntryNormalized[];
172
+ rc?: unknown[];
173
+ tasks?: ActionTaskNormalized[];
174
+ media?: ActionMedia;
175
+ mediaFile?: ActionMediaFile;
176
+ [key: string]: unknown;
177
+ }