Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TW-1442 Add API for sites blacklist for replacing ads #156

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"@types/express": "^4.17.17",
"@types/express-jwt": "^7.4.2",
"@types/express-unless": "^2.0.1",
"@types/lodash": "^4.17.0",
"@types/memoizee": "^0.4.5",
"@types/node": "^18.14.6",
"@types/pino": "^6.3.8",
Expand Down
12 changes: 11 additions & 1 deletion src/advertising/external-ads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ interface AdStylesOverrides {
style: Record<StylePropName, string>;
}

interface ExtVersionConstraints {
export interface ExtVersionConstraints {
extVersion: string;
}

Expand Down Expand Up @@ -138,12 +138,17 @@ export interface AdProviderForAllSitesRule extends ExtVersionConstraints {
providers: string[];
}

export interface ReplaceAdsUrlsBlacklistEntry extends ExtVersionConstraints {
regexes: string[];
}

const AD_PLACES_RULES_KEY = 'ad_places_rules';
const AD_PROVIDERS_BY_SITES_KEY = 'ad_providers_by_sites';
const AD_PROVIDERS_ALL_SITES_KEY = 'ad_providers_all_sites';
const AD_PROVIDERS_LIST_KEY = 'ad_providers_list';
const PERMANENT_AD_PLACES_RULES_KEY = 'permanent_ad_places_rules';
const PERMANENT_NATIVE_AD_PLACES_RULES_KEY = 'permanent_native_ad_places_rules';
const REPLACE_ADS_URLS_BLACKLIST_KEY = 'replace_ads_urls_blacklist';

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

Expand All @@ -164,6 +169,11 @@ export const permanentNativeAdPlacesMethods = objectStorageMethodsFactory<Perman
[]
);

export const replaceAdsUrlsBlacklistMethods = objectStorageMethodsFactory<ReplaceAdsUrlsBlacklistEntry[]>(
REPLACE_ADS_URLS_BLACKLIST_KEY,
[]
);

export const getAdProvidersForAllSites = async () => redisClient.smembers(AD_PROVIDERS_ALL_SITES_KEY);

export const addAdProvidersForAllSites = async (providers: string[]) =>
Expand Down
31 changes: 22 additions & 9 deletions src/routers/slise-ad-rules/ad-places.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
import { Router } from 'express';
import { Request, Router } from 'express';

import {
filterByVersion,
permanentNativeAdPlacesMethods,
permanentAdPlacesMethods,
adPlacesRulesMethods
adPlacesRulesMethods,
PermanentAdPlacesRule,
AdPlacesRule,
ExtVersionConstraints
} from '../../advertising/external-ads';
import { addObjectStorageMethodsToRouter } from '../../utils/express-helpers';
import { transformValues } from '../../utils/helpers';
import {
hostnamesListSchema,
permanentAdPlacesRulesDictionarySchema,
adPlacesRulesDictionarySchema
} from '../../utils/schemas';

const transformAdPlaces = <T extends ExtVersionConstraints>(value: T[], req: Request) =>
filterByVersion(value, req.query.extVersion as string | undefined);
const transformAdPlacesDictionary = <T extends ExtVersionConstraints>(rules: Record<string, T[]>, req: Request) =>
transformValues(rules, value => transformAdPlaces(value, req));

