Skip to content

Commit

Permalink
Adds command 'spo folder sharinglink remove'. Closes pnp#5966
Browse files Browse the repository at this point in the history
  • Loading branch information
Saurabh7019 authored and MathijsVerbeeck committed Sep 11, 2024
1 parent 818f6d5 commit 6f92ffe
Show file tree
Hide file tree
Showing 5 changed files with 401 additions and 0 deletions.
50 changes: 50 additions & 0 deletions docs/docs/cmd/spo/folder/folder-sharinglink-remove.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import Global from '/docs/cmd/_global.mdx';

# spo folder sharinglink remove

Removes a specific sharing link of a folder

## Usage

```sh
m365 spo folder sharinglink remove [options]
```

## Options

```md definition-list
`-u, --webUrl <webUrl>`
: The URL of the site where the folder is located.

`--folderUrl [folderUrl]`
: The server- or site-relative decoded URL of the folder. Specify either `folderUrl` or `folderId` but not both.

`--folderId [folderId]`
: The UniqueId (GUID) of the folder. Specify either `folderUrl` or `folderId` but not both.

`-i, --id <id>`
: The ID of the sharing link.

`-f, --force`
: Don't prompt for confirmation.
```

<Global />

## Examples

Removes a specific sharing link from a folder by id without prompting for confirmation.

```sh
m365 spo folder sharinglink remove --webUrl https://contoso.sharepoint.com/sites/demo --folderId daebb04b-a773-4baa-b1d1-3625418e3234 --id c391b57d-5783-4c53-9236-cefb5c6ef323 --force
```

Removes a specific sharing link from a folder by url with prompting for confirmation.

```sh
m365 spo folder sharinglink remove --webUrl https://contoso.sharepoint.com/sites/demo --folderUrl /sites/demo/shared%20documents/Folder --id c391b57d-5783-4c53-9236-cefb5c6ef323
```

## Response

