Skip to content

Commit

Permalink
feat: support for custom sharepoint domain
Browse files Browse the repository at this point in the history
Fixes #548
  • Loading branch information
rofe authored Oct 6, 2023
1 parent 55b807d commit 1db320b
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/extension/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ function checkTab(id) {
log.debug('local dev url detected, retrieve proxy url');
checkUrl = await getProxyUrl(tab);
}
await populateUrlCache(checkUrl);
await populateUrlCache(checkUrl, projects);
if (tab.active) {
await checkContextMenu(tab, projects);
}
Expand Down
38 changes: 23 additions & 15 deletions src/extension/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -433,33 +433,39 @@
/**
* Recognizes a SharePoint URL.
* @private
* @param {Sidekick} sk The sidekick
* @param {URL} url The URL
* @returns {boolean} {@code true} if URL is SharePoint, else {@code false}
*/
function isSharePoint(url) {
return /\w+\.sharepoint.com$/.test(url.host);
function isSharePoint(sk, url) {
const { host } = url;
const { config: { mountpoint } } = sk;
return /\w+\.sharepoint.com$/.test(host)
|| (!host.endsWith('.google.com') && mountpoint && new URL(mountpoint).host === host);
}

/**
* Recognizes a SharePoint document management URL.
* @private
* @param {Sidekick} sk The sidekick
* @param {URL} url The URL
* @returns {boolean} {@code true} if URL is SharePoint DM, else {@code false}
*/
function isSharePointDM(url) {
return isSharePoint(url)
function isSharePointDM(sk, url) {
return isSharePoint(sk, url)
&& (url.pathname.endsWith('/Forms/AllItems.aspx')
|| url.pathname.endsWith('/onedrive.aspx'));
}

/**
* Recognizes a SharePoint folder URL.
* @private
* @param {Sidekick} sk The sidekick
* @param {URL} url The URL
* @returns {boolean} {@code true} if URL is SharePoint folder, else {@code false}
*/
function isSharePointFolder(url) {
if (isSharePointDM(url)) {
function isSharePointFolder(sk, url) {
if (isSharePointDM(sk, url)) {
const docPath = new URLSearchParams(url.search).get('id');
const dotIndex = docPath?.split('/').pop().indexOf('.');
return [-1, 0].includes(dotIndex); // dot only allowed as first char
Expand All @@ -470,24 +476,26 @@
/**
* Recognizes a SharePoint editor URL.
* @private
* @param {Sidekick} sk The sidekick
* @param {URL} url The URL
* @returns {boolean} {@code true} if URL is SharePoint editor, else {@code false}
*/
function isSharePointEditor(url) {
function isSharePointEditor(sk, url) {
const { pathname, search } = url;
return isSharePoint(url)
return isSharePoint(sk, url)
&& pathname.match(/\/_layouts\/15\/[\w]+.aspx$/)
&& search.includes('sourcedoc=');
}

/**
* Recognizes a SharePoint viewer URL.
* @private
* @param {Sidekick} sk The sidekick
* @param {URL} url The URL
* @returns {boolean} {@code true} if URL is SharePoint viewer, else {@code false}
*/
function isSharePointViewer(url) {
if (isSharePointDM(url)) {
function isSharePointViewer(sk, url) {
if (isSharePointDM(sk, url)) {
const docPath = new URLSearchParams(url.search).get('id');
const dotIndex = docPath?.split('/').pop().lastIndexOf('.');
return dotIndex > 0; // must contain a dot
Expand Down Expand Up @@ -1559,7 +1567,7 @@
const { path, type } = item;
const nameParts = path.split('.');
let [file, ext] = nameParts;
if (isSharePointFolder(sk.location) && ext === 'docx') {
if (isSharePointFolder(sk, sk.location) && ext === 'docx') {
// omit docx extension on sharepoint
ext = '';
}
Expand All @@ -1582,7 +1590,7 @@

const getBulkSelection = () => {
const { location } = sk;
if (isSharePointFolder(location)) {
if (isSharePointFolder(sk, location)) {
const isGrid = document.querySelector('div[class~="ms-TilesList"]');
return [...document.querySelectorAll('#appRoot [role="presentation"] div[aria-selected="true"]')]
.filter((row) => !row.querySelector('img')?.getAttribute('src').includes('/foldericons/')
Expand Down Expand Up @@ -1773,7 +1781,7 @@
callback: (sidekick) => {
const { location } = sk;
const listener = () => window.setTimeout(() => updateBulkInfo(sidekick), 100);
const rootEl = document.querySelector(isSharePointFolder(location) ? '#appRoot' : 'body');
const rootEl = document.querySelector(isSharePointFolder(sk, location) ? '#appRoot' : 'body');
if (rootEl) {
rootEl.addEventListener('click', listener);
rootEl.addEventListener('keyup', listener);
Expand Down Expand Up @@ -3166,7 +3174,7 @@
isEditor() {
const { config, location } = this;
const { host } = location;
if (isSharePointEditor(location) || isSharePointViewer(location)) {
if (isSharePointEditor(this, location) || isSharePointViewer(this, location)) {
return true;
}
if (host === 'docs.google.com') {
Expand All @@ -3184,7 +3192,7 @@
*/
isAdmin() {
const { location } = this;
return isSharePointFolder(location) || location.host === 'drive.google.com';
return isSharePointFolder(this, location) || location.host === 'drive.google.com';
}

/**
Expand Down
21 changes: 14 additions & 7 deletions src/extension/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,19 +227,24 @@ async function fetchGoogleDriveEditInfo(tabUrl) {
/**
* Determines if a URL has a Microsoft SharePoint host.
* @param {string} tabUrl The tab URL
* @param {Object[]} projects The project configurations
* @returns {boolean} {@code true} if SharePoint host, else {@code false}
*/
function isSharePointHost(tabUrl) {
export function isSharePointHost(tabUrl, projects = []) {
const { host } = new URL(tabUrl);
return /^[a-z-]+\.sharepoint\.com$/.test(host);
return /^[a-z-]+\.sharepoint\.com$/.test(host)
|| !!projects.find((p) => {
const mp = p.mountpoints && p.mountpoints[0];
return !host.endsWith('.google.com') && mp && new URL(mp).host === host;
});
}

/**
* Determines if a URL has a Google Drive host.
* @param {string} tabUrl The tab URL
* @returns {boolean} {@code true} if Google Drive host, else {@code false}
*/
function isGoogleDriveHost(tabUrl) {
export function isGoogleDriveHost(tabUrl) {
const { host } = new URL(tabUrl);
return /^(docs|drive)\.google\.com$/.test(host);
}
Expand All @@ -265,12 +270,13 @@ export async function queryUrlCache(tabUrl) {
* Microsoft SharePoint or Google Drive URLs will be looked up in the Franklin Admin Service
* and expire after 2 hours.
* @param {string} tabUrl The tab URL
* @param {Object} config={} The project config (optional)
* @param {Object|Object[]} config={} The project config(s) (optional)
* @param {string} config.owner The owner
* @param {string} config.repo The repository
* @returns {Promise<void>}
*/
export async function populateUrlCache(tabUrl, { owner, repo } = {}) {
export async function populateUrlCache(tabUrl, config = {}) {
const { owner, repo } = typeof config === 'object' && !Array.isArray(config) ? config : {};
const createCacheEntry = (cacheUrl, results = [], expiry = false) => {
const entry = { url: cacheUrl, results };
if (expiry) {
Expand Down Expand Up @@ -300,12 +306,13 @@ export async function populateUrlCache(tabUrl, { owner, repo } = {}) {
urlCache.push(entry);
}
} else {
const isSPHost = isSharePointHost(tabUrl, Array.isArray(config) ? config : [config]);
// lookup (for sharepoint and google drive only)
if (!isSharePointHost(tabUrl) && !isGoogleDriveHost(tabUrl)) {
if (!isSPHost && !isGoogleDriveHost(tabUrl)) {
return;
}
if ((await queryUrlCache(tabUrl)).length === 0) {
const info = isSharePointHost(tabUrl)
const info = isSPHost
? await fetchSharePointEditInfo(tabUrl)
: await fetchGoogleDriveEditInfo(tabUrl);
log.debug('resource edit info', info);
Expand Down
10 changes: 10 additions & 0 deletions test/extension/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,4 +366,14 @@ describe('Test extension utils', () => {
})).to.be.true;
expect(display).to.be.false;
});

it('isSharePointHost', async () => {
expect(utils.isSharePointHost('https://foo.sharepoint.com/sites/foo/Shared%20Documents/root1')).to.be.true;
expect(utils.isSharePointHost('https://foo.custom/sites/foo/Shared%20Documents/root1', CONFIGS)).to.be.true;
});

it('isGoogleDriveHost', async () => {
expect(utils.isGoogleDriveHost('https://drive.google.com/drive/folders/1234567890')).to.be.true;
expect(utils.isGoogleDriveHost('https://docs.google.com/document/d/1234567890/edit')).to.be.true;
});
});

0 comments on commit 1db320b

Please sign in to comment.