Skip to content

Commit 0001373

Browse files
committed
feat: sync orgs from webapp to desktop app
sync orgs and groups to desktop - require re-auth This only syncs net-new orgs and does not attempt to merge anything
1 parent b1e7ca2 commit 0001373

8 files changed

Lines changed: 834 additions & 45 deletions

File tree

apps/api/src/app/controllers/desktop-app.controller.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ export const routeDefinition = {
7171
hasSourceOrg: false,
7272
} satisfies RouteValidator,
7373
},
74+
getOrgs: {
75+
controllerFn: () => getOrgs,
76+
responseType: z.any(),
77+
validators: {
78+
hasSourceOrg: false,
79+
} satisfies RouteValidator,
80+
},
7481
dataSyncPull: {
7582
controllerFn: () => dataSyncPull,
7683
responseType: z.any(),
@@ -209,6 +216,17 @@ const logout = createRoute(routeDefinition.logout.validators, async ({ user }, _
209216
}
210217
});
211218

219+
const getOrgs = createRoute(routeDefinition.getOrgs.validators, async ({ user }, _, res, next) => {
220+
try {
221+
const orgs = await salesforceOrgsDb.findByUserId(user.id);
222+
const organizations = await orgGroupsDb.findByUserId({ userId: user.id });
223+
224+
sendJson(res, { orgs, organizations });
225+
} catch (ex) {
226+
next(new UserFacingError(ex));
227+
}
228+
});
229+
212230
const dataSyncPull = createRoute(routeDefinition.dataSyncPull.validators, async ({ user, query }, _, res) => {
213231
const { lastKey, updatedAt, limit } = query;
214232
const response = await userSyncDbService.findByUpdatedAt({

apps/api/src/app/routes/desktop-app.routes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ routes.delete('/auth/logout', STRICT_AuthRateLimit, authMiddleware, desktopAppCo
7878
/**
7979
* Other Routes
8080
*/
81+
routes.get('/orgs', authMiddleware, desktopAppController.routeDefinition.getOrgs.controllerFn());
82+
8183
routes.get('/data-sync/pull', authMiddleware, desktopAppController.routeDefinition.dataSyncPull.controllerFn());
8284
routes.post('/data-sync/push', authMiddleware, desktopAppController.routeDefinition.dataSyncPush.controllerFn());
8385

apps/jetstream-desktop/src/controllers/jetstream-data-sync.desktop.controller.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import { HTTP } from '@jetstream/shared/constants';
22
import { app } from 'electron';
33
import { z } from 'zod';
44
import { ENV } from '../config/environment';
5-
import { getAppData } from '../services/persistence.service';
6-
import { createRoute, handleErrorResponse, RouteValidator } from '../utils/route.utils';
5+
import { createRoute, getTokens, handleErrorResponse, RouteValidator } from '../utils/route.utils';
76

87
/**
98
* FIXME: this file needs to be worked on
@@ -27,16 +26,6 @@ export const routeDefinition = {
2726
},
2827
};
2928

30-
function getTokens() {
31-
const { accessToken, deviceId } = getAppData();
32-
33-
if (!accessToken || !deviceId) {
34-
throw new Error('Unauthorized');
35-
}
36-
37-
return { authTokens: { accessToken }, extIdentifier: { id: deviceId } };
38-
}
39-
4029
const pull = createRoute(routeDefinition.pull.validators, async ({ query }) => {
4130
try {
4231
const { authTokens, extIdentifier } = getTokens();

apps/jetstream-desktop/src/controllers/orgs.desktop.controller.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import { ApiRequestError } from '@jetstream/salesforce-api';
2-
import { ERROR_MESSAGES } from '@jetstream/shared/constants';
3-
import { SObjectOrganization } from '@jetstream/types';
2+
import { ERROR_MESSAGES, HTTP } from '@jetstream/shared/constants';
3+
import { OrgsWithGroupResponse, SObjectOrganization } from '@jetstream/types';
4+
import { app } from 'electron';
5+
import logger from 'electron-log';
46
import { z } from 'zod';
7+
import { ENV } from '../config/environment';
58
import * as dataService from '../services/persistence.service';
6-
import { createRoute, handleErrorResponse, handleJsonResponse, RouteValidator } from '../utils/route.utils';
9+
import { createRoute, getTokens, handleErrorResponse, handleJsonResponse, RouteValidator } from '../utils/route.utils';
710

811
export const routeDefinition = {
912
getOrgs: {
@@ -52,7 +55,30 @@ export const routeDefinition = {
5255

5356
const getOrgs = createRoute(routeDefinition.getOrgs.validators, async ({}) => {
5457
try {
55-
const orgs = dataService.getSalesforceOrgs().map((org) => ({ ...org, accessToken: undefined }));
58+
const { authTokens, extIdentifier } = getTokens();
59+
60+
const webAppOrgs = await fetch(`${ENV.SERVER_URL}/desktop-app/orgs`, {
61+
method: 'GET',
62+
headers: {
63+
Accept: 'application/json',
64+
Authorization: `Bearer ${authTokens?.accessToken}`,
65+
[HTTP.HEADERS.X_EXT_DEVICE_ID]: extIdentifier.id,
66+
[HTTP.HEADERS.X_APP_VERSION]: app.getVersion(),
67+
},
68+
})
69+
.then(async (res) => {
70+
if (!res.ok) {
71+
logger.warn('Failed to fetch orgs from web app', { error: await res.text().catch(() => 'Unable to read response body') });
72+
return null;
73+
}
74+
return (res.json() as Promise<{ data: OrgsWithGroupResponse }>).then(({ data }) => data);
75+
})
76+
.catch((ex) => {
77+
logger.warn('Failed to fetch orgs from web app', { error: ex });
78+
return null;
79+
});
80+
81+
const orgs = dataService.mergeWebAppOrgsWithDesktopOrgs(webAppOrgs).map((org) => ({ ...org, accessToken: undefined }));
5682

5783
return handleJsonResponse(orgs);
5884
} catch (ex) {

apps/jetstream-desktop/src/controllers/user.desktop.controller.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { app } from 'electron';
44
import { z } from 'zod';
55
import { ENV } from '../config/environment';
66
import * as dataService from '../services/persistence.service';
7-
import { createRoute, handleErrorResponse, handleJsonResponse, RouteValidator } from '../utils/route.utils';
7+
import { createRoute, getTokens, handleErrorResponse, handleJsonResponse, RouteValidator } from '../utils/route.utils';
88

99
export const routeDefinition = {
1010
getUserProfile: {
@@ -59,16 +59,6 @@ const updateProfile = createRoute(routeDefinition.updateProfile.validators, asyn
5959
}
6060
});
6161

62-
function getTokens() {
63-
const { accessToken, deviceId } = dataService.getAppData();
64-
65-
if (!accessToken || !deviceId) {
66-
throw new Error('Unauthorized');
67-
}
68-
69-
return { authTokens: { accessToken }, extIdentifier: { id: deviceId } };
70-
}
71-
7262
const sendUserFeedbackEmail = createRoute(routeDefinition.sendUserFeedbackEmail.validators, async ({}, req) => {
7363
try {
7464
const { authTokens, extIdentifier } = getTokens();

0 commit comments

Comments
 (0)