diff --git a/docs/docs/cmd/onenote/notebook/notebook-add.mdx b/docs/docs/cmd/onenote/notebook/notebook-add.mdx
index 84a9daafed1..cb44e691869 100644
--- a/docs/docs/cmd/onenote/notebook/notebook-add.mdx
+++ b/docs/docs/cmd/onenote/notebook/notebook-add.mdx
@@ -36,6 +36,23 @@ m365 onenote notebook add [options]
+## Permissions
+
+
+
+
+ | Resource | Permissions |
+ |-----------------|------------------------------------------------------------------|
+ | Microsoft Graph | Notes.Create, Sites.Read.All, User.ReadBasic.All, Group.Read.All |
+
+
+
+
+ This command does not support application permissions.
+
+
+
+
## Examples
Create a Microsoft OneNote notebook for the currently logged in user
diff --git a/docs/docs/cmd/onenote/notebook/notebook-list.mdx b/docs/docs/cmd/onenote/notebook/notebook-list.mdx
index 0fc22b22d8d..a44ef3447e2 100644
--- a/docs/docs/cmd/onenote/notebook/notebook-list.mdx
+++ b/docs/docs/cmd/onenote/notebook/notebook-list.mdx
@@ -33,6 +33,23 @@ m365 onenote notebook list [options]
+## Permissions
+
+
+
+
+ | Resource | Permissions |
+ |-----------------|--------------------------------------------------------------------|
+ | Microsoft Graph | Notes.Read.All, Sites.Read.All, User.ReadBasic.All, Group.Read.All |
+
+
+
+
+ This command does not support application permissions.
+
+
+
+
## Examples
List Microsoft OneNote notebooks for the currently logged in user
diff --git a/docs/docs/cmd/onenote/page/page-list.mdx b/docs/docs/cmd/onenote/page/page-list.mdx
index 287e4b16961..25243633c6b 100644
--- a/docs/docs/cmd/onenote/page/page-list.mdx
+++ b/docs/docs/cmd/onenote/page/page-list.mdx
@@ -35,7 +35,24 @@ m365 onenote page list [options]
## Remarks
-When we don't specify either `userId`, `userName`, `groupId`, `groupName` or `webUrl`, the OneNote pages will be retrieved of the currently logged in user.
+When you don't specify either `userId`, `userName`, `groupId`, `groupName` or `webUrl`, the OneNote pages will be retrieved of the currently logged in user.
+
+## Permissions
+
+
+
+
+ | Resource | Permissions |
+ |-----------------|--------------------------------------------------------------------|
+ | Microsoft Graph | Notes.Read.All, Sites.Read.All, User.ReadBasic.All, Group.Read.All |
+
+
+
+
+ This command does not support application permissions.
+
+
+
## Examples
diff --git a/src/m365/onenote/commands/notebook/notebook-add.spec.ts b/src/m365/onenote/commands/notebook/notebook-add.spec.ts
index f98f2c80cfc..efb265ce294 100644
--- a/src/m365/onenote/commands/notebook/notebook-add.spec.ts
+++ b/src/m365/onenote/commands/notebook/notebook-add.spec.ts
@@ -14,6 +14,8 @@ import commands from '../../commands.js';
import command from './notebook-add.js';
import { entraGroup } from '../../../../utils/entraGroup.js';
import { spo } from '../../../../utils/spo.js';
+import { accessToken } from '../../../../utils/accessToken.js';
+import { formatting } from '../../../../utils/formatting.js';
describe(commands.NOTEBOOK_ADD, () => {
const name = 'My Notebook';
@@ -54,6 +56,7 @@ describe(commands.NOTEBOOK_ADD, () => {
let logger: Logger;
let loggerLogSpy: sinon.SinonSpy;
let commandInfo: CommandInfo;
+ let accessTokenStub: sinon.SinonStub;
before(() => {
sinon.stub(auth, 'restoreAuth').resolves();
@@ -78,11 +81,13 @@ describe(commands.NOTEBOOK_ADD, () => {
}
};
loggerLogSpy = sinon.spy(logger, 'log');
+ accessTokenStub = sinon.stub(accessToken, 'assertAccessTokenType').resolves();
});
afterEach(() => {
sinonUtil.restore([
- request.post
+ request.post,
+ accessToken.assertAccessTokenType
]);
});
@@ -130,6 +135,13 @@ describe(commands.NOTEBOOK_ADD, () => {
assert.strictEqual(actual, true);
});
+ it('enforces the user to use delegated permissions', async () => {
+ sinon.stub(request, 'post').resolves();
+
+ await command.action(logger, { options: {} });
+ assert(accessTokenStub.calledOnceWithExactly('delegated'));
+ });
+
it('adds notebook for the currently logged in user', async () => {
sinon.stub(request, 'post').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/me/onenote/notebooks`) {
@@ -209,7 +221,7 @@ describe(commands.NOTEBOOK_ADD, () => {
const userName = 'john@contoso.com';
sinon.stub(request, 'post').callsFake(async (opts) => {
- if (opts.url === `https://graph.microsoft.com/v1.0/users/${userName}/onenote/notebooks`) {
+ if (opts.url === `https://graph.microsoft.com/v1.0/users/${formatting.encodeQueryParameter(userName)}/onenote/notebooks`) {
return addResponse;
}
diff --git a/src/m365/onenote/commands/notebook/notebook-add.ts b/src/m365/onenote/commands/notebook/notebook-add.ts
index 75366bf3620..ae4157edc96 100644
--- a/src/m365/onenote/commands/notebook/notebook-add.ts
+++ b/src/m365/onenote/commands/notebook/notebook-add.ts
@@ -3,9 +3,10 @@ import GlobalOptions from '../../../../GlobalOptions.js';
import request, { CliRequestOptions } from '../../../../request.js';
import { entraGroup } from '../../../../utils/entraGroup.js';
import { validation } from '../../../../utils/validation.js';
-import GraphCommand from '../../../base/GraphCommand.js';
import commands from '../../commands.js';
import { spo } from '../../../../utils/spo.js';
+import GraphDelegatedCommand from '../../../base/GraphDelegatedCommand.js';
+import { formatting } from '../../../../utils/formatting.js';
interface CommandArgs {
options: Options;
@@ -20,7 +21,7 @@ interface Options extends GlobalOptions {
webUrl?: string;
}
-class OneNoteNotebookAddCommand extends GraphCommand {
+class OneNoteNotebookAddCommand extends GraphDelegatedCommand {
public get name(): string {
return commands.NOTEBOOK_ADD;
}
@@ -146,7 +147,7 @@ class OneNoteNotebookAddCommand extends GraphCommand {
endpoint += `users/${args.options.userId}`;
}
else if (args.options.userName) {
- endpoint += `users/${args.options.userName}`;
+ endpoint += `users/${formatting.encodeQueryParameter(args.options.userName)}`;
}
else if (args.options.groupId) {
endpoint += `groups/${args.options.groupId}`;
diff --git a/src/m365/onenote/commands/notebook/notebook-list.spec.ts b/src/m365/onenote/commands/notebook/notebook-list.spec.ts
index 85f2c8d210b..226e1cfea20 100644
--- a/src/m365/onenote/commands/notebook/notebook-list.spec.ts
+++ b/src/m365/onenote/commands/notebook/notebook-list.spec.ts
@@ -12,12 +12,15 @@ import { session } from '../../../../utils/session.js';
import { sinonUtil } from '../../../../utils/sinonUtil.js';
import commands from '../../commands.js';
import command from './notebook-list.js';
+import { accessToken } from '../../../../utils/accessToken.js';
+import { formatting } from '../../../../utils/formatting.js';
describe(commands.NOTEBOOK_LIST, () => {
let log: string[];
let logger: Logger;
let loggerLogSpy: sinon.SinonSpy;
let commandInfo: CommandInfo;
+ let accessTokenStub: sinon.SinonStub;
before(() => {
sinon.stub(auth, 'restoreAuth').resolves();
@@ -42,12 +45,13 @@ describe(commands.NOTEBOOK_LIST, () => {
}
};
loggerLogSpy = sinon.spy(logger, 'log');
- (command as any).items = [];
+ accessTokenStub = sinon.stub(accessToken, 'assertAccessTokenType').resolves();
});
afterEach(() => {
sinonUtil.restore([
- request.get
+ request.get,
+ accessToken.assertAccessTokenType
]);
});
@@ -93,6 +97,13 @@ describe(commands.NOTEBOOK_LIST, () => {
assert.strictEqual(actual, true);
});
+ it('enforces the user to use delegated permissions', async () => {
+ sinon.stub(request, 'get').resolves([]);
+
+ await command.action(logger, { options: {} });
+ assert(accessTokenStub.calledOnceWithExactly('delegated'));
+ });
+
it('lists Microsoft OneNote notebooks for the currently logged in user (debug)', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/me/onenote/notebooks`) {
@@ -351,7 +362,7 @@ describe(commands.NOTEBOOK_LIST, () => {
it('lists Microsoft OneNote notebooks for user by name', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
- if (opts.url === `https://graph.microsoft.com/v1.0/users/user1@contoso.onmicrosoft.com/onenote/notebooks`) {
+ if (opts.url === `https://graph.microsoft.com/v1.0/users/${formatting.encodeQueryParameter('user1@contoso.onmicrosoft.com')}/onenote/notebooks`) {
return {
"value": [
{
diff --git a/src/m365/onenote/commands/notebook/notebook-list.ts b/src/m365/onenote/commands/notebook/notebook-list.ts
index 918cf33c3f2..57d1b85af53 100644
--- a/src/m365/onenote/commands/notebook/notebook-list.ts
+++ b/src/m365/onenote/commands/notebook/notebook-list.ts
@@ -1,12 +1,13 @@
import { Notebook } from '@microsoft/microsoft-graph-types';
import { Logger } from '../../../../cli/Logger.js';
import GlobalOptions from '../../../../GlobalOptions.js';
-import request, { CliRequestOptions } from '../../../../request.js';
import { entraGroup } from '../../../../utils/entraGroup.js';
import { odata } from '../../../../utils/odata.js';
import { validation } from '../../../../utils/validation.js';
-import GraphCommand from '../../../base/GraphCommand.js';
import commands from '../../commands.js';
+import { formatting } from '../../../../utils/formatting.js';
+import GraphDelegatedCommand from '../../../base/GraphDelegatedCommand.js';
+import { spo } from '../../../../utils/spo.js';
interface CommandArgs {
options: Options;
@@ -20,7 +21,7 @@ interface Options extends GlobalOptions {
webUrl?: string;
}
-class OneNoteNotebookListCommand extends GraphCommand {
+class OneNoteNotebookListCommand extends GraphDelegatedCommand {
public get name(): string {
return commands.NOTEBOOK_LIST;
}
@@ -101,7 +102,7 @@ class OneNoteNotebookListCommand extends GraphCommand {
endpoint += `users/${args.options.userId}`;
}
else if (args.options.userName) {
- endpoint += `users/${args.options.userName}`;
+ endpoint += `users/${formatting.encodeQueryParameter(args.options.userName)}`;
}
else if (args.options.groupId) {
endpoint += `groups/${args.options.groupId}`;
@@ -111,7 +112,7 @@ class OneNoteNotebookListCommand extends GraphCommand {
endpoint += `groups/${groupId}`;
}
else if (args.options.webUrl) {
- const siteId = await this.getSpoSiteId(args.options.webUrl);
+ const siteId = await spo.getSpoGraphSiteId(args.options.webUrl);
endpoint += `sites/${siteId}`;
}
else {
@@ -126,20 +127,6 @@ class OneNoteNotebookListCommand extends GraphCommand {
return group.id!;
}
- private async getSpoSiteId(webUrl: string): Promise {
- const url = new URL(webUrl);
- const requestOptions: CliRequestOptions = {
- url: `${this.resource}/v1.0/sites/${url.hostname}:${url.pathname}`,
- headers: {
- accept: 'application/json;odata.metadata=none'
- },
- responseType: 'json'
- };
-
- const site = await request.get<{ id: string }>(requestOptions);
- return site.id;
- }
-
public async commandAction(logger: Logger, args: CommandArgs): Promise {
try {
const endpoint = await this.getEndpointUrl(args);
diff --git a/src/m365/onenote/commands/page/page-list.spec.ts b/src/m365/onenote/commands/page/page-list.spec.ts
index da76ba0b376..133f4a7445b 100644
--- a/src/m365/onenote/commands/page/page-list.spec.ts
+++ b/src/m365/onenote/commands/page/page-list.spec.ts
@@ -14,6 +14,7 @@ import { session } from '../../../../utils/session.js';
import { sinonUtil } from '../../../../utils/sinonUtil.js';
import commands from '../../commands.js';
import command from './page-list.js';
+import { accessToken } from '../../../../utils/accessToken.js';
import { settingsNames } from '../../../../settingsNames.js';
describe(commands.PAGE_LIST, () => {
@@ -76,6 +77,7 @@ describe(commands.PAGE_LIST, () => {
let logger: Logger;
let loggerLogSpy: sinon.SinonSpy;
let commandInfo: CommandInfo;
+ let accessTokenStub: sinon.SinonStub;
before(() => {
sinon.stub(auth, 'restoreAuth').resolves();
@@ -84,13 +86,7 @@ describe(commands.PAGE_LIST, () => {
sinon.stub(session, 'getId').returns('');
auth.connection.active = true;
commandInfo = cli.getCommandInfo(command);
- sinon.stub(cli, 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => {
- if (settingName === 'prompt') {
- return false;
- }
-
- return defaultValue;
- });
+ sinon.stub(cli, 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => settingName === settingsNames.prompt ? false : defaultValue);
});
beforeEach(() => {
@@ -107,14 +103,14 @@ describe(commands.PAGE_LIST, () => {
}
};
loggerLogSpy = sinon.spy(logger, 'log');
- (command as any).items = [];
+ accessTokenStub = sinon.stub(accessToken, 'assertAccessTokenType').resolves();
});
afterEach(() => {
sinonUtil.restore([
request.get,
odata.getAllItems,
- cli.getSettingWithDefaultValue
+ accessToken.assertAccessTokenType
]);
});
@@ -165,6 +161,13 @@ describe(commands.PAGE_LIST, () => {
assert.strictEqual(actual, true);
});
+ it('enforces the user to use delegated permissions', async () => {
+ sinon.stub(odata, 'getAllItems').resolves([]);
+
+ await command.action(logger, { options: {} });
+ assert(accessTokenStub.calledOnceWithExactly('delegated'));
+ });
+
it('lists Microsoft OneNote pages for the currently logged in user', async () => {
sinon.stub(odata, 'getAllItems').callsFake(async (url: string) => {
if (url === `https://graph.microsoft.com/v1.0/me/onenote/pages`) {
@@ -191,7 +194,7 @@ describe(commands.PAGE_LIST, () => {
it('lists Microsoft OneNote pages for user by name', async () => {
sinon.stub(odata, 'getAllItems').callsFake(async (url: string) => {
- if (url === `https://graph.microsoft.com/v1.0/users/${userName}/onenote/pages`) {
+ if (url === `https://graph.microsoft.com/v1.0/users/${formatting.encodeQueryParameter(userName)}/onenote/pages`) {
return pageResponse.value;
}
throw 'Invalid request';
@@ -215,7 +218,7 @@ describe(commands.PAGE_LIST, () => {
it('lists Microsoft OneNote pages in group by name', async () => {
sinon.stub(odata, 'getAllItems').callsFake(async (url: string) => {
- if (url === `https://graph.microsoft.com/v1.0/groups?$filter=displayName eq '${formatting.encodeQueryParameter(groupName)}'`) {
+ if (url === `https://graph.microsoft.com/v1.0/groups?$filter=displayName eq '${formatting.encodeQueryParameter(groupName)}'&$select=id`) {
return [{
"id": groupId,
"description": groupName,
@@ -277,7 +280,7 @@ describe(commands.PAGE_LIST, () => {
it('throws error if group by displayName returns no results', async () => {
sinon.stub(odata, 'getAllItems').callsFake(async (url: string) => {
- if (url === `https://graph.microsoft.com/v1.0/groups?$filter=displayName eq '${formatting.encodeQueryParameter(groupName)}'`) {
+ if (url === `https://graph.microsoft.com/v1.0/groups?$filter=displayName eq '${formatting.encodeQueryParameter(groupName)}'&$select=id`) {
return [];
}
throw 'Invalid request';
@@ -287,17 +290,9 @@ describe(commands.PAGE_LIST, () => {
});
it('throws an error if group by displayName returns multiple results', async () => {
- sinon.stub(cli, 'getSettingWithDefaultValue').callsFake((settingName, defaultValue) => {
- if (settingName === settingsNames.prompt) {
- return false;
- }
-
- return defaultValue;
- });
-
const duplicateGroupId = '9f3c2c36-1682-4922-9ae1-f57d2caf0de1';
sinon.stub(odata, 'getAllItems').callsFake(async (url: string) => {
- if (url === `https://graph.microsoft.com/v1.0/groups?$filter=displayName eq '${formatting.encodeQueryParameter(groupName)}'`) {
+ if (url === `https://graph.microsoft.com/v1.0/groups?$filter=displayName eq '${formatting.encodeQueryParameter(groupName)}'&$select=id`) {
return [{
"id": groupId,
"description": groupName,
@@ -311,6 +306,7 @@ describe(commands.PAGE_LIST, () => {
throw 'Invalid request';
});
- await assert.rejects(command.action(logger, { options: { groupName: groupName } } as any), new CommandError("Multiple groups with name 'Dummy Group A' found. Found: bba4c915-0ac8-47a1-bd05-087a44c92d3b, 9f3c2c36-1682-4922-9ae1-f57d2caf0de1."));
+ await assert.rejects(command.action(logger, { options: { groupName: groupName } }),
+ new CommandError("Multiple groups with name 'Dummy Group A' found. Found: bba4c915-0ac8-47a1-bd05-087a44c92d3b, 9f3c2c36-1682-4922-9ae1-f57d2caf0de1."));
});
});
diff --git a/src/m365/onenote/commands/page/page-list.ts b/src/m365/onenote/commands/page/page-list.ts
index 46852b8d74d..9594626b3ae 100644
--- a/src/m365/onenote/commands/page/page-list.ts
+++ b/src/m365/onenote/commands/page/page-list.ts
@@ -5,8 +5,9 @@ import { entraGroup } from '../../../../utils/entraGroup.js';
import { odata } from '../../../../utils/odata.js';
import { spo } from '../../../../utils/spo.js';
import { validation } from '../../../../utils/validation.js';
-import GraphCommand from '../../../base/GraphCommand.js';
import commands from '../../commands.js';
+import GraphDelegatedCommand from '../../../base/GraphDelegatedCommand.js';
+import { formatting } from '../../../../utils/formatting.js';
interface CommandArgs {
options: Options;
@@ -20,7 +21,7 @@ interface Options extends GlobalOptions {
webUrl?: string;
}
-class OneNotePageListCommand extends GraphCommand {
+class OneNotePageListCommand extends GraphDelegatedCommand {
public get name(): string {
return commands.PAGE_LIST;
}
@@ -101,13 +102,13 @@ class OneNotePageListCommand extends GraphCommand {
endpoint += `users/${args.options.userId}`;
}
else if (args.options.userName) {
- endpoint += `users/${args.options.userName}`;
+ endpoint += `users/${formatting.encodeQueryParameter(args.options.userName)}`;
}
else if (args.options.groupId) {
endpoint += `groups/${args.options.groupId}`;
}
else if (args.options.groupName) {
- const groupId = await this.getGroupId(args.options.groupName);
+ const groupId = await entraGroup.getGroupIdByDisplayName(args.options.groupName);
endpoint += `groups/${groupId}`;
}
else if (args.options.webUrl) {
@@ -121,11 +122,6 @@ class OneNotePageListCommand extends GraphCommand {
return endpoint;
}
- private async getGroupId(groupName: string): Promise {
- const group = await entraGroup.getGroupByDisplayName(groupName);
- return group.id!;
- }
-
public async commandAction(logger: Logger, args: CommandArgs): Promise {
try {
const endpoint = await this.getEndpointUrl(args);