@edifice.io/communities-tests 1.0.0-develop-pedago.9.1753990538887 → 1.1.3

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.
@@ -36,10 +36,10 @@ import {
36
36
  } from "./utils/_membership-api.utils.ts";
37
37
 
38
38
  // Import invitation API utils for join workflow
39
- import {
39
+ import {
40
40
  joinCommunity,
41
41
  updateRequestStatus,
42
- InvitationStatus
42
+ InvitationStatus,
43
43
  } from "./utils/_invitation-api.utils.ts";
44
44
 
45
45
  chai.config.logFailures = true;
@@ -62,7 +62,7 @@ export const options = {
62
62
  };
63
63
 
64
64
  const timestamp = new Date().toISOString();
65
- const schoolName = `IT Community Memberships`;
65
+ const schoolName = `IT Community`;
66
66
 
67
67
  export function setup(): Structure {
68
68
  let structure: Structure = {} as Structure;
@@ -131,7 +131,7 @@ export function testMembershipApi(structure: Structure) {
131
131
  console.log(`Retrieved secret code: ${secretCode}`);
132
132
  });
133
133
 
134
- // Step 3: Member creates join request with secret code
134
+ // Step 3: Member creates join request with secret code
135
135
  describe("Member creates join request with secret code", () => {
136
136
  // Authenticate as member
137
137
  logout();
@@ -144,29 +144,31 @@ export function testMembershipApi(structure: Structure) {
144
144
  const joinRequest = joinCommunity(secretCode);
145
145
  check(joinRequest, {
146
146
  "Join request created successfully": (r) => r !== null,
147
- "Join request has REQUEST status": (r) =>
147
+ "Join request has REQUEST status": (r) =>
148
148
  r !== null && r.status === InvitationStatus.REQUEST,
149
149
  });
150
-
150
+
151
151
  // Store the invitation ID and user ID for later approval
152
152
  const invitationId = joinRequest?.id;
153
153
  currentUserId = Number(joinRequest?.receiver?.id);
154
- console.log(`Created join request with ID: ${invitationId} for user ID: ${currentUserId}`);
155
-
154
+ console.log(
155
+ `Created join request with ID: ${invitationId} for user ID: ${currentUserId}`,
156
+ );
157
+
156
158
  // Step 4: Admin approves the join request
157
159
  logout();
158
160
  authenticateWeb(adminUser.login, "password");
159
-
161
+
160
162
  // Approve join request
161
163
  const approvedRequest = updateRequestStatus(
162
- communityId,
163
- invitationId!,
164
- InvitationStatus.REQUEST_ACCEPTED
164
+ communityId,
165
+ invitationId!,
166
+ InvitationStatus.REQUEST_ACCEPTED,
165
167
  );
166
-
168
+
167
169
  check(approvedRequest, {
168
170
  "Join request approved successfully": (r) => r !== null,
169
- "Status changed to REQUEST_ACCEPTED": (r) =>
171
+ "Status changed to REQUEST_ACCEPTED": (r) =>
170
172
  r !== null && r.status === InvitationStatus.REQUEST_ACCEPTED,
171
173
  });
172
174
  });
@@ -264,19 +266,19 @@ export function testMembershipApi(structure: Structure) {
264
266
  check(joinRequest, {
265
267
  "Join request created successfully": (r) => r !== null,
266
268
  });
267
-
269
+
268
270
  // Store the invitation ID
269
271
  const invitationId = joinRequest?.id;
270
-
272
+
271
273
  // Admin approves the request
272
274
  logout();
273
275
  authenticateWeb(adminUser.login, "password");
274
-
276
+
275
277
  // Approve join request
276
278
  updateRequestStatus(
277
- communityId,
278
- invitationId!,
279
- InvitationStatus.REQUEST_ACCEPTED
279
+ communityId,
280
+ invitationId!,
281
+ InvitationStatus.REQUEST_ACCEPTED,
280
282
  );
281
283
 
282
284
  // Admin removes the member
@@ -357,12 +359,12 @@ export function testMembershipApi(structure: Structure) {
357
359
  authenticateWeb(adminUser.login, "password");
358
360
  for (let i = 0; i < testMemberInvitationIds.length; i++) {
359
361
  updateRequestStatus(
360
- communityId,
361
- testMemberInvitationIds[i],
362
- InvitationStatus.REQUEST_ACCEPTED
362
+ communityId,
363
+ testMemberInvitationIds[i],
364
+ InvitationStatus.REQUEST_ACCEPTED,
363
365
  );
364
366
  }
365
-
367
+
366
368
  // Verify all users are now members
367
369
  const membersBeforeRemoval = listCommunityMembers(communityId);
368
370
  check(membersBeforeRemoval, {
@@ -84,7 +84,7 @@ export const options = {
84
84
  },
85
85
  };
86
86
 
87
- const schoolName = `IT Community Permissions Tests V2`;
87
+ const schoolName = `IT Community`;
88
88
  // Setup function to create structure and configure roles
89
89
  export function setup(): StructureWithRole {
90
90
  let structure: StructureWithRole = {} as StructureWithRole;
@@ -38,6 +38,7 @@ import {
38
38
  SortDirection,
39
39
  listResourcesWithSearch,
40
40
  } from "./utils/_resource-api.utils.ts";
41
+ import { createFolder, Folder } from "./utils/_folders-api.utils.ts";
41
42
 
42
43
  chai.config.logFailures = true;
43
44
 
@@ -60,7 +61,7 @@ export const options = {
60
61
 
61
62
  // Generate unique timestamp for test resources
62
63
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
63
- const schoolName = `Resources Search Sort Test ${timestamp}`;
64
+ const schoolName = `IT Community`;
64
65
 
65
66
  /**
66
67
  * Setup function to prepare test environment and assign permissions
@@ -102,7 +103,7 @@ export function testResourcesSearchSort(structure: Structure) {
102
103
  };
103
104
 
104
105
  // Resource test data
105
- const resourceTestData = [
106
+ let resourceTestData = [
106
107
  {
107
108
  type: ResourceType.ENT,
108
109
  appName: AppName.EXTERNAL_LINK,
@@ -136,6 +137,7 @@ export function testResourcesSearchSort(structure: Structure) {
136
137
  appName: AppName.EXTERNAL_LINK,
137
138
  title: "Epsilon Blog Resource",
138
139
  resourceUrl: "https://example.com/delta",
140
+ folderId: -1, // Placeholder. Folder id will be updated once the test folder is created
139
141
  },
140
142
  ];
141
143
 
@@ -143,6 +145,7 @@ export function testResourcesSearchSort(structure: Structure) {
143
145
  let adminUser: UserInfo;
144
146
  let memberUser: UserInfo;
145
147
  const resourceIds: number[] = [];
148
+ let folderId: number;
146
149
 
147
150
  describe("[Resource Search and Sort API Test]", () => {
148
151
  // Get test users as admin
@@ -163,6 +166,18 @@ export function testResourcesSearchSort(structure: Structure) {
163
166
  communityId = Number(createCommunityOrFail(communityData));
164
167
  console.log(`Created community with ID: ${communityId}`);
165
168
 
169
+ const folder = createFolder(communityId, { name: "Test Folder" })
170
+ .value as Folder;
171
+ folderId = folder.id;
172
+ console.log(`Created folder with ID: ${folderId}`);
173
+ // Assign correct folder id to resource data with folderId property
174
+ resourceTestData = resourceTestData.map((resource) => {
175
+ if (typeof resource.folderId !== "undefined") {
176
+ resource.folderId = folderId;
177
+ }
178
+ return resource;
179
+ });
180
+
166
181
  // Create test resources with small delay between them for reliable date sorting
167
182
  for (const data of resourceTestData) {
168
183
  const resource = createResource(communityId, data);
@@ -310,6 +325,30 @@ export function testResourcesSearchSort(structure: Structure) {
310
325
  });
311
326
  });
312
327
 
328
+ // Test filtering by folder ID
329
+ group("Filter by folder ID", () => {
330
+ const folderSearch = listResourcesWithSearch(communityId, {
331
+ folderId,
332
+ });
333
+ check(folderSearch, {
334
+ "Filtering by folder ID returns results": (r) =>
335
+ r !== null && r.items && r.items.length > 0,
336
+ "All results are in correct folder": (r) =>
337
+ r !== null &&
338
+ r.items &&
339
+ r.items.every((item) => item.folderId == folderId),
340
+ });
341
+ const rootResources = listResourcesWithSearch(communityId);
342
+ check(rootResources, {
343
+ "Not providing folder ID returns results": (r) =>
344
+ r !== null && r.items && r.items.length > 0,
345
+ "All results have no folder defined": (r) =>
346
+ r !== null &&
347
+ r.items &&
348
+ r.items.every((item) => item.folderId === undefined),
349
+ });
350
+ });
351
+
313
352
  // Test sorting capabilities
314
353
  group("Sort resources by different fields", () => {
315
354
  // Test sorting by addedDate ASC
@@ -325,22 +364,29 @@ export function testResourcesSearchSort(structure: Structure) {
325
364
 
326
365
  // Verify ASC order - first item should have earliest date
327
366
  if (dateAsc && dateAsc.items && dateAsc.items.length > 1) {
328
- const dateArray = dateAsc.items.map(item => new Date(item.addedDate).getTime());
329
-
367
+ const dateArray = dateAsc.items.map((item) =>
368
+ new Date(item.addedDate).getTime(),
369
+ );
370
+
330
371
  // Log dates to help debug sorting issues
331
- console.log("Dates in ASC order:", dateArray.map(d => new Date(d).toISOString()));
332
-
372
+ console.log(
373
+ "Dates in ASC order:",
374
+ dateArray.map((d) => new Date(d).toISOString()),
375
+ );
376
+
333
377
  const sortedCorrectly = dateArray.slice(1).every((curr, i) => {
334
378
  const prev = dateArray[i];
335
379
  const isCorrectlySorted = curr >= prev;
336
-
380
+
337
381
  if (!isCorrectlySorted) {
338
- console.log(`Sorting issue at index ${i}: ${new Date(prev).toISOString()} should be <= ${new Date(curr).toISOString()}`);
382
+ console.log(
383
+ `Sorting issue at index ${i}: ${new Date(prev).toISOString()} should be <= ${new Date(curr).toISOString()}`,
384
+ );
339
385
  }
340
-
386
+
341
387
  return isCorrectlySorted;
342
388
  });
343
-
389
+
344
390
  check(dateAsc, {
345
391
  "Resources are correctly sorted by date ASC": () => sortedCorrectly,
346
392
  });
@@ -465,7 +511,10 @@ export function testResourcesSearchSort(structure: Structure) {
465
511
  "First page returns correct number of items": (r) =>
466
512
  r !== null && r.items && r.items.length === 2,
467
513
  [`First page has correct pagination metadata`]: (r) =>
468
- r !== null && r.meta && r.meta.currentPage === 1 && r.meta.itemCount === 2,
514
+ r !== null &&
515
+ r.meta &&
516
+ r.meta.currentPage === 1 &&
517
+ r.meta.itemCount === 2,
469
518
  });
470
519
 
471
520
  // Get second page
@@ -477,7 +526,10 @@ export function testResourcesSearchSort(structure: Structure) {
477
526
  check(secondPage, {
478
527
  "Second page returns results": (r) => r !== null && !!r.items,
479
528
  "Second page has correct pagination metadata": (r) =>
480
- r !== null && r.meta && r.meta.currentPage === 2 && r.meta.itemCount === 2,
529
+ r !== null &&
530
+ r.meta &&
531
+ r.meta.currentPage === 2 &&
532
+ r.meta.itemCount === 2,
481
533
  "Pages return different resources": (r) => {
482
534
  if (!r || !r.items || !firstPage || !firstPage.items) return false;
483
535
 
@@ -59,7 +59,7 @@ export const options = {
59
59
  };
60
60
 
61
61
  const timestamp = new Date().toISOString();
62
- const schoolName = `IT Resources Test`;
62
+ const schoolName = `IT Community`;
63
63
 
64
64
  // List of app types to test
65
65
  // You can adjust this list based on which app types you want to test
@@ -156,12 +156,7 @@ export function testResourcesApi(structure: Structure) {
156
156
  for (const appType of APP_TYPES_TO_TEST) {
157
157
  group(`Testing ${appType} resources`, () => {
158
158
  const resource = DEFAULT_TEST_CONFIGS[appType];
159
- testResourceManagement(
160
- communityId,
161
- resource,
162
- adminUser,
163
- memberUser,
164
- );
159
+ testResourceManagement(communityId, resource, adminUser, memberUser);
165
160
  });
166
161
  }
167
162
 
@@ -0,0 +1,195 @@
1
+ import http, { RefinedResponse } from "k6/http";
2
+ import { getHeaders } from "../../../node_modules/edifice-k6-commons/dist/index.js";
3
+
4
+ //Types
5
+ export type User = {
6
+ id: number;
7
+ displayName: string;
8
+ entId: string;
9
+ profile: string;
10
+ };
11
+
12
+ export type Media = {
13
+ id: string;
14
+ name: string;
15
+ type: string;
16
+ mimeType: string;
17
+ url: string;
18
+ };
19
+
20
+ export type Announcement = {
21
+ id: number;
22
+ content: string;
23
+ media: Media[];
24
+ publicationDate: string;
25
+ modificationDate: string;
26
+ author: User;
27
+ modifier: User;
28
+ communityId: number;
29
+ };
30
+
31
+ export type AnnouncementCount = {
32
+ count: number;
33
+ };
34
+
35
+ export type CreateAnnouncementParams = {
36
+ content: string;
37
+ media: Media[];
38
+ };
39
+
40
+ export type UpdateAnnouncementParams = {
41
+ content: string;
42
+ media: Media[];
43
+ };
44
+
45
+ export type PaginatedAnnouncements = {
46
+ items: Announcement[];
47
+ meta: {
48
+ totalItems: number;
49
+ currentPage: number;
50
+ itemCount: number;
51
+ totalPages: number;
52
+ };
53
+ };
54
+
55
+ const rootUrl = __ENV.ROOT_URL || "";
56
+ function baseUrl(id: number): string {
57
+ return `${rootUrl}/communities/api/communities/${id}/announcements`;
58
+ }
59
+ function makeHeaders(): object {
60
+ return {
61
+ headers: { ...getHeaders(), "Content-Type": "application/json" },
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Create a new announcement
67
+ * @param communityId Community ID
68
+ * @param announcementData announcement creation data
69
+ * @returns HTTP response
70
+ */
71
+ export function createAnnouncement(
72
+ communityId: number,
73
+ announcementData: CreateAnnouncementParams,
74
+ ): RefinedResponse<undefined> {
75
+ return http.post<undefined>(
76
+ `${baseUrl(communityId)}`,
77
+ JSON.stringify(announcementData),
78
+ makeHeaders(),
79
+ );
80
+ }
81
+
82
+ /**
83
+ * List all announcements with pagination
84
+ * @param communityId Community ID
85
+ * @param page Page number (default: 1)
86
+ * @param limit Items per page (default: 10)
87
+ * @param publishedAfter Date to filter announcements from (optional)
88
+ * @param sortBy 'publicationDate' or 'ModificationDate' (optional)
89
+ * @param sortDirection 'ASC' or 'DESC' (optional)
90
+ * @returns List of announcements or null if failed
91
+ */
92
+ export function listAnnouncements(
93
+ communityId: number,
94
+ page: number = 1,
95
+ limit: number = 10,
96
+ publishedAfter: string | null = null,
97
+ sortBy: string | null = null,
98
+ sortDirection: string | null = null,
99
+ ): PaginatedAnnouncements | null {
100
+ let urlParams: string = "";
101
+ if (publishedAfter != null) urlParams += `&publishedAfter=${publishedAfter}`;
102
+ if (sortBy != null) urlParams += `&sortBy=${sortBy}`;
103
+ if (sortDirection != null) urlParams += `&sortDirection=${sortDirection}`;
104
+ const response = http.get(
105
+ `${baseUrl(communityId)}?page=${page}&limit=${limit}${urlParams}`,
106
+ makeHeaders(),
107
+ );
108
+ if (response.status === 200) {
109
+ return JSON.parse(<string>response.body);
110
+ } else {
111
+ return null;
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Count all announcements
117
+ * @param communityId Community ID
118
+ * @param publishedAfter Date to filter announcements from (optional)
119
+ * @returns List of announcements or null if failed
120
+ */
121
+ export function countAnnouncements(
122
+ communityId: number,
123
+ publishedAfter: string | null = null,
124
+ ): AnnouncementCount | null {
125
+ const urlParams =
126
+ publishedAfter == null ? "" : `?publishedAfter=${publishedAfter}`;
127
+ const response = http.get(
128
+ `${baseUrl(communityId)}/count${urlParams}`,
129
+ makeHeaders(),
130
+ );
131
+ if (response.status === 200) {
132
+ return JSON.parse(<string>response.body);
133
+ } else {
134
+ return null;
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Get a specific announcement by ID
140
+ * @param communityId Community ID
141
+ * @param announcementId Announcement ID
142
+ * @returns Announcement or null if not found
143
+ */
144
+ export function getAnnouncement(
145
+ communityId: number,
146
+ announcementId: number,
147
+ ): Announcement | null {
148
+ const response = http.get(
149
+ `${baseUrl(communityId)}/${announcementId}`,
150
+ makeHeaders(),
151
+ );
152
+ if (response.status === 200) {
153
+ return JSON.parse(<string>response.body);
154
+ } else {
155
+ return null;
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Update an announcement
161
+ * @param communityId Community ID
162
+ * @param announcementId Announcement ID
163
+ * @param updateData Update data
164
+ * @returns Updated announcement or null if failed
165
+ */
166
+ export function updateAnnouncement(
167
+ communityId: number,
168
+ announcementId: number,
169
+ updateData: UpdateAnnouncementParams,
170
+ ): Announcement | null {
171
+ const response = http.put(
172
+ `${baseUrl(communityId)}/${announcementId}`,
173
+ JSON.stringify(updateData),
174
+ makeHeaders(),
175
+ );
176
+ if (response.status === 200) {
177
+ return JSON.parse(<string>response.body);
178
+ } else {
179
+ return null;
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Delete an announcement
185
+ * @param communityId Community ID
186
+ * @param announcementId Announcement ID
187
+ * @returns True if deletion was successful, false otherwise
188
+ */
189
+ export function deleteAnnouncement(
190
+ communityId: number,
191
+ announcementId: number,
192
+ ): boolean {
193
+ const response = http.del(`${baseUrl(communityId)}/${announcementId}`);
194
+ return response.status === 204;
195
+ }
@@ -0,0 +1,199 @@
1
+ import http from "k6/http";
2
+ import { getHeaders } from "../../../node_modules/edifice-k6-commons/dist/index.js";
3
+ import { Resource } from "./_resource-api.utils.js";
4
+ import { HttpResponse, success, failure } from "./_http-response.utils.ts";
5
+
6
+ //Types
7
+ export type User = {
8
+ id: number;
9
+ displayName: string;
10
+ entId: string;
11
+ profile: string;
12
+ };
13
+
14
+ export type Folder = {
15
+ id: number;
16
+ name: string;
17
+ creationDate: string;
18
+ modificationDate: string;
19
+ isRoot: boolean;
20
+ creator: User;
21
+ modifier?: User;
22
+ parentId?: number;
23
+ communityId: number;
24
+ stats?: FolderStats;
25
+ };
26
+
27
+ export type FolderStats = {
28
+ childCount: number;
29
+ };
30
+
31
+ export type FolderDetails = {
32
+ id: number;
33
+ name: string;
34
+ creationDate: string;
35
+ modificationDate: string;
36
+ isRoot: boolean;
37
+ creator: User;
38
+ modifier?: User;
39
+ parentId?: number;
40
+ communityId: number;
41
+ stats?: FolderStats;
42
+ subFolders?: Folder[];
43
+ resources?: Resource[];
44
+ };
45
+
46
+ export type CreateFolderParams = {
47
+ name: string;
48
+ parentId?: number;
49
+ };
50
+
51
+ export type UpdateFolderParams = {
52
+ name: string;
53
+ parentId?: number;
54
+ };
55
+
56
+ export type PaginatedFolders = {
57
+ items: Folder[];
58
+ meta: {
59
+ totalItems: number;
60
+ currentPage: number;
61
+ itemCount: number;
62
+ totalPages: number;
63
+ };
64
+ };
65
+
66
+ const rootUrl = __ENV.ROOT_URL || "";
67
+ function baseUrl(id: number): string {
68
+ return `${rootUrl}/communities/api/communities/${id}/folders`;
69
+ }
70
+ function makeHeaders(): object {
71
+ return {
72
+ headers: { ...getHeaders(), "Content-Type": "application/json" },
73
+ };
74
+ }
75
+
76
+ export function getFolders(
77
+ communityId: number,
78
+ page: number = 1,
79
+ limit: number = 10,
80
+ name: string | undefined = undefined,
81
+ parent: number | undefined = undefined,
82
+ rootOnly: boolean = false,
83
+ ): HttpResponse<PaginatedFolders> {
84
+ let urlParams: string = name ? `&name=${name}` : "";
85
+ if (parent) {
86
+ urlParams += `&parentId=${parent}`;
87
+ }
88
+ if (rootOnly) {
89
+ urlParams += `&rootOnly=${rootOnly}`;
90
+ }
91
+ const response = http.get(
92
+ `${baseUrl(communityId)}?page=${page}&limit=${limit}${urlParams}`,
93
+ makeHeaders(),
94
+ );
95
+ if (response.status === 200) {
96
+ return success(JSON.parse(<string>response.body));
97
+ } else {
98
+ return failure(response.status);
99
+ }
100
+ }
101
+
102
+ export function getRootFolders(communityId: number): HttpResponse<Folder[]> {
103
+ const response = http.get(`${baseUrl(communityId)}/root`, makeHeaders());
104
+ if (response.status === 200) {
105
+ return success(JSON.parse(<string>response.body));
106
+ } else {
107
+ return failure(response.status);
108
+ }
109
+ }
110
+
111
+ export function createFolder(
112
+ communityId: number,
113
+ createData: CreateFolderParams,
114
+ ): HttpResponse<Folder> {
115
+ const response = http.post(
116
+ `${baseUrl(communityId)}`,
117
+ JSON.stringify(createData),
118
+ makeHeaders(),
119
+ );
120
+ if (response.status === 201) {
121
+ return success(JSON.parse(<string>response.body));
122
+ } else {
123
+ return failure(response.status);
124
+ }
125
+ }
126
+
127
+ export function updateFolder(
128
+ communityId: number,
129
+ folderId: number,
130
+ updateData: UpdateFolderParams,
131
+ ): HttpResponse<Folder> {
132
+ const response = http.put(
133
+ `${baseUrl(communityId)}/${folderId}`,
134
+ JSON.stringify(updateData),
135
+ makeHeaders(),
136
+ );
137
+ if (response.status === 200) {
138
+ return success(JSON.parse(<string>response.body));
139
+ } else {
140
+ return failure(response.status);
141
+ }
142
+ }
143
+
144
+ export function getFolderContent(
145
+ communityId: number,
146
+ folderId: number,
147
+ ): HttpResponse<FolderDetails> {
148
+ const response = http.get(
149
+ `${baseUrl(communityId)}/${folderId}`,
150
+ makeHeaders(),
151
+ );
152
+ if (response.status === 200) {
153
+ return success(JSON.parse(<string>response.body));
154
+ } else {
155
+ return failure(response.status);
156
+ }
157
+ }
158
+
159
+ export function removeFolder(
160
+ communityId: number,
161
+ folderId: number,
162
+ ): HttpResponse<boolean> {
163
+ const response = http.del(`${baseUrl(communityId)}/${folderId}`);
164
+ if (response.status === 204) {
165
+ return success(true);
166
+ } else {
167
+ return failure(response.status);
168
+ }
169
+ }
170
+
171
+ export function addResourceToFolder(
172
+ communityId: number,
173
+ folderId: number,
174
+ resourceId: number,
175
+ ): HttpResponse<boolean> {
176
+ const response = http.post(
177
+ `${baseUrl(communityId)}/${folderId}/resources/${resourceId}`,
178
+ );
179
+ if (response.status === 204) {
180
+ return success(true);
181
+ } else {
182
+ return failure(response.status);
183
+ }
184
+ }
185
+
186
+ export function removeResourceFromFolder(
187
+ communityId: number,
188
+ folderId: number,
189
+ resourceId: number,
190
+ ): HttpResponse<boolean> {
191
+ const response = http.del(
192
+ `${baseUrl(communityId)}/${folderId}/resources/${resourceId}`,
193
+ );
194
+ if (response.status === 204) {
195
+ return success(true);
196
+ } else {
197
+ return failure(response.status);
198
+ }
199
+ }