Skip to content

Commit

Permalink
Merge pull request #112 from madfish-solutions/development
Browse files Browse the repository at this point in the history
Release latest changes to production
  • Loading branch information
lourenc authored Aug 29, 2023
2 parents e75f0ae + c2090ef commit 8001700
Show file tree
Hide file tree
Showing 34 changed files with 428 additions and 89 deletions.
3 changes: 3 additions & 0 deletions .env.dist
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ ALICE_BOB_PUBLIC_KEY=
ALICE_BOB_PRIVATE_KEY=
THREE_ROUTE_API_URL=
THREE_ROUTE_API_AUTH_TOKEN=
REDIS_URL=
ADD_NOTIFICATION_USERNAME=
ADD_NOTIFICATION_PASSWORD=
Original file line number Diff line number Diff line change
@@ -1,23 +1,7 @@
import { Notification, NotificationType, PlatformType } from './notification.interface';
import { DEFAULT_IMAGE_URLS } from '../../../src/notifications/default-image-fallbacks';
import { Notification, NotificationType, PlatformType } from '../../../src/notifications/notification.interface';

const BANNERS_BUCKET_URL = 'https://generic-objects.fra1.digitaloceanspaces.com/notification-icons';

const DEFAULT_BANNER_URLS = {
extension: {
news: `${BANNERS_BUCKET_URL}/extension/news.svg`,
platformUpdate: `${BANNERS_BUCKET_URL}/extension/platform-update.svg`,
securityNote: `${BANNERS_BUCKET_URL}/extension/security-note.svg`,
winNft: `${BANNERS_BUCKET_URL}/extension/extension-win-nft.svg`
},
mobile: {
news: `${BANNERS_BUCKET_URL}/mobile/news.svg`,
platformUpdate: `${BANNERS_BUCKET_URL}/mobile/platform-update.svg`,
securityNote: `${BANNERS_BUCKET_URL}/mobile/security-note.svg`,
winNft: `${BANNERS_BUCKET_URL}/mobile/mobile-win-nft.svg`
}
};

export const NOTIFICATIONS_LIST: Notification[] = [
export const DEFAULT_NOTIFICATIONS_LIST: Notification[] = [
{
id: 4,
createdAt: '2022-12-29T16:00:00.000Z',
Expand All @@ -35,8 +19,8 @@ export const NOTIFICATIONS_LIST: Notification[] = [
'\n',
'Check whether your mobile app has the latest version.'
],
extensionImageUrl: DEFAULT_BANNER_URLS.extension.news,
mobileImageUrl: DEFAULT_BANNER_URLS.mobile.news
extensionImageUrl: DEFAULT_IMAGE_URLS.extension.news,
mobileImageUrl: DEFAULT_IMAGE_URLS.mobile.news
},
{
id: 3,
Expand All @@ -62,8 +46,8 @@ export const NOTIFICATIONS_LIST: Notification[] = [
url: 'https://story.madfish.solutions/discover-the-tezos-nft-world-and-stand-a-chance-to-win-an-nft-artwork-by-the-famous-artist-mario-klingemann/'
}
],
extensionImageUrl: DEFAULT_BANNER_URLS.extension.winNft,
mobileImageUrl: DEFAULT_BANNER_URLS.mobile.winNft
extensionImageUrl: DEFAULT_IMAGE_URLS.extension.winNft,
mobileImageUrl: DEFAULT_IMAGE_URLS.mobile.winNft
}
];

Expand Down Expand Up @@ -99,8 +83,9 @@ export const MANDATORY_NOTIFICATIONS_LIST: Notification[] = [
{ text: 'here', url: 'https://madfish.crunch.help/temple-wallet/a-note-on-security' },
'.'
],
extensionImageUrl: DEFAULT_BANNER_URLS.extension.securityNote,
mobileImageUrl: DEFAULT_BANNER_URLS.mobile.securityNote
extensionImageUrl: DEFAULT_IMAGE_URLS.extension.securityNote,
mobileImageUrl: DEFAULT_IMAGE_URLS.mobile.securityNote,
isMandatory: true
},
{
id: 1,
Expand Down Expand Up @@ -132,8 +117,9 @@ export const MANDATORY_NOTIFICATIONS_LIST: Notification[] = [
{ text: 'here', url: 'https://madfish.crunch.help/temple-wallet/a-note-on-security' },
'.'
],
extensionImageUrl: DEFAULT_BANNER_URLS.extension.securityNote,
mobileImageUrl: DEFAULT_BANNER_URLS.mobile.securityNote
extensionImageUrl: DEFAULT_IMAGE_URLS.extension.securityNote,
mobileImageUrl: DEFAULT_IMAGE_URLS.mobile.securityNote,
isMandatory: true
},
{
id: 0,
Expand Down Expand Up @@ -175,7 +161,8 @@ export const MANDATORY_NOTIFICATIONS_LIST: Notification[] = [
{ text: 'Discord', url: 'https://discord.com/invite/qFRZ8kVzkv' },
'. We’re happy to have you!\n'
],
extensionImageUrl: DEFAULT_BANNER_URLS.extension.news,
mobileImageUrl: DEFAULT_BANNER_URLS.mobile.news
extensionImageUrl: DEFAULT_IMAGE_URLS.extension.news,
mobileImageUrl: DEFAULT_IMAGE_URLS.mobile.news,
isMandatory: true
}
];
16 changes: 16 additions & 0 deletions migrations/notifications/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import '../../src/configure';

