Skip to content

Commit

Permalink
feat: add support to remove sharing password in workspace
Browse files Browse the repository at this point in the history
  • Loading branch information
apsantiso committed Aug 12, 2024
1 parent ac28e4d commit 265a457
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 2 deletions.
1 change: 0 additions & 1 deletion src/modules/folder/folder.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,6 @@ export class FolderController {
value: 'folder',
},
])
@RequiredSharingPermissions(SharingActionName.GetItems)
@WorkspacesInBehalfValidationFolder()
async getFolderAncestors(
@UserDecorator() user: User,
Expand Down
9 changes: 8 additions & 1 deletion src/modules/sharing/sharing.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ import { ThrottlerGuard } from '../../guards/throttler.guard';
import { SetSharingPasswordDto } from './dto/set-sharing-password.dto';
import { UuidDto } from '../../common/uuid.dto';
import { HttpExceptionFilter } from '../../lib/http/http-exception.filter';
import { WorkspacesInBehalfGuard } from '../workspaces/guards/workspaces-resources-in-behalf.decorator';
import {
WorkspaceResourcesAction,
WorkspacesInBehalfGuard,
} from '../workspaces/guards/workspaces-resources-in-behalf.decorator';
import { GetDataFromRequest } from '../../common/extract-data-from-request';

@ApiTags('Sharing')
Expand Down Expand Up @@ -121,6 +124,8 @@ export class SharingController {
description: 'Id of the sharing',
type: String,
})
@GetDataFromRequest([{ sourceKey: 'params', fieldName: 'sharingId' }])
@WorkspacesInBehalfGuard(WorkspaceResourcesAction.ModifySharingById)
@ApiOkResponse({ description: 'Sets/edit password for public sharings' })
async setPublicSharingPassword(
@UserDecorator() user: User,
Expand All @@ -145,6 +150,8 @@ export class SharingController {
type: String,
})
@ApiOkResponse({ description: 'Remove ' })
@GetDataFromRequest([{ sourceKey: 'params', fieldName: 'sharingId' }])
@WorkspacesInBehalfGuard(WorkspaceResourcesAction.ModifySharingById)
async removePublicSharingPassword(
@UserDecorator() user: User,
@Param('sharingId') sharingId: Sharing['id'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface ValidationOptions {
export enum WorkspaceResourcesAction {
AddItemsToTrash = 'addItemsToTrash',
DeleteItemsFromTrash = 'deleteItemsFromTrash',
ModifySharingById = 'modifySharingById',
Default = 'default',
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,35 @@ describe('WorkspacesResourcesItemsInBehalfGuard', () => {
expect(hasPermissions).toBeTruthy();
});
});

describe('hasUserAccessToSharing', () => {
it('When sharing item is found and creator is requester, it should return true', async () => {
const user = newUser();

workspaceUseCases.getWorkspaceItemBySharingId.mockResolvedValue(
newWorkspaceItemUser({ createdBy: user.uuid }),
);

const hasPermissions = await guard.hasUserAccessToSharing(user, {
sharingId: v4(),
});
expect(hasPermissions).toBeTruthy();
});

it('When sharing item is found and creator is not requester, it should return false', async () => {
const user = newUser();
const notCreator = newUser();

workspaceUseCases.getWorkspaceItemBySharingId.mockResolvedValue(
newWorkspaceItemUser({ createdBy: user.uuid }),
);

const hasPermissions = await guard.hasUserAccessToSharing(notCreator, {
sharingId: v4(),
});
expect(hasPermissions).toBeFalsy();
});
});
});

const createMockExecutionContext = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ export class WorkspacesResourcesItemsInBehalfGuard implements CanActivate {
this.hasUserTrashPermissions.bind(this),
[WorkspaceResourcesAction.DeleteItemsFromTrash]:
this.hasUserTrashPermissions.bind(this),
[WorkspaceResourcesAction.ModifySharingById]:
this.hasUserAccessToSharing.bind(this),
[WorkspaceResourcesAction.Default]: this.hasUserPermissions.bind(this),
};

Expand Down Expand Up @@ -153,6 +155,15 @@ export class WorkspacesResourcesItemsInBehalfGuard implements CanActivate {
return isCreator;
}

async hasUserAccessToSharing(requester: User, data: any): Promise<boolean> {
const { sharingId } = data;

const item =
await this.workspaceUseCases.getWorkspaceItemBySharingId(sharingId);

return !!item?.isOwnedBy(requester);
}

private decodeWorkspaceToken(token: string): DecodedWorkspaceToken {
try {
const decoded = verifyWithDefaultSecret(token) as DecodedWorkspaceToken;
Expand Down
24 changes: 24 additions & 0 deletions src/modules/workspaces/workspaces.usecase.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3560,6 +3560,30 @@ describe('WorkspacesUsecases', () => {
});
});

describe('getWorkspaceItemBySharingId', () => {
it('When sharing is not valid, then it should throw', async () => {
const sharingId = v4();

jest.spyOn(sharingUseCases, 'findSharingBy').mockResolvedValue(null);

await expect(
service.getWorkspaceItemBySharingId(sharingId),
).rejects.toThrow(BadRequestException);
});

it('When sharing is valid, then it should return item', async () => {
const sharing = newSharing();
const item = newWorkspaceItemUser();

jest.spyOn(sharingUseCases, 'findSharingBy').mockResolvedValue(sharing);
jest.spyOn(workspaceRepository, 'getItemBy').mockResolvedValue(item);

const result = await service.getWorkspaceItemBySharingId(sharing.id);

expect(result).toBe(item);
});
});

describe('teams', () => {
describe('createTeam', () => {
it('When workspace is not found, then fail', async () => {
Expand Down
14 changes: 14 additions & 0 deletions src/modules/workspaces/workspaces.usecase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1619,6 +1619,20 @@ export class WorkspacesUsecases {
return this.workspaceRepository.findWorkspaceResourcesOwner(workspace.id);
}

async getWorkspaceItemBySharingId(sharingId: Sharing['id']) {
const sharing = await this.sharingUseCases.findSharingBy({ id: sharingId });

if (!sharing) {
throw new BadRequestException('Sharing does not exist');
}

const item = await this.workspaceRepository.getItemBy({
itemId: sharing.itemId,
});

return item;
}

async isUserCreatorOfItem(
requester: User,
itemId: WorkspaceItemUser['itemId'],
Expand Down

0 comments on commit 265a457

Please sign in to comment.