Skip to content

Commit 6e070dd

Browse files
pyphiliakim
andauthored
refactor: use item type from schema (#2065)
* refactor: use item type from schema * refactor: fix type * fix: fix tests --------- Co-authored-by: kim <kim.phanhoang@epfl.ch>
1 parent 5e6509a commit 6e070dd

93 files changed

Lines changed: 684 additions & 766 deletions

File tree

Some content is hidden

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

src/drizzle/schema.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ import {
2222
import { eq, isNull } from 'drizzle-orm/sql';
2323
import geoip from 'geoip-lite';
2424

25-
import { AccountType, type ItemSettings, type ItemTypeUnion } from '@graasp/sdk';
25+
import { AccountType, type ItemSettings } from '@graasp/sdk';
2626

27+
import { ItemType } from '../schemas/global';
2728
import type { MemberExtra } from '../services/member/types';
2829
import { binary, binaryHash, citext, customNumeric, ltree } from './customTypes';
2930

@@ -863,7 +864,7 @@ export const itemsRawTable = pgTable(
863864
{
864865
id: uuid().primaryKey().notNull(),
865866
name: varchar({ length: 500 }).notNull(),
866-
type: varchar().$type<ItemTypeUnion>().default('folder').notNull(),
867+
type: varchar().$type<ItemType>().default('folder').notNull(),
867868
description: varchar({ length: 5000 }),
868869
path: ltree('path').notNull(),
869870
creatorId: uuid('creator_id'),

src/drizzle/types.ts

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import type {
99
LinkItemExtra,
1010
LinkItemSettings,
1111
ShortcutItemExtra,
12-
UnionOfConst,
1312
} from '@graasp/sdk';
1413

1514
import type { MinimalGuest, MinimalMember } from '../types';
@@ -95,44 +94,28 @@ export type GuestWithItemLoginSchema = GuestRaw & {
9594
itemLoginSchema: ItemLoginSchemaRaw | null;
9695
};
9796

98-
/**
99-
* Item types
100-
*/
101-
export const ItemType = {
102-
APP: 'app',
103-
DOCUMENT: 'document',
104-
FOLDER: 'folder',
105-
LINK: 'embeddedLink',
106-
FILE: 'file',
107-
SHORTCUT: 'shortcut',
108-
H5P: 'h5p',
109-
ETHERPAD: 'etherpad',
110-
PAGE: 'page',
111-
} as const;
112-
export type ItemTypeUnion = UnionOfConst<typeof ItemType>;
113-
11497
export type ItemExtraMap = {
115-
[ItemType.APP]: AppItemExtra;
116-
[ItemType.DOCUMENT]: DocumentItemExtra;
117-
[ItemType.ETHERPAD]: EtherpadItemExtra;
118-
[ItemType.FOLDER]: FolderItemExtra;
119-
[ItemType.H5P]: H5PItemExtra;
120-
[ItemType.LINK]: LinkItemExtra;
121-
[ItemType.FILE]: FileItemExtra;
122-
[ItemType.SHORTCUT]: ShortcutItemExtra;
123-
[ItemType.PAGE]: never;
98+
['app']: AppItemExtra;
99+
['document']: DocumentItemExtra;
100+
['etherpad']: EtherpadItemExtra;
101+
['folder']: FolderItemExtra;
102+
['h5p']: H5PItemExtra;
103+
['embeddedLink']: LinkItemExtra;
104+
['file']: FileItemExtra;
105+
['shortcut']: ShortcutItemExtra;
106+
['page']: never;
124107
};
125108

126109
export type ItemSettingsMap = {
127-
[ItemType.APP]: ItemSettings;
128-
[ItemType.DOCUMENT]: ItemSettings;
129-
[ItemType.ETHERPAD]: ItemSettings;
130-
[ItemType.FOLDER]: ItemSettings;
131-
[ItemType.H5P]: ItemSettings;
132-
[ItemType.LINK]: LinkItemSettings;
133-
[ItemType.FILE]: ItemSettings;
134-
[ItemType.SHORTCUT]: ItemSettings;
135-
[ItemType.PAGE]: ItemSettings;
110+
['app']: ItemSettings;
111+
['document']: ItemSettings;
112+
['etherpad']: ItemSettings;
113+
['folder']: ItemSettings;
114+
['h5p']: ItemSettings;
115+
['embeddedLink']: LinkItemSettings;
116+
['file']: ItemSettings;
117+
['shortcut']: ItemSettings;
118+
['page']: ItemSettings;
136119
};
137120

138121
// local type alias to simplify the notation

src/schemas/global.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// we need this file used in classic json schema
2-
import { Type } from '@sinclair/typebox';
2+
import { type Static, Type } from '@sinclair/typebox';
33
import { StatusCodes } from 'http-status-codes';
44

55
import { customType, registerSchemaAsRef } from '../plugins/typebox';
@@ -31,3 +31,24 @@ export const errorSchemaRef = registerSchemaAsRef(
3131
},
3232
),
3333
);
34+
35+
/**
36+
* List of possible item types
37+
*/
38+
export const ITEM_TYPES = [
39+
'app' as const,
40+
'document' as const,
41+
'embeddedLink' as const,
42+
'etherpad' as const,
43+
'file' as const,
44+
'folder' as const,
45+
'h5p' as const,
46+
'page' as const,
47+
'shortcut' as const,
48+
];
49+
50+
// we derive schema and type
51+
const itemTypeSchema = Type.Union(ITEM_TYPES.map((type) => Type.Literal(type)));
52+
export const itemTypeSchemaRef = registerSchemaAsRef('itemType', 'Item Type', itemTypeSchema);
53+
54+
export type ItemType = Static<typeof itemTypeSchema>;

src/services/item/discrimination.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
1-
import { ItemType } from '@graasp/sdk';
1+
import type { ItemTypeEnumKeys, ItemWithType } from '../../drizzle/types';
2+
import { ItemType } from '../../schemas/global';
23

3-
import type { ItemRaw, ItemTypeEnumKeys, ItemWithType } from '../../drizzle/types';
4-
5-
export type AppItem = ItemWithType<typeof ItemType.APP>;
6-
export type DocumentItem = ItemWithType<typeof ItemType.DOCUMENT>;
7-
export type EtherpadItem = ItemWithType<typeof ItemType.ETHERPAD>;
8-
export type FolderItem = ItemWithType<typeof ItemType.FOLDER>;
4+
export type AppItem = ItemWithType<'app'>;
5+
export type DocumentItem = ItemWithType<'document'>;
6+
export type EtherpadItem = ItemWithType<'etherpad'>;
7+
export type FolderItem = ItemWithType<'folder'>;
98
// For now a capsule is a folder with one different setting
109
export type CapsuleItem = FolderItem;
11-
export type PageItem = ItemWithType<typeof ItemType.PAGE>;
12-
export type H5PItem = ItemWithType<typeof ItemType.H5P>;
13-
export type EmbeddedLinkItem = ItemWithType<typeof ItemType.LINK>;
14-
export type FileItem = ItemWithType<typeof ItemType.FILE>;
15-
export type ShortcutItem = ItemWithType<typeof ItemType.SHORTCUT>;
10+
export type PageItem = ItemWithType<'page'>;
11+
export type H5PItem = ItemWithType<'h5p'>;
12+
export type EmbeddedLinkItem = ItemWithType<'embeddedLink'>;
13+
export type FileItem = ItemWithType<'file'>;
14+
export type ShortcutItem = ItemWithType<'shortcut'>;
1615

1716
export const isItemType = <T extends ItemTypeEnumKeys>(
18-
item: { type: ItemRaw['type'] },
17+
item: { type: ItemType },
1918
type: T,
2019
): item is ItemWithType<T> => {
2120
return item.type === type;

src/services/item/item.controller.read.test.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { v4 as uuidv4 } from 'uuid';
33

44
import type { FastifyInstance } from 'fastify';
55

6-
import { HttpMethod, ItemType } from '@graasp/sdk';
6+
import { HttpMethod } from '@graasp/sdk';
77

88
import build, { clearDatabase, mockAuthenticate, unmockAuthenticate } from '../../../test/app';
99
import { seedFromJson } from '../../../test/mocks/seed';
@@ -504,15 +504,15 @@ describe('Item routes tests', () => {
504504
} = await seedFromJson({
505505
items: [
506506
{
507-
type: ItemType.DOCUMENT,
507+
type: 'document',
508508
memberships: [{ account: 'actor', permission: 'admin' }],
509509
},
510510
{
511-
type: ItemType.FOLDER,
511+
type: 'folder',
512512
memberships: [{ account: 'actor', permission: 'admin' }],
513513
},
514514
{
515-
type: ItemType.APP,
515+
type: 'app',
516516
memberships: [{ account: 'actor', permission: 'admin' }],
517517
},
518518
],
@@ -709,16 +709,16 @@ describe('Item routes tests', () => {
709709
} = await seedFromJson({
710710
items: [
711711
{
712-
type: ItemType.FOLDER,
712+
type: 'folder',
713713
memberships: [{ account: 'actor', permission: 'admin' }],
714714
},
715715
{
716-
type: ItemType.FOLDER,
716+
type: 'folder',
717717
memberships: [{ account: 'actor', permission: 'admin' }],
718718
},
719719
// noise
720720
{
721-
type: ItemType.APP,
721+
type: 'app',
722722
memberships: [{ account: 'actor', permission: 'admin' }],
723723
},
724724
],
@@ -737,7 +737,7 @@ describe('Item routes tests', () => {
737737
method: HttpMethod.Get,
738738
url: '/api/items/accessible',
739739
query: {
740-
types: [ItemType.FOLDER],
740+
types: ['folder'],
741741
},
742742
});
743743

@@ -997,9 +997,9 @@ describe('Item routes tests', () => {
997997
{
998998
memberships: [{ account: 'actor', permission: 'admin' }],
999999
children: [
1000-
{ type: ItemType.DOCUMENT },
1001-
{ type: ItemType.FOLDER },
1002-
{ type: ItemType.FOLDER, children: [{ name: 'noise' }] },
1000+
{ type: 'document' },
1001+
{ type: 'folder' },
1002+
{ type: 'folder', children: [{ name: 'noise' }] },
10031003
],
10041004
},
10051005
],
@@ -1124,15 +1124,15 @@ describe('Item routes tests', () => {
11241124
children: [
11251125
{
11261126
creator: 'actor',
1127-
type: ItemType.DOCUMENT,
1127+
type: 'document',
11281128
},
11291129
{
11301130
creator: 'actor',
1131-
type: ItemType.FOLDER,
1131+
type: 'folder',
11321132
},
11331133
{
11341134
creator: 'actor',
1135-
type: ItemType.FOLDER,
1135+
type: 'folder',
11361136
children: [{ name: 'noise' }],
11371137
},
11381138
],

src/services/item/item.controller.test.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import { StatusCodes } from 'http-status-codes';
22

33
import type { FastifyInstance } from 'fastify';
44

5-
import { ItemType } from '@graasp/sdk';
6-
75
import build, { clearDatabase, mockAuthenticate } from '../../../test/app';
86
import { seedFromJson } from '../../../test/mocks/seed';
97
import { db } from '../../drizzle/db';
@@ -59,9 +57,9 @@ describe('Item controller', () => {
5957
{
6058
memberships: [{ account: 'actor', permission: 'admin' }],
6159
children: [
62-
{ type: ItemType.FOLDER },
63-
{ isHidden: true, type: ItemType.DOCUMENT },
64-
{ isPublic: true, type: ItemType.DOCUMENT },
60+
{ type: 'folder' },
61+
{ isHidden: true, type: 'document' },
62+
{ isPublic: true, type: 'document' },
6563
],
6664
},
6765
],
@@ -71,7 +69,7 @@ describe('Item controller', () => {
7169
mockAuthenticate(actor);
7270
const response = await app.inject({
7371
method: 'GET',
74-
url: `/api/items/${rootUUID}/descendants?types=${ItemType.FOLDER}`,
72+
url: `/api/items/${rootUUID}/descendants?types=${'folder'}`,
7573
});
7674
expect(response.statusCode).toBe(StatusCodes.OK);
7775
const json = response.json();
@@ -87,11 +85,7 @@ describe('Item controller', () => {
8785
items: [
8886
{
8987
memberships: [{ account: 'actor', permission: 'admin' }],
90-
children: [
91-
{},
92-
{ isHidden: true, type: ItemType.APP },
93-
{ isPublic: true, type: ItemType.APP },
94-
],
88+
children: [{}, { isHidden: true, type: 'app' }, { isPublic: true, type: 'app' }],
9589
},
9690
],
9791
});
@@ -100,7 +94,7 @@ describe('Item controller', () => {
10094
mockAuthenticate(actor);
10195
const response = await app.inject({
10296
method: 'GET',
103-
url: `/api/items/${rootUUID}/descendants?types=${ItemType.APP}`,
97+
url: `/api/items/${rootUUID}/descendants?types=${'app'}`,
10498
});
10599
expect(response.statusCode).toBe(StatusCodes.OK);
106100
const json = response.json();

src/services/item/item.controller.update.test.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import {
1414
DescriptionPlacement,
1515
FolderItemFactory,
1616
HttpMethod,
17-
ItemType,
1817
MAX_NUMBER_OF_CHILDREN,
1918
MAX_TARGETS_FOR_MODIFY_REQUEST,
2019
MAX_TREE_LEVELS,
@@ -387,7 +386,7 @@ describe('Item routes tests', () => {
387386
const response = await app.inject({
388387
method: HttpMethod.Post,
389388
url: `/api/items`,
390-
payload: { name: faker.word.adverb(), type: ItemType.FOLDER },
389+
payload: { name: faker.word.adverb(), type: 'folder' },
391390
query: { parentId: parentItem.id },
392391
});
393392

@@ -670,7 +669,7 @@ describe('Item routes tests', () => {
670669
} = await seedFromJson({
671670
items: [
672671
{
673-
type: ItemType.DOCUMENT,
672+
type: 'document',
674673
memberships: [{ account: 'actor', permission: 'admin' }],
675674
},
676675
],
@@ -702,7 +701,7 @@ describe('Item routes tests', () => {
702701
const itemName = 'Test Item';
703702
const payload = new FormData();
704703
payload.append('name', itemName);
705-
payload.append('type', ItemType.FOLDER);
704+
payload.append('type', 'folder');
706705
payload.append('description', '');
707706
payload.append('file', imageStream);
708707
const response = await app.inject({
@@ -717,7 +716,7 @@ describe('Item routes tests', () => {
717716
newItem,
718717
FolderItemFactory({
719718
name: itemName,
720-
type: ItemType.FOLDER,
719+
type: 'folder',
721720
description: '',
722721
settings: { hasThumbnail: true },
723722
lang: 'en',
@@ -750,9 +749,9 @@ describe('Item routes tests', () => {
750749
items: [
751750
{
752751
memberships: [{ account: 'actor', permission: 'admin' }],
753-
type: ItemType.DOCUMENT,
752+
type: 'document',
754753
extra: {
755-
[ItemType.DOCUMENT]: {
754+
['document']: {
756755
content: 'content',
757756
},
758757
},
@@ -766,7 +765,7 @@ describe('Item routes tests', () => {
766765
const payload = {
767766
name: 'new name',
768767
extra: {
769-
[ItemType.DOCUMENT]: {
768+
['document']: {
770769
content: 'new content',
771770
},
772771
},
@@ -2306,7 +2305,7 @@ describe('Item routes tests', () => {
23062305
items: [
23072306
{
23082307
creator: 'actor',
2309-
type: ItemType.DOCUMENT,
2308+
type: 'document',
23102309
memberships: [{ account: 'actor', permission: 'write' }],
23112310
},
23122311
{

0 commit comments

Comments
 (0)