/**
* @swagger
* tags:
Expand Down Expand Up @@ -68,13 +77,14 @@ import {
* type: string
* ExtVersionConstraints:
* type: object
* required:
* - extVersion
* properties:
* extVersion:
* type: string
* description: >
* A range of versions where the rule is applicable. If not specified, the rule is applicable
* for all versions. See the [ranges format](https://www.npmjs.com/package/semver#ranges)
* default: '*'
* AdPlacesRule:
* allOf:
* - $ref: '#/components/schemas/ExtVersionConstraints'
Expand Down Expand Up @@ -420,14 +430,15 @@ export const adPlacesRulesRouter = Router();
* '500':
* $ref: '#/components/responses/ErrorResponse'
*/
addObjectStorageMethodsToRouter(adPlacesRulesRouter, {
addObjectStorageMethodsToRouter<PermanentAdPlacesRule[]>(adPlacesRulesRouter, {
path: '/permanent-native',
methods: permanentNativeAdPlacesMethods,
keyName: 'domain',
objectValidationSchema: permanentAdPlacesRulesDictionarySchema,
keysArrayValidationSchema: hostnamesListSchema,
successfulRemovalMessage: entriesCount => `${entriesCount} entries have been removed`,
transformGotValueFn: (value, req) => filterByVersion(value, req.query.extVersion as string | undefined)
valueTransformFn: transformAdPlaces,
objectTransformFn: transformAdPlacesDictionary
});

/**
Expand Down Expand Up @@ -569,14 +580,15 @@ addObjectStorageMethodsToRouter(adPlacesRulesRouter, {
* '500':
* $ref: '#/components/responses/ErrorResponse'
*/
addObjectStorageMethodsToRouter(adPlacesRulesRouter, {
addObjectStorageMethodsToRouter<PermanentAdPlacesRule[]>(adPlacesRulesRouter, {
path: '/permanent',
methods: permanentAdPlacesMethods,
keyName: 'domain',
objectValidationSchema: permanentAdPlacesRulesDictionarySchema,
keysArrayValidationSchema: hostnamesListSchema,
successfulRemovalMessage: entriesCount => `${entriesCount} entries have been removed`,
transformGotValueFn: (value, req) => filterByVersion(value, req.query.extVersion as string | undefined)
valueTransformFn: transformAdPlaces,
objectTransformFn: transformAdPlacesDictionary
});

/**
Expand Down Expand Up @@ -718,12 +730,13 @@ addObjectStorageMethodsToRouter(adPlacesRulesRouter, {
* '500':
* $ref: '#/components/responses/ErrorResponse'
*/
addObjectStorageMethodsToRouter(adPlacesRulesRouter, {
addObjectStorageMethodsToRouter<AdPlacesRule[]>(adPlacesRulesRouter, {
path: '/',
methods: adPlacesRulesMethods,
keyName: 'domain',
objectValidationSchema: adPlacesRulesDictionarySchema,
keysArrayValidationSchema: hostnamesListSchema,
successfulRemovalMessage: entriesCount => `${entriesCount} entries have been removed`,
transformGotValueFn: (value, req) => filterByVersion(value, req.query.extVersion as string | undefined)
valueTransformFn: transformAdPlaces,
objectTransformFn: transformAdPlacesDictionary
});
2 changes: 2 additions & 0 deletions src/routers/slise-ad-rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Router } from 'express';

import { adPlacesRulesRouter } from './ad-places';
import { adProvidersRouter } from './providers';
import { replaceUrlsBlacklistRouter } from './replace-urls-blacklist';

/**
* @swagger
Expand Down Expand Up @@ -41,3 +42,4 @@ export const adRulesRouter = Router();

adRulesRouter.use('/ad-places', adPlacesRulesRouter);
adRulesRouter.use('/providers', adProvidersRouter);
adRulesRouter.use('/replace-urls-blacklist', replaceUrlsBlacklistRouter);
42 changes: 25 additions & 17 deletions src/routers/slise-ad-rules/providers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Router } from 'express';
import { Request, Router } from 'express';
import { identity } from 'lodash';

import {
addAdProvidersForAllSites,
Expand All @@ -7,12 +8,14 @@ import {
adProvidersMethods,
adProvidersByDomainRulesMethods,
AdProviderSelectorsRule,
filterByVersion
filterByVersion,
AdProvidersByDomainRule
} from '../../advertising/external-ads';
import { basicAuth } from '../../middlewares/basic-auth.middleware';
import { addObjectStorageMethodsToRouter, withBodyValidation, withExceptionHandler } from '../../utils/express-helpers';
import { transformValues } from '../../utils/helpers';
import {
adTypesListSchema,
nonEmptyStringsListSchema,
hostnamesListSchema,
adProvidersByDomainsRulesDictionarySchema,
adProvidersDictionarySchema
Expand Down Expand Up @@ -178,7 +181,7 @@ adProvidersRouter
.post(
basicAuth,
withExceptionHandler(
withBodyValidation(adTypesListSchema, async (req, res) => {
withBodyValidation(nonEmptyStringsListSchema, async (req, res) => {
const providersAddedCount = await addAdProvidersForAllSites(req.body);

res.status(200).send({ message: `${providersAddedCount} providers have been added` });
Expand All @@ -188,7 +191,7 @@ adProvidersRouter
.delete(
basicAuth,
withExceptionHandler(
withBodyValidation(adTypesListSchema, async (req, res) => {
withBodyValidation(nonEmptyStringsListSchema, async (req, res) => {
const providersRemovedCount = await removeAdProvidersForAllSites(req.body);

res.status(200).send({ message: `${providersRemovedCount} providers have been removed` });
Expand Down Expand Up @@ -287,13 +290,15 @@ adProvidersRouter
* '500':
* $ref: '#/components/responses/ErrorResponse'
*/
addObjectStorageMethodsToRouter(adProvidersRouter, {
addObjectStorageMethodsToRouter<AdProvidersByDomainRule[]>(adProvidersRouter, {
path: '/by-sites',
methods: adProvidersByDomainRulesMethods,
keyName: 'domain',
objectValidationSchema: adProvidersByDomainsRulesDictionarySchema,
keysArrayValidationSchema: hostnamesListSchema,
successfulRemovalMessage: entriesCount => `${entriesCount} entries have been removed`
successfulRemovalMessage: entriesCount => `${entriesCount} entries have been removed`,
valueTransformFn: identity,
objectTransformFn: identity
});

/**
Expand Down Expand Up @@ -437,19 +442,22 @@ addObjectStorageMethodsToRouter(adProvidersRouter, {
* '500':
* $ref: '#/components/responses/ErrorResponse'
*/
addObjectStorageMethodsToRouter<AdProviderSelectorsRule[], string[]>(adProvidersRouter, {
const transformAdProviderSelectorsRules = (rules: AdProviderSelectorsRule[], req: Request) =>
Array.from(
new Set(
filterByVersion(rules, req.query.extVersion as string | undefined)
.map(({ selectors }) => selectors)
.flat()
)
);

addObjectStorageMethodsToRouter<AdProviderSelectorsRule[], Record<string, string[]>, string[]>(adProvidersRouter, {
path: '/',
methods: adProvidersMethods,
keyName: 'providerId',
objectValidationSchema: adProvidersDictionarySchema,
keysArrayValidationSchema: adTypesListSchema,
keysArrayValidationSchema: nonEmptyStringsListSchema,
successfulRemovalMessage: entriesCount => `${entriesCount} providers have been removed`,
transformGotValueFn: (rules, req) =>
Array.from(
new Set(
filterByVersion(rules, req.query.extVersion as string | undefined)
.map(({ selectors }) => selectors)
.flat()
)
)
valueTransformFn: transformAdProviderSelectorsRules,
objectTransformFn: (rules, req) => transformValues(rules, value => transformAdProviderSelectorsRules(value, req))
});
Loading
Loading