Skip to content

Commit

Permalink
feat: add rl to clubs
Browse files Browse the repository at this point in the history
  • Loading branch information
bigint committed Jul 11, 2024
1 parent e4cce65 commit 3d75e5c
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 185 deletions.
89 changes: 48 additions & 41 deletions apps/api/src/routes/badges/hasHeyNft.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Handler } from 'express';
import type { Request, Response } from 'express';
import type { Address } from 'viem';

import { HEY_MEMBERSHIP_NFT_PUBLICATION_ID } from '@hey/data/constants';
Expand All @@ -8,38 +8,41 @@ import randomNumber from '@hey/helpers/randomNumber';
import lensPg from 'src/db/lensPg';
import catchedError from 'src/helpers/catchedError';
import { CACHE_AGE_INDEFINITE } from 'src/helpers/constants';
import { rateLimiter } from 'src/helpers/middlewares/rateLimiter';
import { getRedis, setRedis } from 'src/helpers/redisClient';
import { noBody } from 'src/helpers/responses';
import { getAddress } from 'viem';

export const get: Handler = async (req, res) => {
const { address, id } = req.query;
export const get = [
rateLimiter({ requests: 50, within: 1 }),
async (req: Request, res: Response) => {
const { address, id } = req.query;

if (!id && !address) {
return noBody(res);
}
if (!id && !address) {
return noBody(res);
}

try {
const formattedAddress = address
? getAddress(address as Address)
: undefined;
try {
const formattedAddress = address
? getAddress(address as Address)
: undefined;

const cacheKey = `badge:hey-membership-nft:${id || address}`;
const cachedData = await getRedis(cacheKey);
const cacheKey = `badge:hey-membership-nft:${id || address}`;
const cachedData = await getRedis(cacheKey);

if (cachedData) {
logger.info(
`(cached) Hey NFT badge fetched for ${id || formattedAddress}`
);
if (cachedData) {
logger.info(
`(cached) Hey NFT badge fetched for ${id || formattedAddress}`
);

return res
.status(200)
.setHeader('Cache-Control', CACHE_AGE_INDEFINITE)
.json({ hasHeyNft: true, success: true });
}
return res
.status(200)
.setHeader('Cache-Control', CACHE_AGE_INDEFINITE)
.json({ hasHeyNft: true, success: true });
}

const data = await lensPg.query(
`
const data = await lensPg.query(
`
SELECT EXISTS (
SELECT 1
FROM profile.record p
Expand All @@ -49,25 +52,29 @@ export const get: Handler = async (req, res) => {
AND o.publication_id = $3
) AS result;
`,
[id, formattedAddress, HEY_MEMBERSHIP_NFT_PUBLICATION_ID]
);
[id, formattedAddress, HEY_MEMBERSHIP_NFT_PUBLICATION_ID]
);

const hasHeyNft = data[0]?.result;
const hasHeyNft = data[0]?.result;

if (hasHeyNft) {
await setRedis(
cacheKey,
hasHeyNft,
randomNumber(daysToSeconds(400), daysToSeconds(800))
);
}
logger.info(`Hey NFT badge fetched for ${id || formattedAddress}`);
if (hasHeyNft) {
await setRedis(
cacheKey,
hasHeyNft,
randomNumber(daysToSeconds(400), daysToSeconds(800))
);
}
logger.info(`Hey NFT badge fetched for ${id || formattedAddress}`);

return res
.status(200)
.setHeader('Cache-Control', hasHeyNft ? CACHE_AGE_INDEFINITE : 'no-cache')
.json({ hasHeyNft, success: true });
} catch (error) {
return catchedError(res, error);
return res
.status(200)
.setHeader(
'Cache-Control',
hasHeyNft ? CACHE_AGE_INDEFINITE : 'no-cache'
)
.json({ hasHeyNft, success: true });
} catch (error) {
return catchedError(res, error);
}
}
};
];
92 changes: 48 additions & 44 deletions apps/api/src/routes/badges/isHeyProfile.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Handler } from 'express';
import type { Request, Response } from 'express';
import type { Address } from 'viem';

import { HEY_LENS_SIGNUP } from '@hey/data/constants';
Expand All @@ -8,38 +8,41 @@ import randomNumber from '@hey/helpers/randomNumber';
import lensPg from 'src/db/lensPg';
import catchedError from 'src/helpers/catchedError';
import { CACHE_AGE_INDEFINITE } from 'src/helpers/constants';
import { rateLimiter } from 'src/helpers/middlewares/rateLimiter';
import { getRedis, setRedis } from 'src/helpers/redisClient';
import { noBody } from 'src/helpers/responses';
import { getAddress } from 'viem';

export const get: Handler = async (req, res) => {
const { address, id } = req.query;
export const get = [
rateLimiter({ requests: 50, within: 1 }),
async (req: Request, res: Response) => {
const { address, id } = req.query;

if (!id && !address) {
return noBody(res);
}
if (!id && !address) {
return noBody(res);
}

try {
const formattedAddress = address
? getAddress(address as Address)
: undefined;
try {
const formattedAddress = address
? getAddress(address as Address)
: undefined;

const cacheKey = `badge:hey-profile:${id || address}`;
const cachedData = await getRedis(cacheKey);
const cacheKey = `badge:hey-profile:${id || address}`;
const cachedData = await getRedis(cacheKey);

if (cachedData === 'true') {
logger.info(
`(cached) Hey profile badge fetched for ${id || formattedAddress}`
);
if (cachedData === 'true') {
logger.info(
`(cached) Hey profile badge fetched for ${id || formattedAddress}`
);

return res
.status(200)
.setHeader('Cache-Control', CACHE_AGE_INDEFINITE)
.json({ isHeyProfile: true, success: true });
}
return res
.status(200)
.setHeader('Cache-Control', CACHE_AGE_INDEFINITE)
.json({ isHeyProfile: true, success: true });
}

const data = await lensPg.query(
`
const data = await lensPg.query(
`
SELECT EXISTS (
SELECT 1
FROM profile.record p
Expand All @@ -49,28 +52,29 @@ export const get: Handler = async (req, res) => {
AND o.onboarded_by_address = $3
) AS result;
`,
[id, formattedAddress, HEY_LENS_SIGNUP]
);
[id, formattedAddress, HEY_LENS_SIGNUP]
);

const isHeyProfile = data[0]?.result;
const isHeyProfile = data[0]?.result;

if (isHeyProfile) {
await setRedis(
cacheKey,
isHeyProfile,
randomNumber(daysToSeconds(400), daysToSeconds(800))
);
}
logger.info(`Hey profile badge fetched for ${id || formattedAddress}`);
if (isHeyProfile) {
await setRedis(
cacheKey,
isHeyProfile,
randomNumber(daysToSeconds(400), daysToSeconds(800))
);
}
logger.info(`Hey profile badge fetched for ${id || formattedAddress}`);

return res
.status(200)
.setHeader(
'Cache-Control',
isHeyProfile ? CACHE_AGE_INDEFINITE : 'no-cache'
)
.json({ isHeyProfile, success: true });
} catch (error) {
return catchedError(res, error);
return res
.status(200)
.setHeader(
'Cache-Control',
isHeyProfile ? CACHE_AGE_INDEFINITE : 'no-cache'
)
.json({ isHeyProfile, success: true });
} catch (error) {
return catchedError(res, error);
}
}
};
];
70 changes: 37 additions & 33 deletions apps/api/src/routes/clubs/get.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { Handler } from 'express';
import type { Request, Response } from 'express';

import { CLUBS_API_URL, CLUBS_APP_TOKEN } from '@hey/data/constants';
import logger from '@hey/helpers/logger';
import catchedError from 'src/helpers/catchedError';
import { HEY_USER_AGENT } from 'src/helpers/constants';
import { rateLimiter } from 'src/helpers/middlewares/rateLimiter';
import { invalidBody, noBody } from 'src/helpers/responses';
import { number, object, string } from 'zod';

Expand All @@ -16,36 +17,39 @@ const validationSchema = object({
skip: number().max(50).optional()
});

export const post: Handler = async (req, res) => {
const { body } = req;

if (!body) {
return noBody(res);
}

const validation = validationSchema.safeParse(body);

if (!validation.success) {
return invalidBody(res);
}

try {
const accessToken = req.headers['x-access-token'] as string;
const response = await fetch(`${CLUBS_API_URL}/fetch-clubs`, {
body: JSON.stringify(body),
headers: {
'App-Access-Token': CLUBS_APP_TOKEN,
'Content-Type': 'application/json',
'User-Agent': HEY_USER_AGENT,
'X-Access-Token': accessToken
},
method: 'POST'
});

logger.info(`Clubs fetched for ${body.club_handle}`);

return res.status(response.status).json(await response.json());
} catch (error) {
return catchedError(res, error);
export const post = [
rateLimiter({ requests: 100, within: 1 }),
async (req: Request, res: Response) => {
const { body } = req;

if (!body) {
return noBody(res);
}

const validation = validationSchema.safeParse(body);

if (!validation.success) {
return invalidBody(res);
}

try {
const accessToken = req.headers['x-access-token'] as string;
const response = await fetch(`${CLUBS_API_URL}/fetch-clubs`, {
body: JSON.stringify(body),
headers: {
'App-Access-Token': CLUBS_APP_TOKEN,
'Content-Type': 'application/json',
'User-Agent': HEY_USER_AGENT,
'X-Access-Token': accessToken
},
method: 'POST'
});

logger.info(`Clubs fetched for ${body.club_handle}`);

return res.status(response.status).json(await response.json());
} catch (error) {
return catchedError(res, error);
}
}
};
];
Loading

0 comments on commit 3d75e5c

Please sign in to comment.