Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove reliance on JSForce #742

Merged
merged 37 commits into from
Mar 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
e87cd4d
Remove reliance on JSForce
paustint Feb 19, 2024
ee1b80c
Remove JSForce usage
paustint Feb 19, 2024
9b597af
Removed api-interfaces
paustint Feb 19, 2024
96dfc5c
Add better types for controller handler functions
paustint Feb 19, 2024
b3027b8
Fix build error from invalid type
paustint Feb 19, 2024
ec251d4
Fix E2E login test
paustint Feb 19, 2024
48ac621
Fix E2E test
paustint Feb 19, 2024
a97d964
Update node version back to 20
paustint Feb 20, 2024
12fecf2
Add all Salesforce Types to Jetstream and remove type reliance from j…
paustint Feb 20, 2024
15b052f
Fix API route paths
paustint Feb 20, 2024
b2ddaec
Fix frontdoor login
paustint Feb 21, 2024
ec85777
Merge branch 'main' into poc/generic-salesforce-api
paustint Feb 22, 2024
32d5606
Fix types and add API tests
paustint Feb 22, 2024
32dc125
Add tests and fix api bugs
paustint Feb 23, 2024
a08da4d
Add type validation using zod to all server routes
paustint Feb 24, 2024
b0af54e
Added additional tests for metadata api endpoints
paustint Feb 24, 2024
4057c3b
Add E2E API tests and fix route validation
paustint Feb 26, 2024
2197277
Fix clone record modal, revert bulk api minimum count (was for testing)
paustint Feb 26, 2024
23a4ede
Ensure that sfdc client information is available for a refresh attempt
paustint Feb 28, 2024
f2b4bd4
Merge branch 'main' into poc/generic-salesforce-api
paustint Mar 1, 2024
b233e35
Fix Bulk Query API 2.0 tests / endpoints
paustint Mar 1, 2024
4e6a27d
Add error parsing for salesforce error messages
paustint Mar 1, 2024
8ff3114
Migrate to Pino for logging
paustint Mar 2, 2024
f84a9c7
Fix list metadata
paustint Mar 3, 2024
18b469b
Fix create object results when no permissions are deployed
paustint Mar 3, 2024
f95bd32
Fix create field issues
paustint Mar 3, 2024
4567167
Changed API logger 404 response
paustint Mar 3, 2024
8dd1772
Merge branch 'main' into poc/generic-salesforce-api
paustint Mar 17, 2024
8ddf9e2
Merge branch 'main' into poc/generic-salesforce-api
paustint Mar 17, 2024
f7c6d12
Merge branch 'main' into poc/generic-salesforce-api
paustint Mar 17, 2024
3a046bf
Bugfixes
paustint Mar 17, 2024
95f862b
Remove accidental JSForce import
paustint Mar 17, 2024
5f74f72
Add apex test
paustint Mar 18, 2024
2e5e0e7
Upgrade axios
paustint Mar 18, 2024
d9ad577
Merge branch 'main' into poc/generic-salesforce-api
paustint Mar 23, 2024
73213cb
Fix Build Issue
paustint Mar 23, 2024
ed9b8a8
Bugfixes + logging improvements
paustint Mar 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ JETSTREAM_SERVER_DOMAIN='localhost:3333'
JETSTREAM_SERVER_URL='http://localhost:3333'
JETSTREAM_POSTGRES_DBURI='postgres://postgres@localhost:5432/postgres'

# trace, debug (default), info, warn, error, fatal, silent - determines how much server logging is done
LOG_LEVEL='trace'

