Skip to content

Commit 62172ac

Browse files
authored
merge: pull changes from dev (#4618)
2 parents 54cfd51 + 78d4bca commit 62172ac

File tree

81 files changed

+925
-321
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+925
-321
lines changed

packages/api-aco/src/folder/folder.gql.ts

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -55,29 +55,47 @@ export const createFoldersSchema = (params: CreateFolderTypeDefsParams) => {
5555
listFoldersCompressed: async (_, args: any, context) => {
5656
return resolve(async () => {
5757
ensureAuthentication(context);
58+
5859
const [entries] = await context.aco.folder.list(args);
60+
const foldersPromises = entries.map(folder => {
61+
const { folderLevelPermissions: flp } = context.aco;
62+
63+
const canManageStructure = flp.canManageFolderStructure(
64+
folder as unknown as FolderLevelPermission
65+
);
66+
const canManagePermissions = flp.canManageFolderPermissions(
67+
folder as unknown as FolderLevelPermission
68+
);
69+
const canManageContent = flp.canManageFolderContent(
70+
folder as unknown as FolderLevelPermission
71+
);
72+
const hasNonInheritedPermissions =
73+
flp.permissionsIncludeNonInheritedPermissions(folder.permissions);
5974

60-
const folders = entries.map(folder => ({
61-
...folder,
62-
hasNonInheritedPermissions:
63-
context.aco.folderLevelPermissions.permissionsIncludeNonInheritedPermissions(
64-
folder.permissions
65-
),
66-
canManageStructure:
67-
context.aco.folderLevelPermissions.canManageFolderStructure(
68-
folder as unknown as FolderLevelPermission
69-
),
70-
canManagePermissions:
71-
context.aco.folderLevelPermissions.canManageFolderPermissions(
72-
folder as unknown as FolderLevelPermission
73-
),
74-
canManageContent:
75-
context.aco.folderLevelPermissions.canManageFolderContent(
76-
folder as unknown as FolderLevelPermission
77-
)
78-
}));
75+
return Promise.all([
76+
canManageStructure,
77+
canManagePermissions,
78+
canManageContent,
79+
hasNonInheritedPermissions
80+
]).then(
81+
([
82+
canManageStructure,
83+
canManagePermissions,
84+
canManageContent,
85+
hasNonInheritedPermissions
86+
]) => {
87+
return {
88+
...folder,
89+
canManageStructure,
90+
canManagePermissions,
91+
canManageContent,
92+
hasNonInheritedPermissions
93+
};
94+
}
95+
);
96+
});
7997

80-
return compress(folders);
98+
return Promise.all(foldersPromises).then(compress);
8199
});
82100
},
83101
getFolderHierarchy: async (_, args: any, context) => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { useHandler } from "~tests/translations/useHandler";
2+
import {
3+
DeleteTranslatableCollectionUseCase,
4+
GetTranslatableCollectionUseCase,
5+
SaveTranslatableCollectionUseCase
6+
} from "~/translations";
7+
8+
describe("DeleteTranslatableCollectionUseCase", () => {
9+
it("should delete a collection", async () => {
10+
const { handler } = useHandler();
11+
const context = await handler();
12+
13+
// Setup
14+
const saveTranslatableCollection = new SaveTranslatableCollectionUseCase(context);
15+
const newCollection = await saveTranslatableCollection.execute({
16+
collectionId: "collection:1",
17+
items: [
18+
{ itemId: "element:1", value: "Value 1" },
19+
{ itemId: "element:2", value: "Value 2" }
20+
]
21+
});
22+
23+
const getTranslatableCollection = new GetTranslatableCollectionUseCase(context);
24+
const collection = await getTranslatableCollection.execute(newCollection.getCollectionId());
25+
26+
expect(collection).toBeTruthy();
27+
expect(collection!.getCollectionId()).toEqual(newCollection.getCollectionId());
28+
29+
// Test
30+
const deleteTranslatableCollection = new DeleteTranslatableCollectionUseCase(context);
31+
await deleteTranslatableCollection.execute({
32+
collectionId: "collection:1"
33+
});
34+
35+
const checkCollection = await getTranslatableCollection.execute("collection:1");
36+
expect(checkCollection).toBeUndefined();
37+
});
38+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import { useHandler } from "~tests/translations/useHandler";
2+
import {
3+
SaveTranslatableCollectionUseCase,
4+
SaveTranslatableCollectionParams,
5+
SaveTranslatedCollectionUseCase,
6+
DeleteTranslatedCollectionUseCase,
7+
GetTranslatedCollectionUseCase
8+
} from "~/translations";
9+
import { PbContext } from "~/graphql/types";
10+
11+
const createTranslatableCollection = async (
12+
context: PbContext,
13+
params: SaveTranslatableCollectionParams
14+
) => {
15+
const saveCollection = new SaveTranslatableCollectionUseCase(context);
16+
await saveCollection.execute(params);
17+
};
18+
19+
describe("DeleteTranslatedCollectionUseCase", () => {
20+
it("should delete an entire collection with all translations", async () => {
21+
const { handler } = useHandler();
22+
const context = await handler();
23+
24+
// Setup
25+
await createTranslatableCollection(context, {
26+
collectionId: "collection:1",
27+
items: [
28+
{ itemId: "element:1", value: "Value 1" },
29+
{ itemId: "element:2", value: "Value 2" },
30+
{ itemId: "element:3", value: "Value 3" }
31+
]
32+
});
33+
34+
const saveTranslatedCollection = new SaveTranslatedCollectionUseCase(context);
35+
await saveTranslatedCollection.execute({
36+
collectionId: "collection:1",
37+
languageCode: "en",
38+
items: [
39+
{ itemId: "element:1", value: "Translated Value 1 EN" },
40+
{ itemId: "element:2", value: "Translated Value 2 EN" }
41+
]
42+
});
43+
44+
await saveTranslatedCollection.execute({
45+
collectionId: "collection:1",
46+
languageCode: "de",
47+
items: [
48+
{ itemId: "element:1", value: "Translated Value 1 DE" },
49+
{ itemId: "element:2", value: "Translated Value 2 DE" }
50+
]
51+
});
52+
53+
// Test
54+
const deleteTranslatedCollection = new DeleteTranslatedCollectionUseCase(context);
55+
await deleteTranslatedCollection.execute({ collectionId: "collection:1" });
56+
57+
const getTranslatedCollection = new GetTranslatedCollectionUseCase(context);
58+
59+
await expect(
60+
getTranslatedCollection.execute({
61+
collectionId: "collection:1",
62+
languageCode: "en"
63+
})
64+
).rejects.toThrow("not found");
65+
66+
await expect(
67+
getTranslatedCollection.execute({
68+
collectionId: "collection:1",
69+
languageCode: "de"
70+
})
71+
).rejects.toThrow("not found");
72+
});
73+
74+
it("should delete a collection for a given language", async () => {
75+
const { handler } = useHandler();
76+
const context = await handler();
77+
78+
// Setup
79+
await createTranslatableCollection(context, {
80+
collectionId: "collection:1",
81+
items: [
82+
{ itemId: "element:1", value: "Value 1" },
83+
{ itemId: "element:2", value: "Value 2" },
84+
{ itemId: "element:3", value: "Value 3" }
85+
]
86+
});
87+
88+
const saveTranslatedCollection = new SaveTranslatedCollectionUseCase(context);
89+
await saveTranslatedCollection.execute({
90+
collectionId: "collection:1",
91+
languageCode: "en",
92+
items: [
93+
{ itemId: "element:1", value: "Translated Value 1 EN" },
94+
{ itemId: "element:2", value: "Translated Value 2 EN" }
95+
]
96+
});
97+
98+
await saveTranslatedCollection.execute({
99+
collectionId: "collection:1",
100+
languageCode: "de",
101+
items: [
102+
{ itemId: "element:1", value: "Translated Value 1 DE" },
103+
{ itemId: "element:2", value: "Translated Value 2 DE" }
104+
]
105+
});
106+
107+
// Test
108+
const deleteTranslatedCollection = new DeleteTranslatedCollectionUseCase(context);
109+
await deleteTranslatedCollection.execute({
110+
collectionId: "collection:1",
111+
languageCode: "en"
112+
});
113+
114+
const getTranslatedCollection = new GetTranslatedCollectionUseCase(context);
115+
116+
await expect(
117+
getTranslatedCollection.execute({
118+
collectionId: "collection:1",
119+
languageCode: "en"
120+
})
121+
).rejects.toThrow("not found");
122+
123+
const deCollection = await getTranslatedCollection.execute({
124+
collectionId: "collection:1",
125+
languageCode: "de"
126+
});
127+
128+
expect(deCollection.getCollectionId()).toBe("collection:1");
129+
expect(deCollection.getLanguageCode()).toBe("de");
130+
});
131+
});

packages/api-page-builder/src/prerendering/prerenderingHandlers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const prerenderingHandlers = new ContextPlugin<PbContext>(context => {
2020
const render = paths.map<RenderEvent>(item => ({
2121
...item,
2222
tenant,
23+
groupId: tenant,
2324
locale: locale.code
2425
}));
2526

packages/api-page-builder/src/translations/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ export * from "./translatableCollection/useCases/GetTranslatableCollectionUseCas
33
export * from "./translatableCollection/useCases/SaveTranslatableCollectionUseCase";
44
export * from "./translatableCollection/useCases/GetOrCreateTranslatableCollectionUseCase";
55
export * from "./translatableCollection/useCases/CloneTranslatableCollectionUseCase";
6+
export * from "./translatableCollection/useCases/DeleteTranslatableCollectionUseCase";
67

78
// TranslatedCollection
89
export * from "./translatedCollection/useCases/GetTranslatedCollectionUseCase";
910
export * from "./translatedCollection/useCases/CloneTranslatedCollectionUseCase";
1011
export * from "./translatedCollection/useCases/SaveTranslatedCollectionUseCase";
1112
export * from "./translatedCollection/useCases/GetOrCreateTranslatedCollectionUseCase";
13+
export * from "./translatedCollection/useCases/DeleteTranslatedCollectionUseCase";

packages/api-page-builder/src/translations/translatableCollection/graphql/resolvers.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@ import { SaveTranslatableCollectionUseCase } from "~/translations/translatableCo
55
import type { GqlTranslatableItemDTO } from "~/translations/translatableCollection/graphql/GqlTranslatableItemDTO";
66
import { GetTranslatableCollectionByIdRepository } from "~/translations/translatableCollection/repository/GetTranslatableCollectionByIdRepository";
77
import { GqlTranslatableCollectionMapper } from "~/translations/translatableCollection/graphql/GqlTranslatableCollectionMapper";
8+
import { DeleteTranslatableCollectionUseCase } from "~/translations";
89

910
interface UpdateTranslatableCollectionParams {
1011
collectionId: string;
1112
items: GqlTranslatableItemDTO[];
1213
}
1314

15+
interface DeleteTranslatableCollectionParams {
16+
collectionId: string;
17+
}
18+
1419
export const translatableCollectionResolvers: Resolvers<PbContext> = {
1520
TranslationsQuery: {
1621
getTranslatableCollection: async (_, args, context) => {
@@ -39,6 +44,18 @@ export const translatableCollectionResolvers: Resolvers<PbContext> = {
3944
} catch (err) {
4045
return new ErrorResponse(err);
4146
}
47+
},
48+
deleteTranslatableCollection: async (_, args, context) => {
49+
const { collectionId } = args as DeleteTranslatableCollectionParams;
50+
51+
try {
52+
const useCase = new DeleteTranslatableCollectionUseCase(context);
53+
await useCase.execute({ collectionId });
54+
55+
return new Response(true);
56+
} catch (err) {
57+
return new ErrorResponse(err);
58+
}
4259
}
4360
}
4461
};

packages/api-page-builder/src/translations/translatableCollection/graphql/schema.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const translatableCollectionSchema = /* GraphQL*/ `
2828
data: TranslatableCollection
2929
error: PbError
3030
}
31-
31+
3232
extend type TranslationsQuery {
3333
"""Get the source collection with all the items that need to be translated."""
3434
getTranslatableCollection(collectionId: ID!): TranslatableCollectionResponse
@@ -39,5 +39,7 @@ export const translatableCollectionSchema = /* GraphQL*/ `
3939
collectionId: ID!
4040
items: [TranslatableItemInput!]!
4141
): SaveTranslatableCollectionResponse
42+
43+
deleteTranslatableCollection(collectionId: ID!): BooleanResponse
4244
}
4345
`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { PbContext } from "~/types";
2+
import { GetModel } from "~/translations/GetModel";
3+
import { TranslatableCollectionDTO } from "./mappers/TranslatableCollectionDTO";
4+
5+
export class DeleteTranslatableCollectionRepository {
6+
private readonly context: PbContext;
7+
8+
constructor(context: PbContext) {
9+
this.context = context;
10+
}
11+
12+
async execute(collectionId: string): Promise<void> {
13+
const model = await GetModel.byModelId(this.context, "translatableCollection");
14+
15+
// `cms.getEntry` throws an error if an entry is not found.
16+
try {
17+
const existingEntry = await this.context.cms.getEntry<TranslatableCollectionDTO>(
18+
model,
19+
{
20+
where: { collectionId, latest: true }
21+
}
22+
);
23+
24+
await this.context.cms.deleteEntry(model, existingEntry.entryId, { permanently: true });
25+
} catch {
26+
// If a record doesn't exist, then there's nothing to delete, and we can exit.
27+
console.log(
28+
`[DeleteTranslatableCollectionRepository]: Collection doesn't exist: ${collectionId}`
29+
);
30+
}
31+
}
32+
}

