Skip to content

Commit d75fb82

Browse files
setchyafonsojramos
andauthored
feat(accounts): enhance auth account data structure (#1139)
Co-authored-by: Afonso Jorge Ramos <afonsojorgeramos@gmail.com>
1 parent f2daee4 commit d75fb82

36 files changed

+844
-950
lines changed

src/__mocks__/notifications-mocks.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,26 @@ import type { AccountNotifications } from '../types';
22
import {
33
mockEnterpriseNotifications,
44
mockGitHubNotifications,
5-
mockSingleNotification,
65
} from '../utils/api/__mocks__/response-mocks';
6+
import {
7+
mockGitHubCloudAccount,
8+
mockGitHubEnterpriseServerAccount,
9+
} from './state-mocks';
710

811
export const mockAccountNotifications: AccountNotifications[] = [
912
{
10-
hostname: 'github.com',
13+
account: mockGitHubCloudAccount,
1114
notifications: mockGitHubNotifications,
1215
},
1316
{
14-
hostname: 'github.gitify.io',
17+
account: mockGitHubEnterpriseServerAccount,
1518
notifications: mockEnterpriseNotifications,
1619
},
1720
];
1821

1922
export const mockSingleAccountNotifications: AccountNotifications[] = [
2023
{
21-
hostname: 'github.com',
22-
notifications: [mockSingleNotification],
24+
account: mockGitHubCloudAccount,
25+
notifications: [mockGitHubNotifications[0]],
2326
},
2427
];

src/__mocks__/partial-mocks.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
import type { Notification, Subject, User } from '../typesGitHub';
22
import Constants from '../utils/constants';
3+
import { mockGitifyUser, mockToken } from './state-mocks';
34

45
export function partialMockNotification(
56
subject: Partial<Subject>,
67
): Notification {
78
const mockNotification: Partial<Notification> = {
8-
hostname: Constants.GITHUB_API_BASE_URL,
9+
account: {
10+
method: 'Personal Access Token',
11+
platform: 'GitHub Cloud',
12+
hostname: Constants.GITHUB_API_BASE_URL,
13+
token: mockToken,
14+
user: mockGitifyUser,
15+
},
916
subject: subject as Subject,
1017
};
1118

src/__mocks__/state-mocks.ts

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import {
2+
type Account,
23
type AuthState,
34
type GitifyUser,
45
type SettingsState,
56
Theme,
67
} from '../types';
78
import type { EnterpriseAccount } from '../utils/auth/types';
9+
import Constants from '../utils/constants';
810

911
export const mockEnterpriseAccounts: EnterpriseAccount[] = [
1012
{
@@ -13,18 +15,50 @@ export const mockEnterpriseAccounts: EnterpriseAccount[] = [
1315
},
1416
];
1517

16-
export const mockUser: GitifyUser = {
18+
export const mockGitifyUser: GitifyUser = {
1719
login: 'octocat',
1820
name: 'Mona Lisa Octocat',
1921
id: 123456789,
2022
};
2123

22-
export const mockAuth: AuthState = {
24+
export const mockPersonalAccessTokenAccount: Account = {
25+
platform: 'GitHub Cloud',
26+
method: 'Personal Access Token',
27+
token: 'token-123-456',
28+
hostname: Constants.DEFAULT_AUTH_OPTIONS.hostname,
29+
user: mockGitifyUser,
30+
};
31+
32+
export const mockOAuthAccount: Account = {
33+
platform: 'GitHub Enterprise Server',
34+
method: 'OAuth App',
35+
token: '1234568790',
36+
hostname: 'github.gitify.io',
37+
user: mockGitifyUser,
38+
};
39+
40+
export const mockGitHubCloudAccount: Account = {
41+
platform: 'GitHub Cloud',
42+
method: 'Personal Access Token',
2343
token: 'token-123-456',
24-
enterpriseAccounts: mockEnterpriseAccounts,
25-
user: mockUser,
44+
hostname: Constants.DEFAULT_AUTH_OPTIONS.hostname,
45+
user: mockGitifyUser,
2646
};
2747

48+
export const mockGitHubEnterpriseServerAccount: Account = {
49+
platform: 'GitHub Enterprise Server',
50+
method: 'Personal Access Token',
51+
token: '1234568790',
52+
hostname: 'github.gitify.io',
53+
user: mockGitifyUser,
54+
};
55+
56+
export const mockAuth: AuthState = {
57+
accounts: [mockGitHubCloudAccount, mockGitHubEnterpriseServerAccount],
58+
};
59+
60+
export const mockToken = 'token-123-456';
61+
2862
export const mockSettings: SettingsState = {
2963
participating: false,
3064
playSound: true,

src/components/NotificationRow.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ interface IProps {
3636

3737
export const NotificationRow: FC<IProps> = ({ notification, hostname }) => {
3838
const {
39-
settings,
4039
auth,
40+
settings,
4141
removeNotificationFromState,
4242
markNotificationRead,
4343
markNotificationDone,
@@ -46,7 +46,7 @@ export const NotificationRow: FC<IProps> = ({ notification, hostname }) => {
4646
} = useContext(AppContext);
4747

4848
const openNotification = useCallback(() => {
49-
openInBrowser(notification, auth);
49+
openInBrowser(notification);
5050

5151
if (settings.markAsDoneOnOpen) {
5252
markNotificationDone(notification.id, hostname);

src/context/App.test.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { act, fireEvent, render, waitFor } from '@testing-library/react';
22
import { useContext } from 'react';
3-
43
import { mockAuth, mockSettings } from '../__mocks__/state-mocks';
54
import { useNotifications } from '../hooks/useNotifications';
65
import type { AuthState, SettingsState } from '../types';
@@ -133,6 +132,7 @@ describe('context/App.tsx', () => {
133132
expect(markNotificationReadMock).toHaveBeenCalledTimes(1);
134133
expect(markNotificationReadMock).toHaveBeenCalledWith(
135134
{
135+
accounts: [],
136136
enterpriseAccounts: [],
137137
token: null,
138138
user: null,
@@ -165,7 +165,7 @@ describe('context/App.tsx', () => {
165165

166166
expect(markNotificationDoneMock).toHaveBeenCalledTimes(1);
167167
expect(markNotificationDoneMock).toHaveBeenCalledWith(
168-
{ enterpriseAccounts: [], token: null, user: null },
168+
{ accounts: [], enterpriseAccounts: [], token: null, user: null },
169169
mockSettings,
170170
'123-456',
171171
'github.com',
@@ -194,7 +194,7 @@ describe('context/App.tsx', () => {
194194

195195
expect(unsubscribeNotificationMock).toHaveBeenCalledTimes(1);
196196
expect(unsubscribeNotificationMock).toHaveBeenCalledWith(
197-
{ enterpriseAccounts: [], token: null, user: null },
197+
{ accounts: [], enterpriseAccounts: [], token: null, user: null },
198198
mockSettings,
199199
'123-456',
200200
'github.com',
@@ -228,7 +228,7 @@ describe('context/App.tsx', () => {
228228

229229
expect(markRepoNotificationsMock).toHaveBeenCalledTimes(1);
230230
expect(markRepoNotificationsMock).toHaveBeenCalledWith(
231-
{ enterpriseAccounts: [], token: null, user: null },
231+
{ accounts: [], enterpriseAccounts: [], token: null, user: null },
232232
mockSettings,
233233
'gitify-app/notifications-test',
234234
'github.com',
@@ -262,13 +262,14 @@ describe('context/App.tsx', () => {
262262

263263
expect(markRepoNotificationsDoneMock).toHaveBeenCalledTimes(1);
264264
expect(markRepoNotificationsDoneMock).toHaveBeenCalledWith(
265-
{ enterpriseAccounts: [], token: null, user: null },
265+
{ accounts: [], enterpriseAccounts: [], token: null, user: null },
266266
mockSettings,
267267
'gitify-app/notifications-test',
268268
'github.com',
269269
);
270270
});
271271
});
272+
272273
describe('authentication methods', () => {
273274
const apiRequestAuthMock = jest.spyOn(apiRequests, 'apiRequestAuth');
274275
const fetchNotificationsMock = jest.fn();
@@ -370,7 +371,7 @@ describe('context/App.tsx', () => {
370371
});
371372

372373
expect(saveStateMock).toHaveBeenCalledWith({
373-
auth: { enterpriseAccounts: [], token: null, user: null },
374+
auth: { accounts: [], enterpriseAccounts: [], token: null, user: null },
374375
settings: {
375376
participating: true,
376377
playSound: true,
@@ -415,7 +416,7 @@ describe('context/App.tsx', () => {
415416
expect(setAutoLaunchMock).toHaveBeenCalledWith(true);
416417

417418
expect(saveStateMock).toHaveBeenCalledWith({
418-
auth: { enterpriseAccounts: [], token: null, user: null },
419+
auth: { accounts: [], enterpriseAccounts: [], token: null, user: null },
419420
settings: {
420421
participating: false,
421422
playSound: true,

src/context/App.tsx

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
Theme,
1818
} from '../types';
1919
import { headNotifications } from '../utils/api/client';
20+
import { migrateAuthenticatedAccounts } from '../utils/auth/migration';
2021
import type {
2122
LoginOAuthAppOptions,
2223
LoginPersonalAccessTokenOptions,
@@ -34,6 +35,7 @@ import { clearState, loadState, saveState } from '../utils/storage';
3435
import { setTheme } from '../utils/theme';
3536

3637
const defaultAuth: AuthState = {
38+
accounts: [],
3739
token: null,
3840
enterpriseAccounts: [],
3941
user: null,
@@ -116,8 +118,7 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
116118
settings.participating,
117119
settings.showBots,
118120
settings.detailedNotifications,
119-
auth.token,
120-
auth.enterpriseAccounts.length,
121+
auth.accounts.length,
121122
]);
122123

123124
useInterval(() => {
@@ -149,15 +150,15 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
149150
);
150151

151152
const isLoggedIn = useMemo(() => {
152-
return !!auth.token || auth.enterpriseAccounts.length > 0;
153+
return auth.accounts.length > 0;
153154
}, [auth]);
154155

155156
const loginWithGitHubApp = useCallback(async () => {
156157
const { authCode } = await authGitHub();
157158
const { token } = await getToken(authCode);
158159
const hostname = Constants.DEFAULT_AUTH_OPTIONS.hostname;
159160
const user = await getUserData(token, hostname);
160-
const updatedAuth = addAccount(auth, token, hostname, user);
161+
const updatedAuth = addAccount(auth, 'GitHub App', token, hostname, user);
161162
setAuth(updatedAuth);
162163
saveState({ auth: updatedAuth, settings });
163164
}, [auth, settings]);
@@ -166,7 +167,7 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
166167
async (data: LoginOAuthAppOptions) => {
167168
const { authOptions, authCode } = await authGitHub(data);
168169
const { token, hostname } = await getToken(authCode, authOptions);
169-
const updatedAuth = addAccount(auth, token, hostname);
170+
const updatedAuth = addAccount(auth, 'OAuth App', token, hostname);
170171
setAuth(updatedAuth);
171172
saveState({ auth: updatedAuth, settings });
172173
},
@@ -178,7 +179,13 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
178179
await headNotifications(hostname, token);
179180

180181
const user = await getUserData(token, hostname);
181-
const updatedAuth = addAccount(auth, token, hostname, user);
182+
const updatedAuth = addAccount(
183+
auth,
184+
'Personal Access Token',
185+
token,
186+
hostname,
187+
user,
188+
);
182189
setAuth(updatedAuth);
183190
saveState({ auth: updatedAuth, settings });
184191
},
@@ -190,7 +197,9 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
190197
clearState();
191198
}, []);
192199

193-
const restoreSettings = useCallback(() => {
200+
const restoreSettings = useCallback(async () => {
201+
await migrateAuthenticatedAccounts();
202+
194203
const existing = loadState();
195204

196205
if (existing.auth) {

0 commit comments

Comments
 (0)