# PLAYWRIGHT INTEGRATION TEST LOGIN
E2E_LOGIN_USERNAME='[email protected]'
E2E_LOGIN_PASSWORD='TODO'
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ This project was generated using [Nx](https://nx.dev) - This repository is consi
├── electron-scripts
├── libs (CORE LIBRARIES SHARED ACROSS ALL APPLICATIONS)
│ ├── api-config
│ ├── api-interfaces
│ ├── connected (FRONTEND DATA LIBRARY)
│ ├── icon-factory (SFDC ICONS)
│ ├── monaco-configuration
Expand Down
3 changes: 2 additions & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"license": "PRIVATE",
"repository": "https://github.com/jetstreamapp/jetstream",
"engines": {
"node": ">=16 <17"
"node": ">= 20",
"yarn": "1.22.21"
},
"private": true,
"dependencies": {
Expand Down
47 changes: 26 additions & 21 deletions apps/api/src/app/controllers/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { ENV, logger } from '@jetstream/api-config';
import { ENV, getExceptionLog } from '@jetstream/api-config';
import { UserProfileServer } from '@jetstream/types';
import { NextFunction, Request, Response } from 'express';
import { NextFunction } from 'express';
import { isString } from 'lodash';
import * as passport from 'passport';
import { URL } from 'url';
import { hardDeleteUserAndOrgs } from '../db/transactions.db';
import { createOrUpdateUser } from '../db/user.db';
import { checkAuth } from '../routes/route.middleware';
// import { sendWelcomeEmail } from '../services/worker-jobs';
import { linkIdentity } from '../services/auth0';
import { Request, Response } from '../types/types';
import { AuthenticationError } from '../utils/error-handler';
// import { sendWelcomeEmail } from '../services/worker-jobs';

export interface OauthLinkParams {
type: 'auth' | 'salesforce';
Expand All @@ -30,17 +31,17 @@ export async function login(req: Request, res: Response) {
const user = req.user as UserProfileServer;
req.logIn(user, async (err) => {
if (err) {
logger.warn('[AUTH][ERROR] Error logging in %o', err, { requestId: res.locals.requestId });
req.log.warn({ ...getExceptionLog(err) }, '[AUTH][ERROR] Error logging in %o', err);
return res.redirect('/');
}

createOrUpdateUser(user)
.then(async ({ user: _user }) => {
logger.info('[AUTH][SUCCESS] Logged in %s', _user.email, { userId: user.id, requestId: res.locals.requestId });
req.log.info('[AUTH][SUCCESS] Logged in %s', _user.email);
res.redirect(ENV.JETSTREAM_CLIENT_URL!);
})
.catch((err) => {
logger.error('[AUTH][DB][ERROR] Error creating or sending welcome email %o', err, { requestId: res.locals.requestId });
req.log.error({ ...getExceptionLog(err) }, '[AUTH][DB][ERROR] Error creating or sending welcome email %o', err);
res.redirect('/');
});
});
Expand All @@ -59,28 +60,28 @@ export async function callback(req: Request, res: Response, next: NextFunction)
},
(err, user, info) => {
if (err) {
logger.warn('[AUTH][ERROR] Error with authentication %o', err, { requestId: res.locals.requestId });
req.log.warn({ ...getExceptionLog(err) }, '[AUTH][ERROR] Error with authentication %o', err);
return next(new AuthenticationError(err));
}
if (!user) {
logger.warn('[AUTH][ERROR] no user', { requestId: res.locals.requestId });
logger.warn('[AUTH][ERROR] no info %o', info, { requestId: res.locals.requestId });
req.log.warn('[AUTH][ERROR] no user');
req.log.warn('[AUTH][ERROR] no info %o', info);
return res.redirect('/oauth/login');
}
req.logIn(user, async (err) => {
if (err) {
logger.warn('[AUTH][ERROR] Error logging in %o', err, { requestId: res.locals.requestId });
req.log.warn('[AUTH][ERROR] Error logging in %o', err);
return next(new AuthenticationError(err));
}

createOrUpdateUser(user).catch((err) => {
logger.error('[AUTH][DB][ERROR] Error creating or sending welcome email %o', err, { requestId: res.locals.requestId });
req.log.error({ ...getExceptionLog(err) }, '[AUTH][DB][ERROR] Error creating or sending welcome email %o', err);
});

// TODO: confirm returnTo 0 it suddenly was reported as bad
const returnTo = (req.session as any).returnTo;
delete (req.session as any).returnTo;
logger.info('[AUTH][SUCCESS] Logged in %s', user.email, { userId: user.id, requestId: res.locals.requestId });
req.log.info('[AUTH][SUCCESS] Logged in %s', user.email);
res.redirect(returnTo || ENV.JETSTREAM_CLIENT_URL);
});
}
Expand Down Expand Up @@ -115,14 +116,13 @@ export async function linkCallback(req: Request, res: Response, next: NextFuncti
clientUrl: new URL(ENV.JETSTREAM_CLIENT_URL!).origin,
};
if (err) {
logger.warn('[AUTH][LINK][ERROR] Error with authentication %o', err, { requestId: res.locals.requestId });
req.log.warn({ ...getExceptionLog(err) }, '[AUTH][LINK][ERROR] Error with authentication %o', err);
params.error = isString(err) ? err : err.message || 'Unknown Error';
params.message = (req.query.error_description as string) || undefined;
return res.redirect(`/oauth-link/?${new URLSearchParams(params as any).toString()}`);
}
if (!userProfile) {
logger.warn('[AUTH][LINK][ERROR] no user', { requestId: res.locals.requestId });
logger.warn('[AUTH][LINK][ERROR] no info %o', info, { requestId: res.locals.requestId });
req.log.warn('[AUTH][LINK][ERROR] no user');
params.error = 'Authentication Error';
params.message = (req.query.error_description as string) || undefined;
return res.redirect(`/oauth-link/?${new URLSearchParams(params as any).toString()}`);
Expand All @@ -137,16 +137,21 @@ export async function linkCallback(req: Request, res: Response, next: NextFuncti
try {
await hardDeleteUserAndOrgs(userProfile.user_id);
} catch (ex) {
logger.warn('[AUTH0][IDENTITY][LINK][ERROR] Failed to delete the secondary user orgs %s', userProfile.user_id, {
userId: user.id,
secondaryUserId: userProfile.user_id,
requestId: res.locals.requestId,
});
req.log.warn(
{
userId: user.id,
secondaryUserId: userProfile.user_id,

...getExceptionLog(ex),
},
'[AUTH0][IDENTITY][LINK][ERROR] Failed to delete the secondary user orgs %s',
userProfile.user_id
);
}

return res.redirect(`/oauth-link/?${new URLSearchParams(params as any).toString()}`);
} catch (ex) {
logger.warn('[AUTH][LINK][ERROR] Error linking account %o', err, { requestId: res.locals.requestId });
req.log.warn({ ...getExceptionLog(ex) }, '[AUTH][LINK][ERROR] Error linking account %s', ex);
params.error = 'Unexpected Error';
return res.redirect(`/oauth-link/?${new URLSearchParams(params as any).toString()}&clientUrl=${ENV.JETSTREAM_CLIENT_URL}`);
}
Expand Down
22 changes: 12 additions & 10 deletions apps/api/src/app/controllers/image.controller.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
import { ENV } from '@jetstream/api-config';
import { UserProfileServer } from '@jetstream/types';
import { v2 as cloudinary } from 'cloudinary';
import { NextFunction, Request, Response } from 'express';
import { UserFacingError } from '../utils/error-handler';
import { sendJson } from '../utils/response.handlers';
import { createRoute } from '../utils/route.utils';

cloudinary.config({ secure: true });

export const routeValidators = {
getUploadSignature: [],
export const routeDefinition = {
getUploadSignature: {
controllerFn: () => getUploadSignature,
validators: {
hasSourceOrg: false,
},
},
};

export async function getUploadSignature(req: Request, res: Response, next: NextFunction) {
const getUploadSignature = createRoute(routeDefinition.getUploadSignature.validators, async ({ user }, req, res, next) => {
try {
const user = req.user as UserProfileServer;
const timestamp = Math.round(new Date().getTime() / 1000);
const cloudName = cloudinary.config().cloud_name;
const apiKey = cloudinary.config().api_key;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const apiSecret = cloudinary.config().api_secret!;
const context = `caption=${user.id.replace('|', '\\|')}|environment=${ENV.JETSTREAM_SERVER_URL}`;

const signature = cloudinary.utils.api_sign_request({ timestamp: timestamp, upload_preset: 'jetstream-issues', context }, apiSecret);
const signature = cloudinary.utils.api_sign_request({ timestamp, upload_preset: 'jetstream-issues', context }, apiSecret);

sendJson(res, { signature: signature, timestamp: timestamp, cloudName: cloudName, apiKey: apiKey, context }, 200);
sendJson(res, { signature: signature, timestamp, cloudName: cloudName, apiKey: apiKey, context }, 200);
} catch (ex) {
next(new UserFacingError(ex.message));
}
}
});
Loading