├── file.pdf ├── image.jpg ├── views ├── callback.jade ├── error.jade ├── result.jade ├── layout.jade └── index.jade ├── images ├── HostsFile.png └── OneNoteMSAScreen.png ├── public ├── images │ └── spinner.gif ├── stylesheets │ └── style.css └── javascripts │ └── index.js ├── config.js ├── bin └── www ├── package.json ├── app.js ├── routes ├── callback.js └── index.js ├── lib ├── liveconnect-client.js └── create-examples.js ├── doc ├── readme.html ├── post-html-sample.html ├── post-with-url-as-image.html ├── post-pdf-attachment.html ├── post-multi-part-with-image.html └── login-sample.html └── README.md /file.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OneNoteDev/OneNoteAPISampleNodejs/HEAD/file.pdf -------------------------------------------------------------------------------- /image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OneNoteDev/OneNoteAPISampleNodejs/HEAD/image.jpg -------------------------------------------------------------------------------- /views/callback.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | body 5 | script. 6 | window.close(); -------------------------------------------------------------------------------- /images/HostsFile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OneNoteDev/OneNoteAPISampleNodejs/HEAD/images/HostsFile.png -------------------------------------------------------------------------------- /images/OneNoteMSAScreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OneNoteDev/OneNoteAPISampleNodejs/HEAD/images/OneNoteMSAScreen.png -------------------------------------------------------------------------------- /public/images/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OneNoteDev/OneNoteAPISampleNodejs/HEAD/public/images/spinner.gif -------------------------------------------------------------------------------- /views/error.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.details} 7 | -------------------------------------------------------------------------------- /views/result.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | a(href='/') Go back 6 | br 7 | p 8 | a(href=resourceUrl, target='_onenote') Access submitted resource 9 | pre #{body} -------------------------------------------------------------------------------- /views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | script(src='//code.jquery.com/jquery-1.11.0.min.js') 7 | body 8 | block content -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | //Live Connect API information 3 | clientId: '000000004011C945', 4 | clientSecret: 'U5ofKaQiol75VbohV4hh-2x8XZpcJoPf ', 5 | redirectUrl: 'http://onenoteapisamples.com:3000/callback' 6 | }; -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | 10 | button { 11 | padding: 10px 20px; 12 | margin-bottom: 10px; 13 | } -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var debug = require('debug')('onenote-nodejs-sample'); 3 | var app = require('../app'); 4 | 5 | app.set('port', process.env.PORT || 3000); 6 | 7 | var server = app.listen(app.get('port'), function () { 8 | debug('Express server listening on port ' + server.address().port); 9 | }); 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "onenote-nodejs-sample", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "express": "~4.0.0", 10 | "body-parser": "~1.0.2", 11 | "cookie-parser": "~1.0.1", 12 | "debug": "~0.7.4", 13 | "jade": "~1.3.0", 14 | "request": "^2.34.0", 15 | "underscore": "^1.6.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | button(type="button", id="loginBtn") Sign In 6 | p OneNote Create Examples: 7 | form(id="createExamples" name="createExamples", method="post") 8 | button(type="submit", name="submit", value="text" disabled) Create OneNote Page with Text 9 | br 10 | button(type="submit", name="submit", value="textimage" disabled) Create OneNote Page with Text and Images 11 | br 12 | button(type="submit", name="submit", value="html" disabled) Create OneNote Page with a Screenshot of HTML 13 | br 14 | button(type="submit", name="submit", value="url" disabled) Create OneNote Page with a Screenshot of a URL 15 | br 16 | button(type="submit", name="submit", value="file" disabled) Create OneNote Page with an Embedded File 17 | br 18 | script. 19 | window.authUrl = '!{authUrl}'; 20 | script(src="/javascripts/index.js") -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var cookieParser = require('cookie-parser'); 4 | var bodyParser = require('body-parser'); 5 | 6 | var routes = require('./routes/index'); 7 | var callback = require('./routes/callback'); 8 | 9 | var app = express(); 10 | 11 | // view engine setup 12 | app.set('views', path.join(__dirname, 'views')); 13 | app.set('view engine', 'jade'); 14 | 15 | app.use(bodyParser()); 16 | app.use(cookieParser()); 17 | app.use(express.static(path.join(__dirname, 'public'))); 18 | 19 | app.use('/', routes); 20 | app.use('/callback', callback); 21 | 22 | // catch 404 and forwarding to error handler 23 | app.use(function (req, res, next) { 24 | var err = new Error('Not Found'); 25 | err.status = 404; 26 | next(err); 27 | }); 28 | 29 | /// error handler 30 | app.use(function (err, req, res, next) { 31 | res.status(err.status || 500); 32 | res.render('error', { 33 | message: err.message, 34 | error: { 35 | status: err.status, 36 | details: err.stack 37 | } 38 | }); 39 | }); 40 | 41 | module.exports = app; 42 | -------------------------------------------------------------------------------- /routes/callback.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | var liveConnect = require('../lib/liveconnect-client'); 5 | 6 | /* GET Live Connect Auth callback. */ 7 | router.get('/', function (req, res) { 8 | // Get the auth code from the callback url query parameters 9 | var authCode = req.query['code']; 10 | 11 | if (authCode) { 12 | // Request an access token from the auth code 13 | liveConnect.requestAccessTokenByAuthCode(authCode, 14 | function (responseData) { 15 | var accessToken = responseData['access_token'], 16 | refreshToken = responseData['refresh_token'], 17 | expiresIn = responseData['expires_in']; 18 | if (accessToken && refreshToken && expiresIn) { 19 | // Save the access token on a session. Using cookies in this case: 20 | res.cookie('access_token', accessToken, { maxAge: expiresIn * 1000}); 21 | res.cookie('refresh_token', refreshToken); 22 | 23 | res.render('callback'); 24 | } else { 25 | // Handle an authentication error response 26 | res.render('error', { 27 | message: 'Invalid Live Connect Response', 28 | error: {details: JSON.stringify(responseData, null, 2)} 29 | }); 30 | } 31 | }); 32 | } else { 33 | // Handle an error passed from the callback query params 34 | var authError = req.query['error'], 35 | authErrorDescription = req.query['error_description']; 36 | res.render('error', { 37 | message: 'Live Connect Auth Error', 38 | error: {status: authError, details: authErrorDescription} 39 | }); 40 | } 41 | 42 | }); 43 | 44 | module.exports = router; 45 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | var liveConnect = require('../lib/liveconnect-client'); 5 | var createExamples = require('../lib/create-examples'); 6 | 7 | /* GET Index page */ 8 | router.get('/', function (req, res) { 9 | var authUrl = liveConnect.getAuthUrl(); 10 | res.render('index', { title: 'OneNote API Node.js Sample', authUrl: authUrl}); 11 | }); 12 | 13 | /* POST Create example request */ 14 | router.post('/', function (req, res) { 15 | var accessToken = req.cookies['access_token']; 16 | var exampleType = req.body['submit']; 17 | 18 | // Render the API response with the created links or with error output 19 | var createResultCallback = function (error, httpResponse, body) { 20 | if (error) { 21 | return res.render('error', { 22 | message: 'HTTP Error', 23 | error: {details: JSON.stringify(error, null, 2)} 24 | }); 25 | } 26 | 27 | // Parse the body since it is a JSON response 28 | var parsedBody; 29 | try { 30 | parsedBody = JSON.parse(body); 31 | } catch (e) { 32 | parsedBody = {}; 33 | } 34 | // Get the submitted resource url from the JSON response 35 | var resourceUrl = parsedBody['links'] ? parsedBody['links']['oneNoteWebUrl']['href'] : null; 36 | 37 | if (resourceUrl) { 38 | res.render('result', { 39 | title: 'OneNote API Result', 40 | body: body, 41 | resourceUrl: resourceUrl 42 | }); 43 | } else { 44 | res.render('error', { 45 | message: 'OneNote API Error', 46 | error: {status: httpResponse.statusCode, details: body} 47 | }); 48 | } 49 | }; 50 | 51 | // Request the specified create example 52 | switch (exampleType) { 53 | case 'text': 54 | createExamples.createPageWithSimpleText(accessToken, createResultCallback); 55 | break; 56 | case 'textimage': 57 | createExamples.createPageWithTextAndImage(accessToken, createResultCallback); 58 | break; 59 | case 'html': 60 | createExamples.createPageWithScreenshotFromHtml(accessToken, createResultCallback); 61 | break; 62 | case 'url': 63 | createExamples.createPageWithScreenshotFromUrl(accessToken, createResultCallback); 64 | break; 65 | case 'file': 66 | createExamples.createPageWithFile(accessToken, createResultCallback); 67 | break; 68 | } 69 | }); 70 | 71 | module.exports = router; 72 | -------------------------------------------------------------------------------- /lib/liveconnect-client.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var _ = require('underscore'); 3 | 4 | var config = require('../config'); 5 | 6 | var LiveConnectClient = function () { 7 | var oauthAuthorizeUrl = 'https://login.live.com/oauth20_authorize.srf', 8 | oauthTokenUrl = 'https://login.live.com/oauth20_token.srf', 9 | clientId = config.clientId, 10 | clientSecret = config.clientSecret, 11 | redirectUrl = config.redirectUrl; 12 | 13 | // Helper function to create an encoded url query string from an object 14 | function toQueryString(obj) { 15 | var str = []; 16 | for (var p in obj) 17 | if (obj.hasOwnProperty(p)) { 18 | str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); 19 | } 20 | return str.join("&"); 21 | } 22 | 23 | /** 24 | * Obtain a Live Connect authorization endpoint URL based on configuration. 25 | * @returns {string} The authorization endpoint URL 26 | */ 27 | this.getAuthUrl = function () { 28 | var scopes = ['wl.signin', 'wl.basic', 'wl.offline_access', 'office.onenote_create']; 29 | var query = toQueryString({ 30 | 'client_id': clientId, 31 | 'scope': scopes.join(' '), 32 | 'redirect_uri': redirectUrl, 33 | 'display': 'page', 34 | 'locale': 'en', 35 | 'response_type': 'code' 36 | }); 37 | return oauthAuthorizeUrl + "?" + query; 38 | }; 39 | 40 | /* Live Connect API request sender */ 41 | function requestAccessToken(data, callback) { 42 | request.post({url: oauthTokenUrl, 43 | form: _.extend({ 44 | 'client_id': clientId, 45 | 'client_secret': clientSecret, 46 | 'redirect_uri': redirectUrl 47 | }, data)}, 48 | function (error, response, body) { 49 | if (error) { 50 | callback({}); 51 | } else { 52 | callback(JSON.parse(body)); 53 | } 54 | }); 55 | } 56 | 57 | /** 58 | * @callback accessTokenCallback 59 | * @param {object} Response data parsed from JSON API result 60 | */ 61 | 62 | /** 63 | * Request an access token by supplying an authorization code. 64 | * @param {string} authCode The authorization code 65 | * @param {accessTokenCallback} callback The callback with response data 66 | */ 67 | this.requestAccessTokenByAuthCode = function (authCode, callback) { 68 | requestAccessToken({'code': authCode, 'grant_type': 'authorization_code'}, callback); 69 | }; 70 | 71 | /** 72 | * Request an access token by supplying a refresh token. 73 | * @param {string} refreshToken The refresh token 74 | * @param {accessTokenCallback} callback The callback with response data 75 | */ 76 | this.requestAccessTokenByRefreshToken = function(refreshToken, callback) { 77 | requestAccessToken({'refresh_token': refreshToken, 'grant_type': 'refresh_token'}, callback); 78 | }; 79 | 80 | 81 | 82 | }; 83 | module.exports = new LiveConnectClient(); -------------------------------------------------------------------------------- /doc/readme.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |Created by Microsoft Corporation, 2014. Provided As-is without warranty. Trademarks mentioned here are the property of their owners.
11 |The following aspects of the API are covered in this sample. You can find additional documentation at the links below.
13 |Tools and Libraries you will need to download, install, and configure for your development environment.
24 | 32 | 33 |Accounts
34 | 35 |After you've setup your development tools, and checked the prerequisites listed above,....
42 | 43 |npm installnpm start
');
11 | window.setTimeout(function(){disableCreateButtons(true);},0);
12 | });
13 | });
14 | });
15 |
16 | function openPopUp(url) {
17 | var width = 525,
18 | height = 630,
19 | screenTop = !!window.screenTop ? window.screenTop : window.screenY,
20 | screenLeft = !!window.screenLeft ? window.screenLeft : window.screenX,
21 | top = Math.floor(screenTop + ($(window).height() - height) / 2),
22 | left = Math.floor(screenLeft + ($(window).width() - width) / 2);
23 |
24 | var features = [
25 | "width=" + width,
26 | "height=" + height,
27 | "top=" + top,
28 | "left=" + left,
29 | "status=no",
30 | "resizable=yes",
31 | "toolbar=no",
32 | "menubar=no",
33 | "scrollbars=yes"];
34 |
35 | var popup = window.open(url, "oauth", features.join(","));
36 | popup.focus();
37 |
38 | return popup;
39 | }
40 |
41 | function showLogin() {
42 | openPopUp(window.authUrl);
43 | }
44 |
45 | function getCookie(name) {
46 | var cookies = document.cookie;
47 | name += "=";
48 | var start = cookies.indexOf(name);
49 | if (start >= 0) {
50 | start += name.length;
51 |
52 | var end = cookies.indexOf(';', start);
53 | if (end < 0) {
54 | end = cookies.length;
55 | }
56 | return cookies.substring(start, end);
57 | }
58 | return null;
59 | }
60 |
61 | function deleteAllCookies() {
62 | var cookies = document.cookie.split(";");
63 | for (var i = 0; i < cookies.length; i++) {
64 | var cookie = cookies[i];
65 | var eqPos = cookie.indexOf("=");
66 | var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
67 | document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
68 | }
69 | }
70 |
71 | function disableCreateButtons(disabled) {
72 | $('#createExamples').find('button').each(function () {
73 | $(this).attr('disabled', disabled);
74 | });
75 | }
76 |
77 | function disableLoginButton(disabled) {
78 | $loginBtn.attr('disabled', disabled);
79 | }
80 |
81 | function updateLoginButton(isLoggedIn) {
82 | $loginBtn.text(isLoggedIn ? 'Sign Out' : 'Sign In');
83 | $loginBtn.off('click');
84 | $loginBtn.on('click', function () {
85 | disableLoginButton(true);
86 | if (isLoggedIn) {
87 | deleteAllCookies();
88 | } else {
89 | showLogin();
90 | }
91 | });
92 | disableCreateButtons(!isLoggedIn);
93 | }
94 |
95 | function checkLogin() {
96 | if (getCookie("access_token")) {
97 | if (!isLoggedIn) {
98 | disableLoginButton(false);
99 | isLoggedIn = true;
100 | updateLoginButton(isLoggedIn);
101 | }
102 | } else {
103 | if (isLoggedIn) {
104 | disableLoginButton(false);
105 | isLoggedIn = false;
106 | updateLoginButton(isLoggedIn);
107 | }
108 | }
109 | }
110 |
111 | window.setInterval(checkLogin, 1000);
112 |
--------------------------------------------------------------------------------
/doc/post-html-sample.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | This snippet creates a basic OneNote page from HTML by placing the HTML directly in the HTTPS request body. 13 | It doesn't use the multi-part format. The snippet also adds the Content-Type and Authentication headers to the POST request.
14 | 15 |
27 | /**
28 | * Create OneNote Page with Text
29 | *
30 | * @param {string} accessToken The access token
31 | * @param {createPageCallback} callback The callback with response data
32 | */
33 | this.createPageWithSimpleText = function (accessToken, callback) {
34 | var htmlPayload =
35 | "<!DOCTYPE html>" +
36 | "<html>" +
37 | "<head>" +
38 | " <title>A page created from basic HTML-formatted text (Node.js Sample)</title>" +
39 | " <meta name=\"created\" value=\"" + dateTimeNowISO() + "\">" +
40 | "</head>" +
41 | "<body>" +
42 | " <p>This is a page that just contains some simple <i>formatted</i>" +
43 | " <b>text</b></p>" +
44 | "</body>" +
45 | "</html>";
46 |
47 | createPage(accessToken, htmlPayload, callback, false);
48 | };
49 | /**
50 | * @callback createPageCallback
51 | * @param {object} Error
52 | * @param {object} HTTP Response
53 | * @param {string} Response body
54 | */
55 |
56 | var oneNotePagesApiUrl = 'https://www.onenote.com/api/v1.0/pages';
57 |
58 | /* Pages API request builder & sender */
59 | function createPage(accessToken, payload, callback, multipart) {
60 | var options = {
61 | url: oneNotePagesApiUrl,
62 | headers: {'Authorization': 'Bearer ' + accessToken}
63 | };
64 | // Build simple request
65 | if (!multipart) {
66 | options.headers['Content-Type'] = 'text/html';
67 | options.body = payload;
68 | }
69 | var r = request.post(options, callback);
70 | // Build multi-part request
71 | if (multipart) {
72 | var CRLF = '\r\n';
73 | var form = r.form(); // FormData instance
74 | _.each(payload, function (partData, partId) {
75 | form.append(partId, partData.body, {
76 | // Use custom multi-part header
77 | header: CRLF +
78 | '--' + form.getBoundary() + CRLF +
79 | 'Content-Disposition: form-data; name=\"' + partId + '\"' + CRLF +
80 | 'Content-Type: ' + partData.contentType + CRLF + CRLF
81 | });
82 | });
83 | }
84 | }
85 |
86 | function dateTimeNowISO() {
87 | return new Date().toISOString();
88 | }
89 |
90 | The following code snippet builds a simple multi-part POST request with some HTML in a "Presentation" block. 13 | In that HTML is an <img> tag that shows how to specify an internet URL to the page rendering engine.
14 | 15 |
26 | /**
27 | * Create OneNote Page with a Screenshot of a URL
28 | *
29 | * @param {string} accessToken The access token
30 | * @param {createPageCallback} callback The callback with response data
31 | */
32 | this.createPageWithScreenshotFromUrl = function (accessToken, callback) {
33 | var htmlPayload =
34 | "<!DOCTYPE html>" +
35 | "<html>" +
36 | "<head>" +
37 | " <title>A page created with a URL snapshot on it (Node.js Sample)</title>" +
38 | " <meta name=\"created\" value=\"" + dateTimeNowISO() + "\"/>" +
39 | "</head>" +
40 | "<body>" +
41 | " <img data-render-src=\"http://www.onenote.com\" alt=\"An important web page\" />" +
42 | " Source URL: <a href=\"http://www.onenote.com\">http://www.onenote.com</a>" +
43 | "</body>" +
44 | "</html>";
45 |
46 | createPage(accessToken, htmlPayload, callback, false);
47 | };
48 | /**
49 | * @callback createPageCallback
50 | * @param {object} Error
51 | * @param {object} HTTP Response
52 | * @param {string} Response body
53 | */
54 |
55 | var oneNotePagesApiUrl = 'https://www.onenote.com/api/v1.0/pages';
56 |
57 | /* Pages API request builder & sender */
58 | function createPage(accessToken, payload, callback, multipart) {
59 | var options = {
60 | url: oneNotePagesApiUrl,
61 | headers: {'Authorization': 'Bearer ' + accessToken}
62 | };
63 | // Build simple request
64 | if (!multipart) {
65 | options.headers['Content-Type'] = 'text/html';
66 | options.body = payload;
67 | }
68 | var r = request.post(options, callback);
69 | // Build multi-part request
70 | if (multipart) {
71 | var CRLF = '\r\n';
72 | var form = r.form(); // FormData instance
73 | _.each(payload, function (partData, partId) {
74 | form.append(partId, partData.body, {
75 | // Use custom multi-part header
76 | header: CRLF +
77 | '--' + form.getBoundary() + CRLF +
78 | 'Content-Disposition: form-data; name=\"' + partId + '\"' + CRLF +
79 | 'Content-Type: ' + partData.contentType + CRLF + CRLF
80 | });
81 | });
82 | }
83 | }
84 |
85 | function dateTimeNowISO() {
86 | return new Date().toISOString();
87 | }
88 |
89 | The following snippet builds a multi-part request that contains a "Presentation" part with HTML, 13 | and a second part with binary data, that will be inserted into the page as an embedded file. 14 | In this example, a PDF document is compiled into the app, but the technique is the same for other files.
15 | 16 |
28 | /**
29 | * Create OneNote Page with an Embedded File
30 | *
31 | * @param {string} accessToken The access token
32 | * @param {createPageCallback} callback The callback with response data
33 | */
34 | this.createPageWithFile = function (accessToken, callback) {
35 | var htmlPayload =
36 | "<!DOCTYPE html>" +
37 | "<html>" +
38 | "<head>" +
39 | " <title>A page with a file on it (Node.js Sample)</title>" +
40 | " <meta name=\"created\" value=\"" + dateTimeNowISO() + "\"/>" +
41 | "</head>" +
42 | "<body>" +
43 | " <object data-attachment=\"PDF File.pdf\" data=\"name:EmbeddedFile\" type=\"application/pdf\"></object>" +
44 | " <img data-render-src=\"name:EmbeddedFile\" />" +
45 | "</body>" +
46 | "</html>";
47 |
48 | createPage(accessToken, {
49 | 'Presentation': {
50 | body: htmlPayload,
51 | contentType: 'text/html'
52 | },
53 | 'EmbeddedFile': {
54 | body: fs.readFileSync(path.normalize(__dirname + '/../file.pdf')),
55 | contentType: 'application/pdf'
56 | }
57 | }, callback, true);
58 | }
59 | /**
60 | * @callback createPageCallback
61 | * @param {object} Error
62 | * @param {object} HTTP Response
63 | * @param {string} Response body
64 | */
65 |
66 | var oneNotePagesApiUrl = 'https://www.onenote.com/api/v1.0/pages';
67 |
68 | /* Pages API request builder & sender */
69 | function createPage(accessToken, payload, callback, multipart) {
70 | var options = {
71 | url: oneNotePagesApiUrl,
72 | headers: {'Authorization': 'Bearer ' + accessToken}
73 | };
74 | // Build simple request
75 | if (!multipart) {
76 | options.headers['Content-Type'] = 'text/html';
77 | options.body = payload;
78 | }
79 | var r = request.post(options, callback);
80 | // Build multi-part request
81 | if (multipart) {
82 | var CRLF = '\r\n';
83 | var form = r.form(); // FormData instance
84 | _.each(payload, function (partData, partId) {
85 | form.append(partId, partData.body, {
86 | // Use custom multi-part header
87 | header: CRLF +
88 | '--' + form.getBoundary() + CRLF +
89 | 'Content-Disposition: form-data; name=\"' + partId + '\"' + CRLF +
90 | 'Content-Type: ' + partData.contentType + CRLF + CRLF
91 | });
92 | });
93 | }
94 | }
95 |
96 | function dateTimeNowISO() {
97 | return new Date().toISOString();
98 | }
99 |
100 | The following snippet builds a multi-part request that contains a "Presentation" part with HTML, 13 | and a second part with binary image data. 14 | In this example, a logo image is compiled into the app, but the technique is the same for other images.
15 | 16 |
28 | /**
29 | * Create OneNote Page with Text and Images
30 | *
31 | * @param {string} accessToken The access token
32 | * @param {createPageCallback} callback The callback with response data
33 | */
34 | this.createPageWithTextAndImage = function (accessToken, callback) {
35 | var htmlPayload =
36 | "<!DOCTYPE html>" +
37 | "<html>" +
38 | "<head>" +
39 | " <title>A page created containing an image (Node.js Sample)</title>" +
40 | " <meta name=\"created\" value=\"" + dateTimeNowISO() + "\">" +
41 | "</head>" +
42 | "<body>" +
43 | " <p>This is a page that just contains some simple <i>formatted</i>" +
44 | " <b>text</b> and an image</p>" +
45 | " <img src=\"name:ImageData\" width=\"426\" height=\"68\">" +
46 | "</body>" +
47 | "</html>";
48 |
49 | createPage(accessToken, {
50 | 'Presentation': {
51 | body: htmlPayload,
52 | contentType: 'text/html'
53 | },
54 | 'ImageData': {
55 | body: fs.readFileSync(path.normalize(__dirname + '/../image.jpg')),
56 | contentType: 'image/jpeg'
57 | }
58 | }, callback, true);
59 | };
60 | /**
61 | * @callback createPageCallback
62 | * @param {object} Error
63 | * @param {object} HTTP Response
64 | * @param {string} Response body
65 | */
66 |
67 | var oneNotePagesApiUrl = 'https://www.onenote.com/api/v1.0/pages';
68 |
69 | /* Pages API request builder & sender */
70 | function createPage(accessToken, payload, callback, multipart) {
71 | var options = {
72 | url: oneNotePagesApiUrl,
73 | headers: {'Authorization': 'Bearer ' + accessToken}
74 | };
75 | // Build simple request
76 | if (!multipart) {
77 | options.headers['Content-Type'] = 'text/html';
78 | options.body = payload;
79 | }
80 | var r = request.post(options, callback);
81 | // Build multi-part request
82 | if (multipart) {
83 | var CRLF = '\r\n';
84 | var form = r.form(); // FormData instance
85 | _.each(payload, function (partData, partId) {
86 | form.append(partId, partData.body, {
87 | // Use custom multi-part header
88 | header: CRLF +
89 | '--' + form.getBoundary() + CRLF +
90 | 'Content-Disposition: form-data; name=\"' + partId + '\"' + CRLF +
91 | 'Content-Type: ' + partData.contentType + CRLF + CRLF
92 | });
93 | });
94 | }
95 | }
96 |
97 | function dateTimeNowISO() {
98 | return new Date().toISOString();
99 | }
100 |
101 | One of the ways to sign a user in with Node.js is to have a route handle the Live Connect Authentication callback. 11 | The route controller would take the authorization code supplied by the callback and request an access token with a REST client. 12 | The access token is sent back to the client in a cookie. 13 |
14 | 15 |The REST client:
16 |
27 | var oauthAuthorizeUrl = 'https://login.live.com/oauth20_authorize.srf',
28 | oauthTokenUrl = 'https://login.live.com/oauth20_token.srf',
29 | clientId = config.clientId,
30 | clientSecret = config.clientSecret,
31 | redirectUrl = config.redirectUrl;
32 |
33 | // Helper function to create an encoded url query string from an object
34 | function toQueryString(obj) {
35 | var str = [];
36 | for (var p in obj)
37 | if (obj.hasOwnProperty(p)) {
38 | str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
39 | }
40 | return str.join("&");
41 | }
42 |
43 | /**
44 | * Obtain a Live Connect authorization endpoint URL based on configuration.
45 | * @returns {string} The authorization endpoint URL
46 | */
47 | this.getAuthUrl = function () {
48 | var scopes = ['wl.signin', 'wl.basic', 'wl.offline_access', 'office.onenote_create'];
49 | var query = toQueryString({
50 | 'client_id': clientId,
51 | 'scope': scopes.join(' '),
52 | 'redirect_uri': redirectUrl,
53 | 'display': 'page',
54 | 'locale': 'en',
55 | 'response_type': 'code'
56 | });
57 | return oauthAuthorizeUrl + "?" + query;
58 | };
59 |
60 | /* Live Connect API request sender */
61 | function requestAccessToken(data, callback) {
62 | request.post({url: oauthTokenUrl,
63 | form: _.extend({
64 | 'client_id': clientId,
65 | 'client_secret': clientSecret,
66 | 'redirect_uri': redirectUrl
67 | }, data)},
68 | function (error, response, body) {
69 | if (error) {
70 | callback({});
71 | } else {
72 | callback(JSON.parse(body));
73 | }
74 | });
75 | }
76 |
77 | /**
78 | * @callback accessTokenCallback
79 | * @param {object} Response data parsed from JSON API result
80 | */
81 |
82 | /**
83 | * Request an access token by supplying an authorization code.
84 | * @param {string} authCode The authorization code
85 | * @param {accessTokenCallback} callback The callback with response data
86 | */
87 | this.requestAccessTokenByAuthCode = function (authCode, callback) {
88 | requestAccessToken({'code': authCode, 'grant_type': 'authorization_code'}, callback);
89 | };
90 |
91 | /**
92 | * Request an access token by supplying a refresh token.
93 | * @param {string} refreshToken The refresh token
94 | * @param {accessTokenCallback} callback The callback with response data
95 | */
96 | this.requestAccessTokenByRefreshToken = function(refreshToken, callback) {
97 | requestAccessToken({'refresh_token': refreshToken, 'grant_type': 'refresh_token'}, callback);
98 | };
99 |
100 | The callback route controller:
106 | (The liveConnect variable is an instance of the REST client snippet above)
118 | /* GET Live Connect Auth callback. */
119 | router.get('/', function (req, res) {
120 | // Get the auth code from the callback url query parameters
121 | var authCode = req.query['code'];
122 |
123 | if (authCode) {
124 | // Request an access token from the auth code
125 | liveConnect.requestAccessTokenByAuthCode(authCode,
126 | function (responseData) {
127 | var accessToken = responseData['access_token'],
128 | refreshToken = responseData['refresh_token'],
129 | expiresIn = responseData['expires_in'];
130 | if (accessToken && refreshToken && expiresIn) {
131 | // Save the access token on a session. Using cookies in this case:
132 | res.cookie('access_token', accessToken, { maxAge: expiresIn * 1000});
133 | res.cookie('refresh_token', refreshToken);
134 |
135 | res.render('callback');
136 | } else {
137 | // Handle an authentication error response
138 | res.render('error', {
139 | message: 'Invalid Live Connect Response',
140 | error: {details: JSON.stringify(responseData, null, 2)}
141 | });
142 | }
143 | });
144 | } else {
145 | // Handle an error passed from the callback query params
146 | var authError = req.query['error'],
147 | authErrorDescription = req.query['error_description'];
148 | res.render('error', {
149 | message: 'Live Connect Auth Error',
150 | error: {status: authError, details: authErrorDescription}
151 | });
152 | }
153 |
154 | });
155 |
156 | This is a page that just contains some simple formatted" + 64 | " text
" + 65 | "" + 66 | ""; 67 | 68 | createPage(accessToken, htmlPayload, callback, false); 69 | }; 70 | 71 | /** 72 | * Create OneNote Page with Text and Images 73 | * 74 | * @param {string} accessToken The access token 75 | * @param {createPageCallback} callback The callback with response data 76 | */ 77 | this.createPageWithTextAndImage = function (accessToken, callback) { 78 | var htmlPayload = 79 | "" + 80 | "" + 81 | "" + 82 | "This is a page that just contains some simple formatted" + 87 | " text and an image
" + 88 | "" + 131 | " Lorem ipsum dolor sit amet, consectetur adipiscing elit." + 132 | " Nullam vehicula magna quis mauris accumsan, nec imperdiet nisi tempus. " + 133 | " Suspendisse potenti. Duis vel nulla sit amet turpis venenatis elementum. " + 134 | " Cras laoreet quis nisi et sagittis. Donec euismod at tortor ut porta. " + 135 | " Duis libero urna, viverra idaliquam in, ornare sed orci. " + 136 | " Pellentesque condimentum gravida felis, sed pulvinar erat suscipit sit amet. Nulla id felis quis " + 137 | " sem blandit dapibus. " + 138 | " Utviverra auctor nisi ac egestas. " + 139 | " Quisque ac neque nec velit fringilla sagittis porttitor sit amet quam." + 140 | "
" + 141 | "" + 142 | ""; 143 | 144 | createPage(accessToken, { 145 | 'Presentation': { 146 | body: htmlPayload, 147 | contentType: 'text/html' 148 | }, 149 | 'HtmlForScreenshot': { 150 | body: htmlForScreenshot, 151 | contentType: 'text/html' 152 | } 153 | }, callback, true); 154 | }; 155 | 156 | /** 157 | * Create OneNote Page with a Screenshot of a URL 158 | * 159 | * @param {string} accessToken The access token 160 | * @param {createPageCallback} callback The callback with response data 161 | */ 162 | this.createPageWithScreenshotFromUrl = function (accessToken, callback) { 163 | var htmlPayload = 164 | "" + 165 | "" + 166 | "" + 167 | "