packages/api-page-builder/src/translations/translatableCollection/repository/GetTranslatableCollectionByIdRepository.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,23 @@ export class GetTranslatableCollectionByIdRepository {
1515
async execute(collectionId: string): Promise<TranslatableCollection> {
1616
const model = await GetModel.byModelId(this.context, "translatableCollection");
1717

18-
const existingEntry = await this.context.cms.getEntry<TranslatableCollectionDTO>(model, {
19-
where: { collectionId, latest: true }
20-
});
18+
try {
19+
const existingEntry = await this.context.cms.getEntry<TranslatableCollectionDTO>(
20+
model,
21+
{
22+
where: { collectionId, latest: true }
23+
}
24+
);
2125

22-
if (!existingEntry) {
26+
return TranslatableCollectionMapper.fromDTO(
27+
existingEntry.values,
28+
existingEntry.entryId
29+
);
30+
} catch {
2331
throw new WebinyError({
2432
message: `TranslatableCollection "${collectionId}" not found!`,
2533
code: "NOT_FOUND"
2634
});
2735
}
28-
29-
return TranslatableCollectionMapper.fromDTO(existingEntry.values, existingEntry.entryId);
3036
}
3137
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { PbContext } from "~/graphql/types";
2+
import { DeleteTranslatableCollectionRepository } from "~/translations/translatableCollection/repository/DeleteTranslatableCollectionRepository";
3+
4+
export interface DeleteTranslatableCollectionParams {
5+
collectionId: string;
6+
}
7+
8+
export class DeleteTranslatableCollectionUseCase {
9+
private readonly context: PbContext;
10+
11+
constructor(context: PbContext) {
12+
this.context = context;
13+
}
14+
15+
async execute(params: DeleteTranslatableCollectionParams): Promise<void> {
16+
const deleteRepository = new DeleteTranslatableCollectionRepository(this.context);
17+
18+
await deleteRepository.execute(params.collectionId);
19+
}
20+
}

0 commit comments

Comments
 (0)