import { Redis } from 'ioredis';
import { EnvVars } from '../../src/config';
import { addExistingNotificationsToDb } from './utils/add-existing-notifications-to-db';
import logger from '../../src/utils/logger';

const redisClient = new Redis(EnvVars.REDIS_URL);

redisClient.on('error', err => logger.error(err));

(async () => {
await addExistingNotificationsToDb(redisClient);
logger.info('Notifications successfully added to Redis database.');
process.exit(0);
})();
14 changes: 14 additions & 0 deletions migrations/notifications/utils/add-existing-notifications-to-db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Redis } from 'ioredis';

import { DEFAULT_NOTIFICATIONS_LIST, MANDATORY_NOTIFICATIONS_LIST } from '../data/notifications.data';

export const addExistingNotificationsToDb = async (client: Redis) => {
const data = await client.lrange('notifications', 0, -1);
const existingNotifications = [...DEFAULT_NOTIFICATIONS_LIST, ...MANDATORY_NOTIFICATIONS_LIST];

if (data.length === 0) {
for (let i = 0; i < existingNotifications.length; i++) {
await client.rpush('notifications', JSON.stringify(existingNotifications[i]));
}
}
};
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
"@taquito/utils": "14.0.0",
"axios": "^0.27.2",
"bignumber.js": "^9.1.0",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"cross-fetch": "^3.1.5",
"dotenv": "^9.0.2",
"express": "^4.18.2",
"firebase-admin": "^10.0.2",
"ioredis": "^5.3.2",
"memoizee": "^0.4.15",
"pino": "^6.11.2",
"pino-http": "^5.5.0",
Expand All @@ -32,9 +34,11 @@
"ts": "tsc --pretty",
"lint": "eslint ./src --ext .js,.ts",
"lint:fix": "eslint ./src --ext .js,.ts --fix",
"clean": "rimraf dist/"
"clean": "rimraf dist/",
"db-migration": "cd migrations/notifications && npx ts-node index.ts"
},
"devDependencies": {
"@types/body-parser": "^1.19.2",
"@types/express": "^4.17.17",
"@types/express-jwt": "^7.4.2",
"@types/express-unless": "^2.0.1",
Expand Down
30 changes: 13 additions & 17 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,17 @@ import { isDefined } from './utils/helpers';
export const MIN_IOS_APP_VERSION = '1.10.445';
export const MIN_ANDROID_APP_VERSION = '1.10.445';

export const MOONPAY_SECRET_KEY = getEnv('MOONPAY_SECRET_KEY');
export const ALICE_BOB_PRIVATE_KEY = getEnv('ALICE_BOB_PRIVATE_KEY');
export const ALICE_BOB_PUBLIC_KEY = getEnv('ALICE_BOB_PUBLIC_KEY');
export const THREE_ROUTE_API_URL = getEnv('THREE_ROUTE_API_URL');
export const THREE_ROUTE_API_AUTH_TOKEN = getEnv('THREE_ROUTE_API_AUTH_TOKEN');
export const EnvVars = {
MOONPAY_SECRET_KEY: getEnv('MOONPAY_SECRET_KEY'),
ALICE_BOB_PRIVATE_KEY: getEnv('ALICE_BOB_PRIVATE_KEY'),
ALICE_BOB_PUBLIC_KEY: getEnv('ALICE_BOB_PUBLIC_KEY'),
THREE_ROUTE_API_URL: getEnv('THREE_ROUTE_API_URL'),
THREE_ROUTE_API_AUTH_TOKEN: getEnv('THREE_ROUTE_API_AUTH_TOKEN'),
REDIS_URL: getEnv('REDIS_URL'),
ADD_NOTIFICATION_USERNAME: getEnv('ADD_NOTIFICATION_USERNAME'),
ADD_NOTIFICATION_PASSWORD: getEnv('ADD_NOTIFICATION_PASSWORD')
};

const variablesToAssert = [
{ name: 'MOONPAY_SECRET_KEY', value: MOONPAY_SECRET_KEY },
{ name: 'ALICE_BOB_PRIVATE_KEY', value: ALICE_BOB_PRIVATE_KEY },
{ name: 'ALICE_BOB_PUBLIC_KEY', value: ALICE_BOB_PUBLIC_KEY },
{ name: 'THREE_ROUTE_API_URL', value: THREE_ROUTE_API_URL },
{ name: 'THREE_ROUTE_API_AUTH_TOKEN', value: THREE_ROUTE_API_AUTH_TOKEN }
];
variablesToAssert.forEach(({ name, value }) => {
if (!isDefined(value)) {
throw new Error(`process.env.${name} not found.`);
}
});
for (const name in EnvVars) {
if (!isDefined(EnvVars[name])) throw new Error(`process.env.${name} is not set.`);
}
59 changes: 54 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require('./configure');

import bodyParser from 'body-parser';
import cors from 'cors';
import express, { Request, Response } from 'express';
import firebaseAdmin from 'firebase-admin';
Expand All @@ -9,16 +10,21 @@ import pinoHttp from 'pino-http';
import { getAdvertisingInfo } from './advertising/advertising';
import { MIN_ANDROID_APP_VERSION, MIN_IOS_APP_VERSION } from './config';
import getDAppsStats from './getDAppsStats';
import { PlatformType } from './notifications/notification.interface';
import { getNotifications } from './notifications/notifications.utils';
import { basicAuth } from './middlewares/basic-auth.middleware';
import { Notification, PlatformType } from './notifications/notification.interface';
import { getImageFallback } from './notifications/utils/get-image-fallback.util';
import { getNotifications } from './notifications/utils/get-notifications.util';
import { getParsedContent } from './notifications/utils/get-parsed-content.util';
import { getPlatforms } from './notifications/utils/get-platforms.util';
import { redisClient } from './redis';
import { getABData } from './utils/ab-test';
import { cancelAliceBobOrder } from './utils/alice-bob/cancel-alice-bob-order';
import { createAliceBobOrder } from './utils/alice-bob/create-alice-bob-order';
import { estimateAliceBobOutput } from './utils/alice-bob/estimate-alice-bob-output';
import { getAliceBobOrderInfo } from './utils/alice-bob/get-alice-bob-order-info';
import { getAliceBobPairInfo } from './utils/alice-bob/get-alice-bob-pair-info';
import { coinGeckoTokens } from './utils/gecko-tokens';
import { getExternalApiErrorPayload } from './utils/helpers';
import { getExternalApiErrorPayload, isDefined, isNonEmptyString } from './utils/helpers';
import logger from './utils/logger';
import { getSignedMoonPayUrl } from './utils/moonpay/get-signed-moonpay-url';
import SingleQueryDataProvider from './utils/SingleQueryDataProvider';
Expand Down Expand Up @@ -50,6 +56,7 @@ const PINO_LOGGER = {
const app = express();
app.use(pinoHttp(PINO_LOGGER));
app.use(cors());
app.use(bodyParser.json());

const dAppsProvider = new SingleQueryDataProvider(15 * 60 * 1000, getDAppsStats);

Expand Down Expand Up @@ -91,10 +98,11 @@ app.get('/api/top-coins', (_req, res) => {
res.status(200).send(coinGeckoTokens);
});

app.get('/api/notifications', (_req, res) => {
app.get('/api/notifications', async (_req, res) => {
try {
const { platform, startFromTime } = _req.query;
const data = getNotifications(
const data = await getNotifications(
redisClient,
platform === PlatformType.Mobile ? PlatformType.Mobile : PlatformType.Extension,
Number(startFromTime) ?? 0
);
Expand All @@ -105,6 +113,47 @@ app.get('/api/notifications', (_req, res) => {
}
});

app.post('/api/notifications', basicAuth, async (req, res) => {
try {
const {
mobile,
extension,
type,
title,
description,
extensionImageUrl,
mobileImageUrl,
content,
date,
expirationDate,
isMandatory
} = req.body;

const newNotification: Notification = {
id: Date.now(),
createdAt: date,
type,
platforms: getPlatforms(mobile, extension),
language: 'en-US',
title,
description,
content: getParsedContent(content),
extensionImageUrl: isNonEmptyString(extensionImageUrl)
? extensionImageUrl
: getImageFallback(PlatformType.Extension, type),
mobileImageUrl: isNonEmptyString(mobileImageUrl) ? mobileImageUrl : getImageFallback(PlatformType.Mobile, type),
expirationDate,
isMandatory: isDefined(isMandatory)
};

await redisClient.lpush('notifications', JSON.stringify(newNotification));

res.status(200).send({ message: 'Notification added successfully' });
} catch (error: any) {
res.status(500).send({ error: error.message });
}
});

app.get('/api/dapps', makeProviderDataRequestHandler(dAppsProvider));

app.get('/api/abtest', (_, res) => {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
25 changes: 25 additions & 0 deletions src/middlewares/basic-auth.middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Request, Response, NextFunction } from 'express';

import { EnvVars } from '../config';
import { isDefined } from '../utils/helpers';

export const basicAuth = (req: Request, res: Response, next: NextFunction) => {
const base64EncodedCredentials = req.get('Authorization');

if (isDefined(base64EncodedCredentials)) {
const [username, password] = Buffer.from(base64EncodedCredentials.split(' ')[1], 'base64').toString().split(':');

if (!(username === EnvVars.ADD_NOTIFICATION_USERNAME && password === EnvVars.ADD_NOTIFICATION_PASSWORD)) {
handleNotAuthenticated(res, next);
}
next();
} else {
handleNotAuthenticated(res, next);
}
};

const handleNotAuthenticated = (res: Response, next: NextFunction) => {
const err = new Error('Not Authenticated!');
res.status(401).set('WWW-Authenticate', 'Basic');
next(err);
};
16 changes: 16 additions & 0 deletions src/notifications/default-image-fallbacks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const IMAGES_BUCKET_URL = 'https://generic-objects.fra1.digitaloceanspaces.com/notification-icons';

export const DEFAULT_IMAGE_URLS = {
extension: {
news: `${IMAGES_BUCKET_URL}/extension/news.svg`,
platformUpdate: `${IMAGES_BUCKET_URL}/extension/platform-update.svg`,
securityNote: `${IMAGES_BUCKET_URL}/extension/security-note.svg`,
winNft: `${IMAGES_BUCKET_URL}/extension/extension-win-nft.svg`
},
mobile: {
news: `${IMAGES_BUCKET_URL}/mobile/news.svg`,
platformUpdate: `${IMAGES_BUCKET_URL}/mobile/platform-update.svg`,
securityNote: `${IMAGES_BUCKET_URL}/mobile/security-note.svg`,
winNft: `${IMAGES_BUCKET_URL}/mobile/mobile-win-nft.svg`
}
};
4 changes: 3 additions & 1 deletion src/notifications/notification.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export enum PlatformType {
Extension = 'Extension'
}

interface NotificationLink {
export interface NotificationLink {
text: string;
url: string;
}
Expand All @@ -26,4 +26,6 @@ export interface Notification {
extensionImageUrl: string;
mobileImageUrl: string;
sourceUrl?: string;
expirationDate?: string;
isMandatory?: boolean;
}
11 changes: 0 additions & 11 deletions src/notifications/notifications.utils.ts

This file was deleted.

24 changes: 24 additions & 0 deletions src/notifications/utils/get-image-fallback.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { DEFAULT_IMAGE_URLS } from '../default-image-fallbacks';
import { NotificationType, PlatformType } from '../notification.interface';

export const getImageFallback = (platform: PlatformType, notificationType: NotificationType) => {
if (platform === PlatformType.Mobile) {
switch (notificationType) {
case NotificationType.PlatformUpdate:
return DEFAULT_IMAGE_URLS.mobile.platformUpdate;
case NotificationType.SecurityNote:
return DEFAULT_IMAGE_URLS.mobile.securityNote;
default:
return DEFAULT_IMAGE_URLS.mobile.news;
}
} else {
switch (notificationType) {
case NotificationType.PlatformUpdate:
return DEFAULT_IMAGE_URLS.extension.platformUpdate;
case NotificationType.SecurityNote:
return DEFAULT_IMAGE_URLS.extension.securityNote;
default:
return DEFAULT_IMAGE_URLS.extension.news;
}
}
};
Loading

0 comments on commit 8001700

Please sign in to comment.