From d11752e195c2ab08f4e2770f079b2817a559c742 Mon Sep 17 00:00:00 2001 From: Devin Binnie <52460000+devinbinnie@users.noreply.github.com> Date: Thu, 6 Jun 2024 14:04:49 -0400 Subject: [PATCH] [MM-58455] Add error handling when FocusStatus is not authorized on macOS (#3053) * [MM-58455] Add error handling when FocusStatus is not authorized on macOS * Do the permission check very early so that it's less likely for users to miss it * Move permissions check to initialize --- src/main/app/initialize.test.js | 1 + src/main/app/initialize.ts | 4 +++ src/main/notifications/index.test.ts | 39 ++++++++++++++++++++++++---- src/main/notifications/index.ts | 10 +++++-- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/main/app/initialize.test.js b/src/main/app/initialize.test.js index ce0bdc74..f8ff46c6 100644 --- a/src/main/app/initialize.test.js +++ b/src/main/app/initialize.test.js @@ -143,6 +143,7 @@ jest.mock('main/CriticalErrorHandler', () => ({ })); jest.mock('main/notifications', () => ({ displayDownloadCompleted: jest.fn(), + getDoNotDisturb: jest.fn(), })); jest.mock('main/ParseArgs', () => jest.fn()); jest.mock('common/servers/serverManager', () => ({ diff --git a/src/main/app/initialize.ts b/src/main/app/initialize.ts index ba35243b..a3fb9740 100644 --- a/src/main/app/initialize.ts +++ b/src/main/app/initialize.ts @@ -47,6 +47,7 @@ import {configPath, updatePaths} from 'main/constants'; import CriticalErrorHandler from 'main/CriticalErrorHandler'; import downloadsManager from 'main/downloadsManager'; import i18nManager from 'main/i18nManager'; +import {getDoNotDisturb} from 'main/notifications'; import parseArgs from 'main/ParseArgs'; import PermissionsManager from 'main/permissionsManager'; import Tray from 'main/tray/tray'; @@ -374,6 +375,9 @@ async function initializeAfterAppReady() { } } + // Call this to initiate a permissions check for DND state + getDoNotDisturb(); + // listen for status updates and pass on to renderer UserActivityMonitor.on('status', (status) => { log.debug('UserActivityMonitor.on(status)', status); diff --git a/src/main/notifications/index.test.ts b/src/main/notifications/index.test.ts index 93ecb71c..e18d231d 100644 --- a/src/main/notifications/index.test.ts +++ b/src/main/notifications/index.test.ts @@ -35,7 +35,7 @@ const mentions: Array<{body: string; value: any}> = []; jest.mock('child_process', () => ({ execSync: jest.fn(), })); - +jest.mock('electron-is-dev', () => false); jest.mock('electron', () => { class NotificationMock { callbackMap: Map void>; @@ -137,6 +137,7 @@ describe('main/notifications', () => { afterEach(() => { jest.resetAllMocks(); + mentions.length = 0; Config.notifications = { flashWindow: 0, bounceIcon: false, @@ -156,7 +157,7 @@ describe('main/notifications', () => { {id: 1} as WebContents, '', ); - expect(MainWindow.show).not.toBeCalled(); + expect(mentions.length).toBe(0); }); it('should do nothing when alarms only is enabled on windows', async () => { @@ -176,7 +177,7 @@ describe('main/notifications', () => { {id: 1} as WebContents, '', ); - expect(MainWindow.show).not.toBeCalled(); + expect(mentions.length).toBe(0); Object.defineProperty(process, 'platform', { value: originalPlatform, @@ -200,7 +201,35 @@ describe('main/notifications', () => { {id: 1} as WebContents, '', ); - expect(MainWindow.show).not.toBeCalled(); + expect(mentions.length).toBe(0); + + Object.defineProperty(process, 'platform', { + value: originalPlatform, + }); + }); + + it('should still show notification when dnd permission on mac is not authorized', async () => { + const originalPlatform = process.platform; + Object.defineProperty(process, 'platform', { + value: 'darwin', + }); + + getDarwinDoNotDisturb.mockImplementation(() => { + throw new Error('Unauthorized'); + }); + await NotificationManager.displayMention( + 'test', + 'test body', + 'channel_id', + 'team_id', + 'http://server-1.com/team_id/channel_id', + false, + {id: 1} as WebContents, + '', + ); + expect(mentions.length).toBe(1); + const mention = mentions[0]; + expect(mention.value.show).toHaveBeenCalled(); Object.defineProperty(process, 'platform', { value: originalPlatform, @@ -219,7 +248,7 @@ describe('main/notifications', () => { {id: 1} as WebContents, '', ); - expect(MainWindow.show).not.toBeCalled(); + expect(mentions.length).toBe(0); }); it('should play notification sound when custom sound is provided', async () => { diff --git a/src/main/notifications/index.ts b/src/main/notifications/index.ts index 7e55c7d4..4c042f24 100644 --- a/src/main/notifications/index.ts +++ b/src/main/notifications/index.ts @@ -197,14 +197,20 @@ class NotificationManager { } } -async function getDoNotDisturb() { +export async function getDoNotDisturb() { if (process.platform === 'win32') { return getWindowsDoNotDisturb(); } // We have to turn this off for dev mode because the Electron binary doesn't have the focus center API entitlement if (process.platform === 'darwin' && !isDev) { - return getDarwinDoNotDisturb(); + try { + const dnd = await getDarwinDoNotDisturb(); + return dnd; + } catch (e) { + log.warn('macOS DND check threw an error', e); + return false; + } } if (process.platform === 'linux') {