1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Server: Refactor ShareType

This commit is contained in:
Laurent Cozic 2021-05-16 12:46:58 +02:00
parent 489995daef
commit b9955f58d3
11 changed files with 34 additions and 35 deletions

View File

@ -237,9 +237,8 @@ export function changeTypeToString(t: ChangeType): string {
}
export enum ShareType {
Link = 1, // When a note is shared via a public link
App = 2, // When a note is shared with another user on the same server instance
JoplinRootFolder = 3,
Note = 1, // When a note is shared via a public link
Folder = 3, // When a complete folder is shared with another Joplin Server user
}
export enum ShareUserStatus {

View File

@ -416,7 +416,7 @@ export default class ItemModel extends BaseModel<Item> {
const path = await this.joplinItemPath(jopId);
if (!path.length) throw new ApiError(`Cannot retrieve path for item: ${jopId}`, null, 'noPathForItem');
const rootFolderItem = path[path.length - 1];
const share = await this.models().share().itemShare(ShareType.JoplinRootFolder, rootFolderItem.id);
const share = await this.models().share().itemShare(ShareType.Folder, rootFolderItem.id);
if (!share) return null;
return {

View File

@ -27,7 +27,7 @@ describe('ShareModel', function() {
error = await checkThrowAsync(async () => await models().share().createShare(user.id, 20 as ShareType, item.id));
expect(error instanceof ErrorBadRequest).toBe(true);
error = await checkThrowAsync(async () => await models().share().createShare(user.id, ShareType.Link, 'doesntexist'));
error = await checkThrowAsync(async () => await models().share().createShare(user.id, ShareType.Note, 'doesntexist'));
expect(error instanceof ErrorNotFound).toBe(true);
});
@ -49,14 +49,14 @@ describe('ShareModel', function() {
});
const folderItem1 = await models().item().loadByJopId(user1.id, '000000000000000000000000000000F1');
await shareWithUserAndAccept(session1.id, session3.id, user3, ShareType.JoplinRootFolder, folderItem1);
await shareWithUserAndAccept(session1.id, session3.id, user3, ShareType.Folder, folderItem1);
const folderItem2 = await models().item().loadByJopId(user2.id, '000000000000000000000000000000F2');
await shareWithUserAndAccept(session2.id, session1.id, user1, ShareType.JoplinRootFolder, folderItem2);
await shareWithUserAndAccept(session2.id, session1.id, user1, ShareType.Folder, folderItem2);
const shares1 = await models().share().byUserId(user1.id, ShareType.JoplinRootFolder);
const shares2 = await models().share().byUserId(user2.id, ShareType.JoplinRootFolder);
const shares3 = await models().share().byUserId(user3.id, ShareType.JoplinRootFolder);
const shares1 = await models().share().byUserId(user1.id, ShareType.Folder);
const shares2 = await models().share().byUserId(user2.id, ShareType.Folder);
const shares3 = await models().share().byUserId(user3.id, ShareType.Folder);
expect(shares1.length).toBe(2);
expect(shares1.find(s => s.folder_id === '000000000000000000000000000000F1')).toBeTruthy();

View File

@ -16,7 +16,7 @@ export default class ShareModel extends BaseModel<Share> {
if (action === AclAction.Create) {
if (!await this.models().item().userHasItem(user.id, resource.item_id)) throw new ErrorForbidden('cannot share an item not owned by the user');
if (resource.type === ShareType.JoplinRootFolder) {
if (resource.type === ShareType.Folder) {
const item = await this.models().item().loadByJopId(user.id, resource.folder_id);
if (item.jop_parent_id) throw new ErrorForbidden('A shared notebook must be at the root');
}
@ -44,8 +44,8 @@ export default class ShareModel extends BaseModel<Share> {
}
protected async validate(share: Share, options: ValidateOptions = {}): Promise<Share> {
if ('type' in share && ![ShareType.Link, ShareType.App, ShareType.JoplinRootFolder].includes(share.type)) throw new ErrorBadRequest(`Invalid share type: ${share.type}`);
if (share.type !== ShareType.Link && await this.itemIsShared(share.type, share.item_id)) throw new ErrorBadRequest('A shared item cannot be shared again');
if ('type' in share && ![ShareType.Note, ShareType.Folder].includes(share.type)) throw new ErrorBadRequest(`Invalid share type: ${share.type}`);
if (share.type !== ShareType.Note && await this.itemIsShared(share.type, share.item_id)) throw new ErrorBadRequest('A shared item cannot be shared again');
const item = await this.models().item().load(share.item_id);
if (!item) throw new ErrorNotFound(`Could not find item: ${share.item_id}`);
@ -299,7 +299,7 @@ export default class ShareModel extends BaseModel<Share> {
if (share) return share;
const shareToSave = {
type: ShareType.JoplinRootFolder,
type: ShareType.Folder,
item_id: folderItem.id,
owner_id: owner.id,
folder_id: folderId,
@ -317,7 +317,7 @@ export default class ShareModel extends BaseModel<Share> {
if (existingShare) return existingShare;
const shareToSave = {
type: ShareType.Link,
type: ShareType.Note,
item_id: noteItem.id,
owner_id: owner.id,
note_id: noteId,

View File

@ -128,7 +128,7 @@ export default class ShareUserModel extends BaseModel<ShareUser> {
public async deleteByShare(share: Share): Promise<void> {
// Notes that are shared by link do not have associated ShareUser items,
// so there's nothing to do.
if (share.type !== ShareType.JoplinRootFolder) return;
if (share.type !== ShareType.Folder) return;
const shareUsers = await this.byShareId(share.id, null);

View File

@ -29,8 +29,8 @@ describe('share_users', function() {
});
const folderItem1 = await models().item().loadByJopId(user1.id, '000000000000000000000000000000F1');
const folderItem2 = await models().item().loadByJopId(user1.id, '000000000000000000000000000000F2');
const { share: share1 } = await shareWithUserAndAccept(session1.id, session2.id, user2, ShareType.JoplinRootFolder, folderItem1);
const { share: share2 } = await shareWithUserAndAccept(session1.id, session2.id, user2, ShareType.JoplinRootFolder, folderItem2);
const { share: share1 } = await shareWithUserAndAccept(session1.id, session2.id, user2, ShareType.Folder, folderItem1);
const { share: share2 } = await shareWithUserAndAccept(session1.id, session2.id, user2, ShareType.Folder, folderItem2);
const shareUsers = await getApi<PaginatedResults>(session2.id, 'share_users');
expect(shareUsers.items.length).toBe(2);
@ -44,7 +44,7 @@ describe('share_users', function() {
await createItemTree(user1.id, '', { '000000000000000000000000000000F1': {} });
const folderItem = await models().item().loadByJopId(user1.id, '000000000000000000000000000000F1');
const { shareUser } = await shareWithUserAndAccept(session1.id, session2.id, user2, ShareType.JoplinRootFolder, folderItem);
const { shareUser } = await shareWithUserAndAccept(session1.id, session2.id, user2, ShareType.Folder, folderItem);
// User can modify own UserShare object
await patchApi(session2.id, `share_users/${shareUser.id}`, { status: ShareUserStatus.Rejected });

View File

@ -32,7 +32,7 @@ describe('shares.folder', function() {
// Create the file share object
// ----------------------------------------------------------------
const share = await postApi<Share>(session1.id, 'shares', {
type: ShareType.JoplinRootFolder,
type: ShareType.Folder,
folder_id: folderItem.jop_id,
});

View File

@ -37,7 +37,7 @@ describe('shares', function() {
await createItemTree(user1.id, '', tree);
const folderItem = await itemModel1.loadByJopId(user1.id, '000000000000000000000000000000F1');
const noteItem2 = await itemModel1.loadByJopId(user1.id, '00000000000000000000000000000002');
const { share } = await shareWithUserAndAccept(session1.id, session2.id, user2, ShareType.JoplinRootFolder, folderItem);
const { share } = await shareWithUserAndAccept(session1.id, session2.id, user2, ShareType.Folder, folderItem);
// Only share with user 3, without accepting it
await postApi(session1.id, `shares/${share.id}/users`, {
@ -54,11 +54,11 @@ describe('shares', function() {
const share1: Share = shares.items.find(it => it.folder_id === '000000000000000000000000000000F1');
expect(share1).toBeTruthy();
expect(share1.type).toBe(ShareType.JoplinRootFolder);
expect(share1.type).toBe(ShareType.Folder);
const share2: Share = shares.items.find(it => it.note_id === '00000000000000000000000000000002');
expect(share2).toBeTruthy();
expect(share2.type).toBe(ShareType.Link);
expect(share2.type).toBe(ShareType.Note);
const shareUsers = await getApi<PaginatedResults>(session1.id, `shares/${share1.id}/users`);
expect(shareUsers.items.length).toBe(2);

View File

@ -92,7 +92,7 @@ router.get('api/shares/:id', async (path: SubPath, ctx: AppContext) => {
const shareModel = ctx.models.share();
const share = await shareModel.load(path.id);
if (share && share.type === ShareType.Link) {
if (share && share.type === ShareType.Note) {
// No authentication is necessary - anyone who knows the share ID is allowed
// to access the file. It is essentially public.
return shareModel.toApiOutput(share);

View File

@ -62,7 +62,7 @@ describe('shares.link', function() {
});
const share = await postApi<Share>(session.id, 'shares', {
type: ShareType.Link,
type: ShareType.Note,
note_id: noteItem.jop_id,
});
@ -82,7 +82,7 @@ describe('shares.link', function() {
});
const share = await postApi<Share>(session.id, 'shares', {
type: ShareType.Link,
type: ShareType.Note,
note_id: noteItem.jop_id,
});
@ -103,7 +103,7 @@ describe('shares.link', function() {
await createItem(session.id, 'root:/.resource/96765a68655f4446b3dbad7d41b6566e:', await testImageBuffer());
const share = await postApi<Share>(session.id, 'shares', {
type: ShareType.Link,
type: ShareType.Note,
note_id: noteItem.jop_id,
});
@ -137,7 +137,7 @@ describe('shares.link', function() {
});
const share = await postApi<Share>(session.id, 'shares', {
type: ShareType.Link,
type: ShareType.Note,
note_id: noteItem.jop_id,
});
@ -151,7 +151,7 @@ describe('shares.link', function() {
});
const share = await postApi<Share>(session.id, 'shares', {
type: ShareType.Link,
type: ShareType.Note,
note_id: noteItem.jop_id,
});

View File

@ -16,7 +16,7 @@ export async function createFolderShare(sessionId: string, folderId: string): Pr
// const item = await createFolder(sessionId, { id: '00000000 });
return postApi<Share>(sessionId, 'shares', {
type: ShareType.JoplinRootFolder,
type: ShareType.Folder,
folder_id: folderId,
});
}
@ -75,7 +75,7 @@ export async function shareFolderWithUser(sharerSessionId: string, shareeSession
});
const share: Share = await postApi<Share>(sharerSessionId, 'shares', {
type: ShareType.JoplinRootFolder,
type: ShareType.Folder,
folder_id: rootFolderItem.jop_id,
});
@ -113,16 +113,16 @@ export async function shareFolderWithUser(sharerSessionId: string, shareeSession
// - User 2 accepts the share
//
// The result is that user 2 will have a file linked to user 1's file.
export async function shareWithUserAndAccept(sharerSessionId: string, shareeSessionId: string, sharee: User, shareType: ShareType = ShareType.App, item: Item = null): Promise<ShareResult> {
export async function shareWithUserAndAccept(sharerSessionId: string, shareeSessionId: string, sharee: User, shareType: ShareType = ShareType.Folder, item: Item = null): Promise<ShareResult> {
item = item || await createItem(sharerSessionId, 'root:/test.txt:', 'testing share');
let share: Share = null;
if ([ShareType.JoplinRootFolder, ShareType.Link].includes(shareType)) {
if ([ShareType.Folder, ShareType.Note].includes(shareType)) {
share = await postApi<Share>(sharerSessionId, 'shares', {
type: shareType,
note_id: shareType === ShareType.Link ? item.jop_id : undefined,
folder_id: shareType === ShareType.JoplinRootFolder ? item.jop_id : undefined,
note_id: shareType === ShareType.Note ? item.jop_id : undefined,
folder_id: shareType === ShareType.Folder ? item.jop_id : undefined,
});
} else {
const sharer = await models().session().sessionUser(sharerSessionId);