Skip to content

Commit fc0d150

Browse files
authored
TW-1518: Add an entrypoint for blacklisted Hypelab campaigns (#174)
1 parent 463fd63 commit fc0d150

File tree

6 files changed

+159
-42
lines changed

6 files changed

+159
-42
lines changed

src/advertising/external-ads.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { satisfies as versionSatisfiesRange } from 'semver';
22

3-
import { objectStorageMethodsFactory, redisClient } from '../redis';
3+
import { objectStorageMethodsFactory, setStorageMethodsFactory } from '../redis';
44

55
/** Style properties names that are likely to be unnecessary for banners are skipped */
66
export const stylePropsNames = [
@@ -176,6 +176,7 @@ const PERMANENT_NATIVE_AD_PLACES_RULES_KEY = 'permanent_native_ad_places_rules';
176176
const REPLACE_ADS_URLS_BLACKLIST_KEY = 'replace_ads_urls_blacklist';
177177
const ELEMENTS_TO_HIDE_OR_REMOVE_KEY = 'elements_to_hide_or_remove';
178178
const AD_PROVIDERS_CATEGORIES_KEY = 'ad_providers_categories';
179+
const HYPELAB_CAMPAIGNS_BLACKLIST_KEY = 'hypelab_campaigns_blacklist';
179180

180181
export const adPlacesRulesMethods = objectStorageMethodsFactory<AdPlacesRule[]>(AD_PLACES_RULES_KEY, []);
181182

@@ -210,13 +211,8 @@ export const adProvidersCategoriesMethods = objectStorageMethodsFactory<string[]
210211
'crypto'
211212
]);
212213

213-
export const getAdProvidersForAllSites = async () => redisClient.smembers(AD_PROVIDERS_ALL_SITES_KEY);
214-
215-
export const addAdProvidersForAllSites = async (providers: string[]) =>
216-
redisClient.sadd(AD_PROVIDERS_ALL_SITES_KEY, ...providers);
217-
218-
export const removeAdProvidersForAllSites = async (providers: string[]) =>
219-
redisClient.srem(AD_PROVIDERS_ALL_SITES_KEY, ...providers);
214+
export const adProvidersForAllSitesMethods = setStorageMethodsFactory(AD_PROVIDERS_ALL_SITES_KEY);
215+
export const hypelabCampaignsBlacklistMethods = setStorageMethodsFactory(HYPELAB_CAMPAIGNS_BLACKLIST_KEY);
220216

221217
const FALLBACK_VERSION = '0.0.0';
222218

src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { getPlatforms } from './notifications/utils/get-platforms.util';
2222
import { redisClient } from './redis';
2323
import { evmRouter } from './routers/evm';
2424
import { adRulesRouter } from './routers/slise-ad-rules';
25+
import { templeWalletAdsRouter } from './routers/temple-wallet-ads';
2526
import { getTkeyStats } from './tkey-stats';
2627
import { getABData } from './utils/ab-test';
2728
import { cancelAliceBobOrder } from './utils/alice-bob/cancel-alice-bob-order';
@@ -343,6 +344,8 @@ app.use('/api/slise-ad-rules', adRulesRouter);
343344

344345
app.use('/api/evm', evmRouter);
345346

