feat: wip server folder structure (#4573)

* feat: wip server folder structure

* fix: merge

* fix: wrong merge

* fix: remove unused file

* fix: comment

* fix: lint

* fix: merge

* fix: remove console.log

* fix: metadata graphql arguments broken
This commit is contained in:
Jérémy M
2024-03-20 16:23:46 +01:00
committed by GitHub
parent da12710fe9
commit e5c1309e8c
461 changed files with 1396 additions and 1322 deletions

View File

@ -0,0 +1,9 @@
import { ObjectType, Field } from '@nestjs/graphql';
@ObjectType()
export class Analytics {
@Field(() => Boolean, {
description: 'Boolean that confirms query was dispatched',
})
success: boolean;
}

View File

@ -0,0 +1,15 @@
import { Module } from '@nestjs/common';
import { HttpModule } from '@nestjs/axios';
import { AnalyticsService } from './analytics.service';
import { AnalyticsResolver } from './analytics.resolver';
@Module({
providers: [AnalyticsResolver, AnalyticsService],
imports: [
HttpModule.register({
baseURL: 'https://t.twenty.com/api/v1/s2s',
}),
],
})
export class AnalyticsModule {}

View File

@ -0,0 +1,34 @@
import { Test, TestingModule } from '@nestjs/testing';
import { HttpService } from '@nestjs/axios';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { AnalyticsResolver } from './analytics.resolver';
import { AnalyticsService } from './analytics.service';
describe('AnalyticsResolver', () => {
let resolver: AnalyticsResolver;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
AnalyticsResolver,
AnalyticsService,
{
provide: EnvironmentService,
useValue: {},
},
{
provide: HttpService,
useValue: {},
},
],
}).compile();
resolver = module.get<AnalyticsResolver>(AnalyticsResolver);
});
it('should be defined', () => {
expect(resolver).toBeDefined();
});
});

View File

@ -0,0 +1,36 @@
import { Resolver, Mutation, Args, Context } from '@nestjs/graphql';
import { UseGuards } from '@nestjs/common';
import { Request } from 'express';
import { OptionalJwtAuthGuard } from 'src/engine/guards/optional-jwt.auth.guard';
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { User } from 'src/engine/core-modules/user/user.entity';
import { AnalyticsService } from './analytics.service';
import { Analytics } from './analytics.entity';
import { CreateAnalyticsInput } from './dto/create-analytics.input';
@UseGuards(OptionalJwtAuthGuard)
@Resolver(() => Analytics)
export class AnalyticsResolver {
constructor(private readonly analyticsService: AnalyticsService) {}
@Mutation(() => Analytics)
track(
@Args() createAnalyticsInput: CreateAnalyticsInput,
@AuthWorkspace() workspace: Workspace | undefined,
@AuthUser({ allowUndefined: true }) user: User | undefined,
@Context('req') request: Request,
) {
return this.analyticsService.create(
createAnalyticsInput,
user,
workspace,
request,
);
}
}

View File

@ -0,0 +1,32 @@
import { Test, TestingModule } from '@nestjs/testing';
import { HttpService } from '@nestjs/axios';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { AnalyticsService } from './analytics.service';
describe('AnalyticsService', () => {
let service: AnalyticsService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
AnalyticsService,
{
provide: EnvironmentService,
useValue: {},
},
{
provide: HttpService,
useValue: {},
},
],
}).compile();
service = module.get<AnalyticsService>(AnalyticsService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@ -0,0 +1,60 @@
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { Request } from 'express';
import { anonymize } from 'src/utils/anonymize';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { User } from 'src/engine/core-modules/user/user.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { CreateAnalyticsInput } from './dto/create-analytics.input';
@Injectable()
export class AnalyticsService {
constructor(
private readonly environmentService: EnvironmentService,
private readonly httpService: HttpService,
) {}
async create(
createEventInput: CreateAnalyticsInput,
user: User | undefined,
workspace: Workspace | undefined,
request: Request,
) {
if (!this.environmentService.get('TELEMETRY_ENABLED')) {
return { success: true };
}
const anonymizationEnabled = this.environmentService.get(
'TELEMETRY_ANONYMIZATION_ENABLED',
);
const data = {
type: createEventInput.type,
data: {
hostname: request.hostname,
userUUID: user
? anonymizationEnabled
? anonymize(user.id)
: user.id
: undefined,
workspaceUUID: workspace
? anonymizationEnabled
? anonymize(workspace.id)
: workspace.id
: undefined,
workspaceDisplayName: workspace ? workspace.displayName : undefined,
workspaceDomainName: workspace ? workspace.domainName : undefined,
...createEventInput.data,
},
};
try {
await this.httpService.axiosRef.post('/v1', data);
} catch {}
return { success: true };
}
}

View File

@ -0,0 +1,16 @@
import { ArgsType, Field } from '@nestjs/graphql';
import graphqlTypeJson from 'graphql-type-json';
import { IsNotEmpty, IsString, IsObject } from 'class-validator';
@ArgsType()
export class CreateAnalyticsInput {
@Field({ description: 'Type of the event' })
@IsNotEmpty()
@IsString()
type: string;
@Field(() => graphqlTypeJson, { description: 'Event data in JSON format' })
@IsObject()
data: JSON;
}