Skip to content

Commit

Permalink
add jwt support for webhooks graphs
Browse files Browse the repository at this point in the history
  • Loading branch information
anamarn committed Oct 21, 2024
1 parent 8cadcdf commit 7663067
Show file tree
Hide file tree
Showing 11 changed files with 88 additions and 9 deletions.
10 changes: 6 additions & 4 deletions packages/twenty-front/src/generated/graphql.tsx

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type CurrentUser = Pick<
| 'id'
| 'email'
| 'supportUserHash'
| 'analyticsTinybirdJwt'
| 'canImpersonate'
| 'onboardingStatus'
| 'userVars'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { useRecoilValue } from 'recoil';

import { currentUserState } from '@/auth/states/currentUserState';

export const useAnalyticsTinybirdJwt = (): string | null | undefined => {
const currentUser = useRecoilValue(currentUserState);
return currentUser?.analyticsTinybirdJwt;
};
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
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';

export const useGraphData = (webhookId: string) => {
const { enqueueSnackBar } = useSnackBar();
const supportTinybirdJwt = useAnalyticsTinybirdJwt();
const fetchGraphData = async (
windowLengthGraphOption: '7D' | '1D' | '12H' | '4H',
) => {
try {
return await fetchGraphDataOrThrow({
webhookId,
windowLength: windowLengthGraphOption,
tinybirdJwt: supportTinybirdJwt ?? undefined,
});
} catch (error) {
enqueueSnackBar('Something went wrong while fetching webhook usage', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
},
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const USER_QUERY_FRAGMENT = gql`
email
canImpersonate
supportUserHash
analyticsTinybirdJwt
onboardingStatus
workspaceMember {
...WorkspaceMemberQueryFragment
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
/* eslint-disable no-restricted-imports */
import { HttpModule } from '@nestjs/axios';
import { Module } from '@nestjs/common';
import { JwtModule as NestJwtModule } from '@nestjs/jwt';

import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';

import { AnalyticsResolver } from './analytics.resolver';
import { AnalyticsService } from './analytics.service';

const TINYBIRD_BASE_URL = 'https://api.eu-central-1.aws.tinybird.co/v0';

const InternalTinybirdJwtModule = NestJwtModule.registerAsync({
useFactory: async (environmentService: EnvironmentService) => {
return {
secret: environmentService.get('TINYBIRD_JWT_TOKEN'),
signOptions: {
expiresIn: environmentService.get('TINYBIRD_TOKEN_EXPIRES_IN'),
},
};
},
inject: [EnvironmentService],
});

@Module({
providers: [AnalyticsResolver, AnalyticsService],
imports: [
HttpModule.register({
baseURL: TINYBIRD_BASE_URL,
}),
InternalTinybirdJwtModule,
],
exports: [AnalyticsService],
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { HttpService } from '@nestjs/axios';
import { Injectable, Logger } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

import { AxiosRequestConfig } from 'axios';

Expand All @@ -18,6 +19,7 @@ export class AnalyticsService {
constructor(
private readonly environmentService: EnvironmentService,
private readonly httpService: HttpService,
private readonly jwtService: JwtService,
) {}

async create(
Expand Down Expand Up @@ -58,7 +60,7 @@ export class AnalyticsService {
const config: AxiosRequestConfig = {
headers: {
Authorization:
'Bearer ' + this.environmentService.get('TINYBIRD_TOKEN'),
'Bearer ' + this.environmentService.get('TINYBIRD_DATASOURCE_TOKEN'),
},
};

Expand Down Expand Up @@ -86,4 +88,22 @@ export class AnalyticsService {

return { success: true };
}

async generateJWT(workspaceId: string | null | undefined) {
const pipeId = 't_b49e0fe60f9e438eae81cb31c5260df2'; // refactor this pass as params
//perhaps a constant of name:pipeId??? better typing in this func^
const payload = {
name: 'my_demo_jwt',
workspace_id: this.environmentService.get('TINYBIRD_WORKSPACE_UUID'),
scopes: [
{
type: 'PIPES:READ',
resource: pipeId,
fixed_params: { workspaceId: workspaceId },
},
],
};

return this.jwtService.sign(payload);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,23 @@ export class EnvironmentVariables {
@CastToBoolean()
@IsOptional()
@IsBoolean()
ANALYTICS_ENABLED = false;
ANALYTICS_ENABLED = true;

@IsString()
@ValidateIf((env) => env.ANALYTICS_ENABLED)
TINYBIRD_TOKEN: string;
TINYBIRD_DATASOURCE_TOKEN: string;

@IsString()
@ValidateIf((env) => env.ANALYTICS_ENABLED)
TINYBIRD_WORKSPACE_UUID: string;

@IsString()
@ValidateIf((env) => env.ANALYTICS_ENABLED)
TINYBIRD_TOKEN_EXPIRES_IN: string;

@IsString()
@ValidateIf((env) => env.ANALYTICS_ENABLED)
TINYBIRD_JWT_TOKEN: string;

@CastToPositiveNumber()
@IsNumber()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';

import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
import { AnalyticsModule } from 'src/engine/core-modules/analytics/analytics.module';
import { FileUploadModule } from 'src/engine/core-modules/file/file-upload/file-upload.module';
import { FileModule } from 'src/engine/core-modules/file/file.module';
import { KeyValuePair } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
Expand Down Expand Up @@ -37,6 +38,7 @@ import { UserService } from './services/user.service';
OnboardingModule,
TypeOrmModule.forFeature([KeyValuePair], 'core'),
UserVarsModule,
AnalyticsModule,
],
exports: [UserService],
providers: [UserService, UserResolver, TypeORMService],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { Repository } from 'typeorm';
import { SupportDriver } from 'src/engine/core-modules/environment/interfaces/support.interface';
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';

import { AnalyticsService } from 'src/engine/core-modules/analytics/analytics.service';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
import { FileService } from 'src/engine/core-modules/file/services/file.service';
Expand Down Expand Up @@ -55,6 +56,7 @@ export class UserResolver {
private readonly onboardingService: OnboardingService,
private readonly userVarService: UserVarsService,
private readonly fileService: FileService,
private readonly analyticsservice: AnalyticsService,
) {}

@Query(() => User)
Expand Down Expand Up @@ -154,6 +156,15 @@ export class UserResolver {
return getHMACKey(parent.email, key);
}

@ResolveField(() => String, {
nullable: true,
})
async analyticsTinybirdJwt(
@AuthWorkspace() workspace: Workspace | undefined,
): Promise<string | null> {
return await this.analyticsservice.generateJWT(workspace?.id);
}

@Mutation(() => String)
async uploadProfilePicture(
@AuthUser() { id }: User,
Expand Down

0 comments on commit 7663067

Please sign in to comment.