347+
app.use('/api/temple-wallet-ads', templeWalletAdsRouter);
348+
346349
app.post('/api/magic-square-quest/start', async (req, res) => {
347350
try {
348351
await startMagicSquareQuest(req.body);

src/redis.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,9 @@ export const objectStorageMethodsFactory = <V, F = V>(storageKey: string, fallba
3030
),
3131
removeValues: (keys: string[]) => redisClient.hdel(storageKey, ...keys)
3232
});
33+
34+
export const setStorageMethodsFactory = (storageKey: string) => ({
35+
addValues: (values: string[]) => redisClient.sadd(storageKey, ...values),
36+
removeValues: (values: string[]) => redisClient.srem(storageKey, ...values),
37+
getAllValues: () => redisClient.smembers(storageKey)
38+
});

src/routers/slise-ad-rules/providers.ts

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,19 @@ import { Request, Router } from 'express';
22
import { identity } from 'lodash';
33

44
import {
5-
addAdProvidersForAllSites,
6-
getAdProvidersForAllSites,
7-
removeAdProvidersForAllSites,
5+
adProvidersForAllSitesMethods,
86
adProvidersMethods,
97
adProvidersByDomainRulesMethods,
108
AdProviderSelectorsRule,
119
filterRules,
1210
AdProvidersByDomainRule,
1311
adProvidersCategoriesMethods
1412
} from '../../advertising/external-ads';
15-
import { basicAuth } from '../../middlewares/basic-auth.middleware';
16-
import { addObjectStorageMethodsToRouter, withBodyValidation, withExceptionHandler } from '../../utils/express-helpers';
13+
import {
14+
addObjectStorageMethodsToRouter,
15+
addSetStorageMethodsToRouter,
16+
withExceptionHandler
17+
} from '../../utils/express-helpers';
1718
import { isDefined, transformValues } from '../../utils/helpers';
1819
import {
1920
nonEmptyStringsListSchema,
@@ -204,35 +205,13 @@ export const adProvidersRouter = Router();
204205
* '500':
205206
* $ref: '#/components/responses/ErrorResponse'
206207
*/
207-
adProvidersRouter
208-
.route('/all-sites')
209-
.get(
210-
withExceptionHandler(async (_req, res) => {
211-
const providers = await getAdProvidersForAllSites();
212-
213-
res.status(200).header('Cache-Control', 'public, max-age=300').send(providers);
214-
})
215-
)
216-
.post(
217-
basicAuth,
218-
withExceptionHandler(
219-
withBodyValidation(nonEmptyStringsListSchema, async (req, res) => {
220-
const providersAddedCount = await addAdProvidersForAllSites(req.body);
221-
222-
res.status(200).send({ message: `${providersAddedCount} providers have been added` });
223-
})
224-
)
225-
)
226-
.delete(
227-
basicAuth,
228-
withExceptionHandler(
229-
withBodyValidation(nonEmptyStringsListSchema, async (req, res) => {
230-
const providersRemovedCount = await removeAdProvidersForAllSites(req.body);
231-
232-
res.status(200).send({ message: `${providersRemovedCount} providers have been removed` });
233-
})
234-
)
235-
);
208+
addSetStorageMethodsToRouter(adProvidersRouter, {
209+
path: '/all-sites',
210+
methods: adProvidersForAllSitesMethods,
211+
arrayValidationSchema: nonEmptyStringsListSchema,
212+
successfulAdditionMessage: addedEntriesCount => `${addedEntriesCount} providers have been added`,
213+
successfulRemovalMessage: removedEntriesCount => `${removedEntriesCount} providers have been removed`
214+
});
236215

237216
/**
238217
* @swagger

src/routers/temple-wallet-ads.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { Router } from 'express';
2+
3+
import { hypelabCampaignsBlacklistMethods } from '../advertising/external-ads';
4+
import { addSetStorageMethodsToRouter } from '../utils/express-helpers';
5+
import { nonEmptyStringsListSchema } from '../utils/schemas';
6+
7+
export const templeWalletAdsRouter = Router();
8+
9+
/**
10+
* @swagger
11+
* tags:
12+
* name: Temple Wallet Ads
13+
* /api/temple-wallet-ads/hypelab-campaigns-blacklist:
14+
* get:
15+
* summary: Get the list of blacklisted Hypelab campaigns slugs
16+
* tags:
17+
* - Temple Wallet Ads
18+
* responses:
19+
* '200':
20+
* description: List of blacklisted Hypelab campaigns slugs
21+
* content:
22+
* application/json:
23+
* schema:
24+
* type: array
25+
* items:
26+
* type: string
27+
* example:
28+
* - '3896abb03b'
29+
* '500':
30+
* $ref: '#/components/responses/ErrorResponse'
31+
* post:
32+
* summary: Add Hypelab campaigns slugs to the blacklist
33+
* tags:
34+
* - Temple Wallet Ads
35+
* security:
36+
* - basicAuth: []
37+
* requestBody:
38+
* required: true
39+
* content:
40+
* application/json:
41+
* schema:
42+
* type: array
43+
* items:
44+
* type: string
45+
* example:
46+
* - '3896abb03b'
47+
* responses:
48+
* '200':
49+
* $ref: '#/components/responses/SuccessResponse'
50+
* '400':
51+
* $ref: '#/components/responses/ErrorResponse'
52+
* '401':
53+
* $ref: '#/components/responses/UnauthorizedError'
54+
* '500':
55+
* $ref: '#/components/responses/ErrorResponse'
56+
* delete:
57+
* summary: Remove Hypelab campaigns slugs from the blacklist
58+
* tags:
59+
* - Temple Wallet Ads
60+
* security:
61+
* - basicAuth: []
62+
* requestBody:
63+
* required: true
64+
* content:
65+
* application/json:
66+
* schema:
67+
* type: array
68+
* items:
69+
* type: string
70+
* example:
71+
* - '3896abb03b'
72+
* responses:
73+
* '200':
74+
* $ref: '#/components/responses/SuccessResponse'
75+
* '400':
76+
* $ref: '#/components/responses/ErrorResponse'
77+
* '401':
78+
* $ref: '#/components/responses/UnauthorizedError'
79+
* '500':
80+
* $ref: '#/components/responses/ErrorResponse'
81+
*/
82+
addSetStorageMethodsToRouter(templeWalletAdsRouter, {
83+
path: '/hypelab-campaigns-blacklist',
84+
methods: hypelabCampaignsBlacklistMethods,
85+
arrayValidationSchema: nonEmptyStringsListSchema,
86+
successfulAdditionMessage: slugs => `Added ${slugs} slugs to the blacklist`,
87+
successfulRemovalMessage: slugs => `Removed ${slugs} slugs from the blacklist`
88+
});

src/utils/express-helpers.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ interface ObjectStorageMethods<V> {
1313
removeValues: (keys: string[]) => Promise<number>;
1414
}
1515

16+
interface SetStorageMethods {
17+
addValues: (values: string[]) => Promise<number>;
18+
removeValues: (values: string[]) => Promise<number>;
19+
getAllValues: () => Promise<string[]>;
20+
}
21+
1622
type TypedBodyRequestHandler<T> = (
1723
req: Request<Record<string, string>, unknown, T>,
1824
res: Response,
@@ -103,6 +109,45 @@ interface ObjectStorageMethodsEntrypointsConfig<StoredValue, ObjectResponse, Val
103109
valueTransformFn: (value: StoredValue, req: Request) => ValueResponse;
104110
}
105111

112+
interface SetStorageMethodsEntrypointsConfig {
113+
path: string;
114+
methods: SetStorageMethods;
115+
arrayValidationSchema: IArraySchema<string[], object>;
116+
successfulAdditionMessage: (addedEntriesCount: number) => string;
117+
successfulRemovalMessage: (removedEntriesCount: number) => string;
118+
}
119+
120+
export const addSetStorageMethodsToRouter = (router: Router, config: SetStorageMethodsEntrypointsConfig) => {
121+
const { path, methods, arrayValidationSchema, successfulAdditionMessage, successfulRemovalMessage } = config;
122+
123+
router
124+
.route(path)
125+
.get(
126+
withExceptionHandler(async (_req, res) => {
127+
res
128+
.status(200)
129+
.header('Cache-Control', 'public, max-age=300')
130+
.send(await methods.getAllValues());
131+
})
132+
)
133+
.post(
134+
basicAuth,
135+
withExceptionHandler(
136+
withBodyValidation(arrayValidationSchema, async (req, res) => {
137+
res.status(200).send({ message: successfulAdditionMessage(await methods.addValues(req.body)) });
138+
})
139+
)
140+
)
141+
.delete(
142+
basicAuth,
143+
withExceptionHandler(
144+
withBodyValidation(arrayValidationSchema, async (req, res) => {
145+
res.status(200).send({ message: successfulRemovalMessage(await methods.removeValues(req.body)) });
146+
})
147+
)
148+
);
149+
};
150+
106151
export const addObjectStorageMethodsToRouter = <
107152
StoredValue,
108153
ObjectResponse = Record<string, StoredValue>,

0 commit comments

Comments
 (0)