Secure connexion between TinyBird and webhookResponseGraph (#7913)
TLDR: Secure connexion between tinybird and twenty using jwt when accessing datasource from tinybird. Solves: https://github.com/twentyhq/private-issues/issues/73 In order to test: 1. Set ANALYTICS_ENABLED to true 2. Set TINYBIRD_JWT_TOKEN to the ADMIN token from the workspace twenty_analytics_playground 3. Set TINYBIRD_JWT_TOKEN to the datasource or your admin token from the workspace twenty_analytics_playground 4. Create a Webhook in twenty and set wich events it needs to track 5. Run twenty-worker in order to make the webhooks work. 6. Do your tasks in order to populate the data 7. Enter to settings> webhook>your webhook and the statistics section should be displayed. --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
committed by
GitHub
parent
edf4ae084b
commit
373926b895
@ -1,6 +1,6 @@
|
||||
import { useGraphData } from '@/settings/developers/webhook/hooks/useGraphData';
|
||||
import { webhookGraphDataState } from '@/settings/developers/webhook/states/webhookGraphDataState';
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
type SettingsDevelopersWebhookUsageGraphEffectProps = {
|
||||
@ -11,14 +11,18 @@ export const SettingsDevelopersWebhookUsageGraphEffect = ({
|
||||
webhookId,
|
||||
}: SettingsDevelopersWebhookUsageGraphEffectProps) => {
|
||||
const setWebhookGraphData = useSetRecoilState(webhookGraphDataState);
|
||||
const [isLoaded, setIsLoaded] = useState(false);
|
||||
|
||||
const { fetchGraphData } = useGraphData(webhookId);
|
||||
|
||||
useEffect(() => {
|
||||
fetchGraphData('7D').then((graphInput) => {
|
||||
setWebhookGraphData(graphInput);
|
||||
});
|
||||
}, [fetchGraphData, setWebhookGraphData, webhookId]);
|
||||
if (!isLoaded) {
|
||||
fetchGraphData('7D').then((graphInput) => {
|
||||
setWebhookGraphData(graphInput);
|
||||
});
|
||||
setIsLoaded(true);
|
||||
}
|
||||
}, [fetchGraphData, isLoaded, setWebhookGraphData, webhookId]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
|
||||
import { CurrentUser, currentUserState } from '@/auth/states/currentUserState';
|
||||
import { useAnalyticsTinybirdJwt } from '@/settings/developers/webhook/hooks/useAnalyticsTinybirdJwt';
|
||||
import { act } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||
|
||||
const Wrapper = getJestMetadataAndApolloMocksWrapper({
|
||||
apolloMocks: [],
|
||||
});
|
||||
|
||||
describe('useAnalyticsTinybirdJwt', () => {
|
||||
it('should return the analytics jwt token', async () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const setCurrentUserState = useSetRecoilState(currentUserState);
|
||||
|
||||
return {
|
||||
useAnalyticsTinybirdJwt: useAnalyticsTinybirdJwt(),
|
||||
setCurrentUserState,
|
||||
};
|
||||
},
|
||||
{ wrapper: Wrapper },
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.setCurrentUserState({
|
||||
analyticsTinybirdJwt: 'jwt',
|
||||
} as CurrentUser);
|
||||
});
|
||||
|
||||
expect(result.current.useAnalyticsTinybirdJwt).toBe('jwt');
|
||||
|
||||
act(() => {
|
||||
result.current.setCurrentUserState(null);
|
||||
});
|
||||
|
||||
expect(result.current.useAnalyticsTinybirdJwt).toBeUndefined();
|
||||
|
||||
act(() => {
|
||||
result.current.setCurrentUserState({} as CurrentUser);
|
||||
});
|
||||
|
||||
expect(result.current.useAnalyticsTinybirdJwt).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,18 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { isNull } from '@sniptt/guards';
|
||||
|
||||
export const useAnalyticsTinybirdJwt = (): string | undefined => {
|
||||
const currentUser = useRecoilValue(currentUserState);
|
||||
|
||||
if (!currentUser) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (isNull(currentUser.analyticsTinybirdJwt)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return currentUser.analyticsTinybirdJwt;
|
||||
};
|
||||
@ -1,16 +1,24 @@
|
||||
import { useAnalyticsTinybirdJwt } from '@/settings/developers/webhook/hooks/useAnalyticsTinybirdJwt';
|
||||
import { fetchGraphDataOrThrow } from '@/settings/developers/webhook/utils/fetchGraphDataOrThrow';
|
||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { isUndefined } from '@sniptt/guards';
|
||||
|
||||
export const useGraphData = (webhookId: string) => {
|
||||
const { enqueueSnackBar } = useSnackBar();
|
||||
const analyticsTinybirdJwt = useAnalyticsTinybirdJwt();
|
||||
const fetchGraphData = async (
|
||||
windowLengthGraphOption: '7D' | '1D' | '12H' | '4H',
|
||||
) => {
|
||||
try {
|
||||
if (isUndefined(analyticsTinybirdJwt)) {
|
||||
throw new Error('No analyticsTinybirdJwt found');
|
||||
}
|
||||
|
||||
return await fetchGraphDataOrThrow({
|
||||
webhookId,
|
||||
windowLength: windowLengthGraphOption,
|
||||
tinybirdJwt: analyticsTinybirdJwt,
|
||||
});
|
||||
} catch (error) {
|
||||
enqueueSnackBar('Something went wrong while fetching webhook usage', {
|
||||
|
||||
@ -4,22 +4,24 @@ import { WEBHOOK_GRAPH_API_OPTIONS_MAP } from '@/settings/developers/webhook/con
|
||||
type fetchGraphDataOrThrowProps = {
|
||||
webhookId: string;
|
||||
windowLength: '7D' | '1D' | '12H' | '4H';
|
||||
tinybirdJwt: string;
|
||||
};
|
||||
|
||||
export const fetchGraphDataOrThrow = async ({
|
||||
webhookId,
|
||||
windowLength,
|
||||
tinybirdJwt,
|
||||
}: fetchGraphDataOrThrowProps) => {
|
||||
const queryString = new URLSearchParams({
|
||||
...WEBHOOK_GRAPH_API_OPTIONS_MAP[windowLength],
|
||||
webhookIdRequest: webhookId,
|
||||
}).toString();
|
||||
const token = 'REPLACE_ME';
|
||||
|
||||
const response = await fetch(
|
||||
`https://api.eu-central-1.aws.tinybird.co/v0/pipes/getWebhooksAnalyticsV2.json?${queryString}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + token,
|
||||
Authorization: 'Bearer ' + tinybirdJwt,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user