Skip to content

Commit

Permalink
feat: add accessible items endpoint (#538)
Browse files Browse the repository at this point in the history
  • Loading branch information
pyphilia authored Dec 18, 2023
1 parent 95cf2c4 commit 5da09cd
Show file tree
Hide file tree
Showing 11 changed files with 350 additions and 4 deletions.
21 changes: 20 additions & 1 deletion src/api/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,24 @@ import {
} from '@graasp/sdk';

import { DEFAULT_THUMBNAIL_SIZE } from '../config/constants';
import { PartialQueryConfigForApi } from '../types';
import {
Paginated,
PaginationParams,
PartialQueryConfigForApi,
} from '../types';
import { getParentsIdsFromPath } from '../utils/item';
import { verifyAuthentication } from './axios';
import {
GET_OWN_ITEMS_ROUTE,
GET_RECYCLED_ITEMS_DATA_ROUTE,
ItemSearchParams,
SHARED_ITEM_WITH_ROUTE,
buildCopyItemsRoute,
buildDeleteItemsRoute,
buildDownloadFilesRoute,
buildDownloadItemThumbnailRoute,
buildEditItemRoute,
buildGetAccessibleItems,
buildGetChildrenRoute,
buildGetItemDescendants,
buildGetItemParents,
Expand Down Expand Up @@ -55,6 +61,19 @@ export const getOwnItems = async ({
.then(({ data }) => data),
);

export const getAccessibleItems = async (
params: ItemSearchParams,
pagination: PaginationParams,
{ API_HOST, axios }: PartialQueryConfigForApi,
) =>
verifyAuthentication(() =>
axios
.get<Paginated<DiscriminatedItem>>(
`${API_HOST}/${buildGetAccessibleItems(params, pagination)}`,
)
.then(({ data }) => data),
);

export type PostItemPayloadType = Partial<DiscriminatedItem> &
Pick<DiscriminatedItem, 'type' | 'name'> & {
parentId?: UUID;
Expand Down
23 changes: 23 additions & 0 deletions src/api/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import {
DiscriminatedItem,
ItemTag,
ItemTagType,
Member,
UUID,
} from '@graasp/sdk';

import qs from 'qs';

import { DEFAULT_THUMBNAIL_SIZE } from '../config/constants';
import { PaginationParams } from '../types';
import { AggregateActionsArgs } from '../utils/action';

export const APPS_ROUTE = 'app-items';
Expand All @@ -28,6 +30,26 @@ export const buildAppListRoute = `${APPS_ROUTE}/list`;
export const SHORT_LINKS_ROUTE = `${ITEMS_ROUTE}/short-links`;
export const SHORT_LINKS_LIST_ROUTE = `${SHORT_LINKS_ROUTE}/list`;

export type ItemSearchParams =
| {
creatorId?: Member['id'];
name?: string;
ordering?: 'desc' | 'asc';
sortBy?: 'name' | 'type' | 'creator' | 'created_at' | 'updated_at';
}
| undefined;
export const buildGetAccessibleItems = (
params: ItemSearchParams,
pagination: PaginationParams,
) =>
`${ITEMS_ROUTE}/accessible${qs.stringify(
{ ...params, ...pagination },
{
arrayFormat: 'repeat',
addQueryPrefix: true,
},
)}`;

export const buildPostItemRoute = (parentId?: UUID) => {
let url = ITEMS_ROUTE;
if (parentId) {
Expand Down Expand Up @@ -438,6 +460,7 @@ export const API_ROUTES = {
buildExportItemChatRoute,
buildExportItemRoute,
buildFavoriteItemRoute,
buildGetAccessibleItems,
buildGetActions,
buildGetAllPublishedItemsRoute,
buildGetApiAccessTokenRoute,
Expand Down
8 changes: 8 additions & 0 deletions src/config/keys.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { AggregateBy, Category, UUID } from '@graasp/sdk';

import { ItemSearchParams } from '../api/routes';
import { PaginationParams } from '../types';
import { AggregateActionsArgs } from '../utils/action';
import { hashItemsIds } from '../utils/item';
import { DEFAULT_THUMBNAIL_SIZE } from './constants';
Expand Down Expand Up @@ -38,6 +40,12 @@ export const buildItemDescendantsKey = (id: UUID) => [
'descendants',
id,
];

export const accessibleItemsKeys = {
all: [ITEMS_KEY, 'accessible'] as const,
singlePage: (params: ItemSearchParams, pagination: PaginationParams) =>
[...accessibleItemsKeys.all, params, pagination] as const,
};
export const SHARED_ITEMS_KEY = 'shared';
export const CURRENT_MEMBER_KEY = 'currentMember';
export const MEMBERS_KEY = 'members';
Expand Down
40 changes: 40 additions & 0 deletions src/hooks/item.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
SHARED_ITEM_WITH_ROUTE,
buildDownloadFilesRoute,
buildDownloadItemThumbnailRoute,
buildGetAccessibleItems,
buildGetChildrenRoute,
buildGetItemParents,
buildGetItemRoute,
Expand All @@ -37,6 +38,7 @@ import {
import {
OWN_ITEMS_KEY,
SHARED_ITEMS_KEY,
accessibleItemsKeys,
buildFileContentKey,
buildItemChildrenKey,
buildItemKey,
Expand Down Expand Up @@ -339,6 +341,44 @@ describe('Items Hooks', () => {
});
});

describe('useAccessibleItems', () => {
const params = {};
const pagination = {};
const route = `/${buildGetAccessibleItems(params, pagination)}`;
const response = { data: ITEMS, totalCount: ITEMS.length };
const hook = () => hooks.useAccessibleItems();
const key = accessibleItemsKeys.singlePage(params, pagination);

it(`Receive accessible items`, async () => {
const endpoints = [{ route, response }];
const { data } = await mockHook({ endpoints, hook, wrapper });

expect(data).toMatchObject(response);
// verify cache keys
expect(queryClient.getQueryData(key)).toMatchObject(response);
});

it(`Unauthorized`, async () => {
const endpoints = [
{
route,
response: UNAUTHORIZED_RESPONSE,
statusCode: StatusCodes.UNAUTHORIZED,
},
];
const { data, isError } = await mockHook({
hook,
endpoints,
wrapper,
});

expect(data).toBeFalsy();
expect(isError).toBeTruthy();
// verify cache keys
expect(queryClient.getQueryData(key)).toBeFalsy();
});
});

describe('useItem', () => {
const response = ITEMS[0];
const { id } = response;
Expand Down
55 changes: 53 additions & 2 deletions src/hooks/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {

import * as Api from '../api';
import { splitRequestByIdsAndReturn } from '../api/axios';
import { ItemSearchParams } from '../api/routes';
import {
CONSTANT_KEY_CACHE_TIME_MILLISECONDS,
DEFAULT_THUMBNAIL_SIZE,
Expand All @@ -30,6 +31,7 @@ import {
RECYCLED_ITEMS_DATA_KEY,
RECYCLED_ITEMS_KEY,
SHARED_ITEMS_KEY,
accessibleItemsKeys,
buildEtherpadKey,
buildFileContentKey,
buildItemChildrenKey,
Expand All @@ -40,10 +42,11 @@ import {
buildItemThumbnailKey,
buildItemsKey,
} from '../config/keys';
import { getOwnItemsRoutine } from '../routines';
import { QueryClientConfig } from '../types';
import { getAccessibleItemsRoutine, getOwnItemsRoutine } from '../routines';
import { PaginationParams, QueryClientConfig } from '../types';
import { paginate } from '../utils/util';
import { configureWsItemHooks } from '../ws';
import useDebounce from './useDebounce';

export default (
queryConfig: QueryClientConfig,
Expand All @@ -58,6 +61,53 @@ export default (
: undefined;

return {
/**
* Returns items the highest in the tree you have access to
* Is paginated by default
* @param params
* @param pagination
* @param _options
* @returns
*/
useAccessibleItems: (
params?: ItemSearchParams,
pagination?: PaginationParams,
options?: { getUpdates?: boolean },
) => {
const queryClient = useQueryClient();
const getUpdates = options?.getUpdates ?? enableWebsocket;

const { data: currentMember } = useCurrentMember();
itemWsHooks?.useAccessibleItemsUpdates(
getUpdates ? currentMember?.id : null,
);

const debouncedName = useDebounce(params?.name, 500);
const finalParams = { ...params, name: debouncedName };
const paginationParams = { ...(pagination ?? {}) };
return useQuery({
queryKey: accessibleItemsKeys.singlePage(finalParams, paginationParams),
queryFn: () =>
Api.getAccessibleItems(finalParams, paginationParams, queryConfig),
onSuccess: async ({ data: items }) => {
// save items in their own key
// eslint-disable-next-line no-unused-expressions
items?.forEach(async (item) => {
const { id } = item;
queryClient.setQueryData(buildItemKey(id), item);
});
},
onError: (error) => {
notifier?.({
type: getAccessibleItemsRoutine.FAILURE,
payload: { error },
});
},
...defaultQueryOptions,
});
},

/** @deprecated use useAccessibleItems */
useOwnItems: (options?: { getUpdates?: boolean }) => {
const queryClient = useQueryClient();
const getUpdates = options?.getUpdates ?? enableWebsocket;
Expand Down Expand Up @@ -221,6 +271,7 @@ export default (
});
},

/** @deprecated use useAccessibleItems */
useSharedItems: (options?: { getUpdates?: boolean }) => {
const getUpdates = options?.getUpdates ?? enableWebsocket;

Expand Down
2 changes: 2 additions & 0 deletions src/mutations/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ export default (queryConfig: QueryClientConfig) => {
return prevValue;
};

// todo: we don't consider accessible, shared or published items here
// this part is a bit flacky/unclear it might be better to refactor it
const mutateParentChildren = async (
args: ({ id?: string } | { childPath: string }) & { value: unknown },
queryClient: QueryClient,
Expand Down
2 changes: 1 addition & 1 deletion src/routines/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import createRoutine from './utils';
export const createItemRoutine = createRoutine('CREATE_ITEM');
export const deleteItemRoutine = createRoutine('DELETE_ITEM');
export const getOwnItemsRoutine = createRoutine('GET_OWN_ITEMS');
export const setItemRoutine = createRoutine('GET_OWN_ITEMS');
export const getAccessibleItemsRoutine = createRoutine('GET_ACCESSIBLE');
export const moveItemRoutine = createRoutine('MOVE_ITEM');
export const moveItemsRoutine = createRoutine('MOVE_ITEMS');
export const copyItemRoutine = createRoutine('COPY_ITEM');
Expand Down
9 changes: 9 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,12 @@ export type PartialQueryConfigForApi = Pick<
// todo: move per feature folders
export type NewInvitation = Pick<Invitation, 'email' & 'permission'> &
Partial<Invitation>;

export type PaginationParams = {
page?: number;
pageSize?: number;
};

export type Paginated<T> = { data: T[]; totalCount: number };

export const defaultPagination: PaginationParams = { page: 1 };
1 change: 1 addition & 0 deletions src/ws/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const KINDS = {
OWN: 'own',
RECYCLE_BIN: 'recycle_bin',
SELF: 'self',
ACCESSIBLE: 'accessible',
SHARED: 'shared',
};

Expand Down
Loading

0 comments on commit 5da09cd

Please sign in to comment.