The command won't return a response on success.
5 changes: 5 additions & 0 deletions docs/src/config/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2617,6 +2617,11 @@ const sidebars: SidebarsConfig = {
type: 'doc',
label: 'folder sharinglink list',
id: 'cmd/spo/folder/folder-sharinglink-list'
},
{
type: 'doc',
label: 'folder sharinglink remove',
id: 'cmd/spo/folder/folder-sharinglink-remove'
}
]
},
Expand Down
1 change: 1 addition & 0 deletions src/m365/spo/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export default {
FOLDER_SHARINGLINK_CLEAR: `${prefix} folder sharinglink clear`,
FOLDER_SHARINGLINK_GET: `${prefix} folder sharinglink get`,
FOLDER_SHARINGLINK_LIST: `${prefix} folder sharinglink list`,
FOLDER_SHARINGLINK_REMOVE: `${prefix} folder sharinglink remove`,
GET: `${prefix} get`,
GROUP_ADD: `${prefix} group add`,
GROUP_GET: `${prefix} group get`,
Expand Down
210 changes: 210 additions & 0 deletions src/m365/spo/commands/folder/folder-sharinglink-remove.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
import assert from 'assert';
import sinon from 'sinon';
import auth from '../../../../Auth.js';
import { cli } from '../../../../cli/cli.js';
import { CommandError } from '../../../../Command.js';
import { telemetry } from '../../../../telemetry.js';
import { Logger } from '../../../../cli/Logger.js';
import request from '../../../../request.js';
import { pid } from '../../../../utils/pid.js';
import { session } from '../../../../utils/session.js';
import { sinonUtil } from '../../../../utils/sinonUtil.js';
import { CommandInfo } from '../../../../cli/CommandInfo.js';
import commands from '../../commands.js';
import command from './folder-sharinglink-remove.js';
import { spo } from '../../../../utils/spo.js';
import { drive } from '../../../../utils/drive.js';
import { Drive } from '@microsoft/microsoft-graph-types';

describe(commands.FOLDER_SHARINGLINK_REMOVE, () => {
let log: any[];
let logger: Logger;
let commandInfo: CommandInfo;
let promptIssued: boolean = false;

const webUrl = 'https://contoso.sharepoint.com/sites/project-x';
const folderId = 'f09c4efe-b8c0-4e89-a166-03418661b89b';
const folderUrl = '/sites/project-x/shared documents/folder1';
const siteId = '0f9b8f4f-0e8e-4630-bb0a-501442db9b64';
const driveId = '013TMHP6UOOSLON57HT5GLKEU7R5UGWZVK';
const itemId = 'b!T4-bD44OMEa7ClAUQtubZID9tc40pGJKpguycvELod_Gx-lo4ZQiRJ7vylonTufG';
const id = 'ef1cddaa-b74a-4aae-8a7a-5c16b4da67f2';

const driveDetails: Drive = {
id: driveId,
webUrl: `${webUrl}/Shared%20Documents`
};

const getStubs: any = (options: any) => {
sinon.stub(spo, 'getFolderServerRelativeUrl').resolves(options.folderUrl);
sinon.stub(spo, 'getSiteId').resolves(options.siteId);
sinon.stub(drive, 'getDriveByUrl').resolves(options.drive);
sinon.stub(drive, 'getDriveItemId').resolves(options.itemId);
};

before(() => {
sinon.stub(auth, 'restoreAuth').resolves();
sinon.stub(telemetry, 'trackEvent').returns();
sinon.stub(pid, 'getProcessName').returns('');
sinon.stub(session, 'getId').returns('');
auth.connection.active = true;
commandInfo = cli.getCommandInfo(command);
});

beforeEach(() => {
log = [];
logger = {
log: async (msg: string) => {
log.push(msg);
},
logRaw: async (msg: string) => {
log.push(msg);
},
logToStderr: async (msg: string) => {
log.push(msg);
}
};

sinon.stub(cli, 'promptForConfirmation').callsFake(async () => {
promptIssued = true;
return false;
});

promptIssued = false;
});

afterEach(() => {
sinonUtil.restore([
request.delete,
cli.promptForConfirmation,
spo.getSiteId,
spo.getFolderServerRelativeUrl,
drive.getDriveByUrl,
drive.getDriveItemId
]);
});

after(() => {
sinon.restore();
auth.connection.active = false;
});

it('has correct name', () => {
assert.strictEqual(command.name, commands.FOLDER_SHARINGLINK_REMOVE);
});

it('has a description', () => {
assert.notStrictEqual(command.description, null);
});

it('fails validation if the webUrl option is not a valid SharePoint site URL', async () => {
const actual = await command.validate({ options: { webUrl: 'foo', folderId: folderId, id: id } }, commandInfo);
assert.notStrictEqual(actual, true);
});

it('fails validation if the folderId option is not a valid GUID', async () => {
const actual = await command.validate({ options: { webUrl: webUrl, folderId: 'invalid', id: id } }, commandInfo);
assert.notStrictEqual(actual, true);
});

it('passes validation if options are valid', async () => {
const actual = await command.validate({ options: { webUrl: webUrl, folderId: folderId, id: id } }, commandInfo);
assert.strictEqual(actual, true);
});

it('prompts before removing the specified sharing link to a folder when force option not passed', async () => {
await command.action(logger, {
options: {
webUrl: webUrl,
folderId: folderId,
id: id
}
});

assert(promptIssued);
});

it('aborts removing the specified sharing link to a folder when force option not passed and prompt not confirmed', async () => {
const deleteSpy = sinon.spy(request, 'delete');
sinonUtil.restore(cli.promptForConfirmation);
sinon.stub(cli, 'promptForConfirmation').resolves(false);

await command.action(logger, {
options: {
webUrl: webUrl,
folderUrl: folderUrl,
id: id
}
});

assert(deleteSpy.notCalled);
});

it('removes specified sharing link to a folder by folderId when prompt confirmed', async () => {
getStubs({ folderUrl: folderUrl, siteId: siteId, drive: driveDetails, itemId: itemId });

const requestDeleteStub = sinon.stub(request, 'delete').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/drives/${driveId}/items/${itemId}/permissions/${id}`) {
return;
}

throw 'Invalid request';
});

sinonUtil.restore(cli.promptForConfirmation);
sinon.stub(cli, 'promptForConfirmation').resolves(true);

await command.action(logger, {
options: {
verbose: true,
webUrl: webUrl,
folderId: folderId,
id: id
}
});
assert(requestDeleteStub.called);
});

it('removes specified sharing link to a folder by folderUrl when prompt confirmed', async () => {
getStubs({ folderUrl: folderUrl, siteId: siteId, drive: driveDetails, itemId: itemId });

const requestDeleteStub = sinon.stub(request, 'delete').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/drives/${driveId}/items/${itemId}/permissions/${id}`) {
return;
}

throw 'Invalid request';
});

sinonUtil.restore(cli.promptForConfirmation);
sinon.stub(cli, 'promptForConfirmation').resolves(true);

await command.action(logger, {
options: {
verbose: true,
webUrl: webUrl,
folderUrl: folderUrl,
id: id,
force: true
}
});
assert(requestDeleteStub.called);
});

it('throws error when drive not found by url', async () => {
sinon.stub(spo, 'getFolderServerRelativeUrl').resolves(folderUrl);
sinon.stub(spo, 'getSiteId').resolves(siteId);
sinon.stub(request, 'get').callsFake(async opts => {
if (opts.url === `https://graph.microsoft.com/v1.0/sites/${siteId}/drives?$select=webUrl,id`) {
return {
value: []
};
}

throw 'Invalid request';
});

await assert.rejects(command.action(logger, { options: { webUrl: webUrl, folderUrl: folderUrl, force: true } } as any),
new CommandError(`Drive 'https://contoso.sharepoint.com/sites/project-x/shared%20documents/folder1' not found`));
});
});
Loading

0 comments on commit 6f92ffe

Please sign in to comment.