From 14f536fb7a647fdaabcdc52781bc4e24c7b5f4b7 Mon Sep 17 00:00:00 2001 From: LucasLvy Date: Fri, 28 Jun 2024 18:29:14 +0200 Subject: [PATCH] feat(backend): user from address --- backend/src/routes/getUser.ts | 43 ++++++++++++++++++ backend/src/routes/index.ts | 2 + backend/test/getUser.test.ts | 83 +++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 backend/src/routes/getUser.ts create mode 100644 backend/test/getUser.test.ts diff --git a/backend/src/routes/getUser.ts b/backend/src/routes/getUser.ts new file mode 100644 index 00000000..ae6ad3c6 --- /dev/null +++ b/backend/src/routes/getUser.ts @@ -0,0 +1,43 @@ +import { eq } from 'drizzle-orm/pg-core/expressions' +import type { FastifyInstance } from 'fastify' + +import { registration } from '@/db/schema' + +import { addressRegex } from '.' + +export function getUserRoute(fastify: FastifyInstance) { + fastify.get( + '/get_user', + + async (request, reply) => { + const { address } = request.query as { address?: string } + + if (!address) { + return reply.status(400).send({ message: 'Address is required' }) + } + + // Validate address format + if (!addressRegex.test(address)) { + return reply.status(400).send({ message: 'Invalid address format' }) + } + + try { + const user = await fastify.db + .select({ user: registration.nickname }) + .from(registration) + .where(eq(registration.contract_address, address)) + .limit(1) + .execute() + + if (!user.length) { + return reply.status(404).send({ message: 'User not found.' }) + } + + return reply.send(user[0]) + } catch (error) { + console.error(error) + return reply.status(500).send({ message: 'Internal server error' }) + } + }, + ) +} diff --git a/backend/src/routes/index.ts b/backend/src/routes/index.ts index 2cedd198..bee4438f 100644 --- a/backend/src/routes/index.ts +++ b/backend/src/routes/index.ts @@ -13,6 +13,7 @@ import { getHistoricalBalanceRoute } from './getHistoricalBalance' import { getLimitRoute } from './getLimit' import { getOtp } from './getOtp' import { getTransactionHistory } from './getTransactionHistory' +import { getUserRoute } from './getUser' import { verifyOtp } from './verifyOtp' export const addressRegex = /^0x0[0-9a-fA-F]{63}$/ @@ -28,6 +29,7 @@ export function declareRoutes(fastify: FastifyInstance, deployer: Account, twili getClaimRoute(fastify) getLimitRoute(fastify) getExecuteFromOutsideRoute(fastify, deployer) + getUserRoute(fastify) } function getStatusRoute(fastify: FastifyInstance) { diff --git a/backend/test/getUser.test.ts b/backend/test/getUser.test.ts new file mode 100644 index 00000000..a336e78d --- /dev/null +++ b/backend/test/getUser.test.ts @@ -0,0 +1,83 @@ +import { PostgreSqlContainer, type StartedPostgreSqlContainer } from '@testcontainers/postgresql' +import type { FastifyInstance } from 'fastify' +import { afterAll, beforeAll, describe, expect, test } from 'vitest' + +import { buildApp } from '@/app' + +import * as schema from '../src/db/schema' + +describe('GET /get_user route', () => { + let container: StartedPostgreSqlContainer + let app: FastifyInstance + const testAddress = '0x064a24243f2aabae8d2148fa878276e6e6e452e3941b417f3c33b1649ea83e11' + const unknownAddress = '0x064a24243f2aabae8d2148fa878276e6e6e452e3941b417f3c33b1649ea83e12' + const testName = 'Jean Dupont' + + beforeAll(async () => { + container = await new PostgreSqlContainer().start() + const connectionUri = container.getConnectionUri() + app = await buildApp({ + database: { + connectionString: connectionUri, + }, + app: { + port: 8080, + }, + }) + + await app.ready() + await app.db.insert(schema.registration).values([ + { + phone_number: '+33611223344', + contract_address: testAddress, + nickname: testName, + }, + ]) + }) + + afterAll(async () => { + await app.close() + await container.stop() + }) + + test('should return the name for a valid registered address', async () => { + const response = await app.inject({ + method: 'GET', + url: `/get_user?address=${testAddress}`, + }) + + expect(response.statusCode).toBe(200) + expect(response.json()).toHaveProperty('user', testName) + }) + + test('should return an error for an unknown address', async () => { + const response = await app.inject({ + method: 'GET', + url: `/get_user?address=${unknownAddress}`, + }) + + expect(response.statusCode).toBe(404) + expect(response.json()).toHaveProperty('message', 'User not found.') + }) + + test('should return error, invalid address format', async () => { + const invalidAddress = '0x0' + const response = await app.inject({ + method: 'GET', + url: `/get_user?address=${invalidAddress}`, + }) + + expect(response.statusCode).toBe(400) + expect(response.json()).toHaveProperty('message', 'Invalid address format') + }) + + test('should return error, no address provided', async () => { + const response = await app.inject({ + method: 'GET', + url: '/get_user', + }) + + expect(response.statusCode).toBe(400) + expect(response.json()).toHaveProperty('message', 'Address is required') + }) +})