diff --git a/apps/api/src/app/app.controller.ts b/apps/api/src/app/app.controller.ts index 66052d32..8de71ed4 100644 --- a/apps/api/src/app/app.controller.ts +++ b/apps/api/src/app/app.controller.ts @@ -8,6 +8,7 @@ import { Patch, Post, Put, + Query, Res, UseInterceptors, } from '@nestjs/common'; @@ -59,7 +60,10 @@ export class AppController { @ApiResponse({ status: 200, description: 'Result Report for All the Health Check Services' }) async checkHealth() { return this.healthCheckService.check([ - async () => this.http.pingCheck('RabbitMQ', 'http://localhost:15672/'), + async () => this.http.pingCheck( + "RabbitMQ", + this.configService.get("RABBITMQ_HEALTH_URL") + ), async () => this.http.pingCheck('Basic Check', 'http://localhost:3333/api'), async () => this.redisIndicator.checkHealth('Redis', { type: 'redis', client: this.redis, timeout: 500 }), async () => this.prismaIndicator.isHealthy('Db'), @@ -90,8 +94,8 @@ export class AppController { @Get('/:hashid') @ApiOperation({ summary: 'Redirect Links' }) @ApiResponse({ status: 301, description: 'will be redirected to the specified link'}) - async redirect(@Param('hashid') hashid: string, @Res() res) { - const reRouteURL: string = await this.appService.redirect(hashid); + async redirect(@Param('hashid') hashid: string, @Query() queryParams: Record, @Res() res) { + const reRouteURL: string = await this.appService.redirect(hashid, queryParams); this.clickServiceClient .send('onClick', { hashid: hashid, diff --git a/apps/api/src/app/app.service.spec.ts b/apps/api/src/app/app.service.spec.ts index 9633732d..40ff4258 100644 --- a/apps/api/src/app/app.service.spec.ts +++ b/apps/api/src/app/app.service.spec.ts @@ -11,9 +11,11 @@ import { RedisService } from 'nestjs-redis'; import { AppService } from './app.service'; import { PrismaService } from './prisma.service'; import { TelemetryService } from './telemetry/telemetry.service'; +import { Link } from './app.interface'; describe('AppService', () => { let service: AppService; + let prisma: PrismaService; let mockRedisSet; const mockRedis = { @@ -90,11 +92,36 @@ describe('AppService', () => { .compile(); service = module.get(AppService); + prisma = module.get(PrismaService); }); it('should be defined', () => { expect(service).toBeDefined(); }); + it("should return url with query params appended to it", async () => { + const url = "https://google.com"; + const hashId = "1"; + const queryParams = { + hello: "1234", + world: "5678", + }; + const link: Link = { + id: "1", + user: null, + tags: [], + clicks: 0, + url: url, + hashid: +hashId, + project: null, + customHashId: null, + }; + + prisma.link.findMany = jest.fn().mockResolvedValueOnce([link]); + + expect(await service.redirect(hashId, queryParams)).toBe( + `${url}?hello=1234&world=5678` + ); + }); }); diff --git a/apps/api/src/app/app.service.ts b/apps/api/src/app/app.service.ts index c389dab0..1b97007a 100644 --- a/apps/api/src/app/app.service.ts +++ b/apps/api/src/app/app.service.ts @@ -104,7 +104,7 @@ export class AppService { }); } - async redirect(hashid: string): Promise { + async redirect(hashid: string, queryParams?: Record): Promise { return this.prisma.link.findMany({ where: { OR: [ @@ -122,20 +122,39 @@ export class AppService { take: 1 }) .then(response => { - const url = response[0].url + let url = response[0].url const params = response[0].params const ret = []; this.updateClicks(response[0].hashid.toString()); - if(params == null){ - return url; - }else { + if(params != null){ Object.keys(params).forEach(function(d) { ret.push(encodeURIComponent(d) + '=' + encodeURIComponent(params[d])); }) - return `${url}?${ret.join('&')}` || ''; + url = `${url}?${ret.join('&')}` || ''; } + + if (queryParams && Object.keys(queryParams).length) { + if (params == null) { + url += "?"; + } else { + url += "&"; + } + const qparams = []; + Object.keys(queryParams).forEach((d: string) => { + if (Array.isArray(queryParams[d])) { + (queryParams[d] as string[]).forEach(val => { + qparams.push(encodeURIComponent(d) + "=" + encodeURIComponent(val)); + }); + } else { + qparams.push(encodeURIComponent(d) + "=" + encodeURIComponent(queryParams[d] as string)); + } + }); + url += qparams.join("&") || ""; + } + + return url; }) .catch(err => { this.telemetryService.sendEvent(this.configService.get('POSTHOG_DISTINCT_KEY'), "Exception in getLinkFromHashIdOrCustomHashId query", {error: err.message}) diff --git a/sample.env b/sample.env index 7c727095..e3157e71 100644 --- a/sample.env +++ b/sample.env @@ -18,6 +18,8 @@ POSTHOG_BATCH_SIZE=20 POSTHOG_FLUSH_INTERVAL=10000 CLICK_BACKUP_CRON='* * 1 * * *' +RABBITMQ_HEALTH_URL=http://localhost:15672/ + # This was inserted by `prisma init`: # Environment variables declared in this file are automatically made available to Prisma. # See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema @@ -25,4 +27,4 @@ CLICK_BACKUP_CRON='* * 1 * * *' # Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB (Preview). # See the documentation for all the connection string options: https://pris.ly/d/connection-strings -DATABASE_URL="postgresql://postgres:yoursupersecret@localhost:5432/shortdb?schema=public" \ No newline at end of file +DATABASE_URL="postgresql://postgres:yoursupersecret@localhost:5432/shortdb?schema=public"