mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-14 21:10:34 +01:00
Updated prisma and redis clients.
This commit is contained in:
parent
c05d116875
commit
dff105c747
14
lib/cache.ts
14
lib/cache.ts
@ -1,10 +1,16 @@
|
|||||||
import { User, Website } from '@prisma/client';
|
import { User, Website } from '@prisma/client';
|
||||||
import redis from 'lib/redis';
|
import redis from '@umami/redis-client';
|
||||||
import { getSession, getUser, getWebsite } from '../queries';
|
import { getSession, getUser, getWebsite } from '../queries';
|
||||||
|
|
||||||
|
const DELETED = 'DELETED';
|
||||||
|
|
||||||
async function fetchObject(key, query) {
|
async function fetchObject(key, query) {
|
||||||
const obj = await redis.get(key);
|
const obj = await redis.get(key);
|
||||||
|
|
||||||
|
if (obj === DELETED) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return query().then(async data => {
|
return query().then(async data => {
|
||||||
if (data) {
|
if (data) {
|
||||||
@ -22,8 +28,8 @@ async function storeObject(key, data) {
|
|||||||
return redis.set(key, data);
|
return redis.set(key, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteObject(key) {
|
async function deleteObject(key, soft = false) {
|
||||||
return redis.set(key, redis.DELETED);
|
return soft ? redis.set(key, DELETED) : redis.del(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchWebsite(id): Promise<Website> {
|
async function fetchWebsite(id): Promise<Website> {
|
||||||
@ -42,7 +48,7 @@ async function deleteWebsite(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function fetchUser(id): Promise<User> {
|
async function fetchUser(id): Promise<User> {
|
||||||
return fetchObject(`user:${id}`, () => getUser({ id }, true));
|
return fetchObject(`user:${id}`, () => getUser({ id }, { includePassword: true }));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function storeUser(data) {
|
async function storeUser(data) {
|
||||||
|
@ -4,7 +4,6 @@ export const MYSQL = 'mysql';
|
|||||||
export const CLICKHOUSE = 'clickhouse';
|
export const CLICKHOUSE = 'clickhouse';
|
||||||
export const KAFKA = 'kafka';
|
export const KAFKA = 'kafka';
|
||||||
export const KAFKA_PRODUCER = 'kafka-producer';
|
export const KAFKA_PRODUCER = 'kafka-producer';
|
||||||
export const REDIS = 'redis';
|
|
||||||
|
|
||||||
// Fixes issue with converting bigint values
|
// Fixes issue with converting bigint values
|
||||||
BigInt.prototype.toJSON = function () {
|
BigInt.prototype.toJSON = function () {
|
||||||
|
@ -2,10 +2,10 @@ import { createMiddleware, unauthorized, badRequest, parseSecureToken } from 'ne
|
|||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
import { validate } from 'uuid';
|
import { validate } from 'uuid';
|
||||||
|
import redis from '@umami/redis-client';
|
||||||
import { findSession } from 'lib/session';
|
import { findSession } from 'lib/session';
|
||||||
import { getAuthToken, parseShareToken } from 'lib/auth';
|
import { getAuthToken, parseShareToken } from 'lib/auth';
|
||||||
import { secret } from 'lib/crypto';
|
import { secret } from 'lib/crypto';
|
||||||
import redis from 'lib/redis';
|
|
||||||
import { ROLES } from 'lib/constants';
|
import { ROLES } from 'lib/constants';
|
||||||
import { getUser } from '../queries';
|
import { getUser } from '../queries';
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ export const useSession = createMiddleware(async (req, res, next) => {
|
|||||||
const session = await findSession(req);
|
const session = await findSession(req);
|
||||||
|
|
||||||
if (!session) {
|
if (!session) {
|
||||||
log('useSession:session-not-found');
|
log('useSession: Session not found');
|
||||||
return badRequest(res);
|
return badRequest(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ export const useAuth = createMiddleware(async (req, res, next) => {
|
|||||||
log({ token, payload, user, shareToken });
|
log({ token, payload, user, shareToken });
|
||||||
|
|
||||||
if (!user && !shareToken) {
|
if (!user && !shareToken) {
|
||||||
log('useAuth:user-not-authorized');
|
log('useAuth: User not authorized');
|
||||||
return unauthorized(res);
|
return unauthorized(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import { PrismaClient } from '@prisma/client';
|
import prisma from '@umami/prisma-client';
|
||||||
import chalk from 'chalk';
|
|
||||||
import moment from 'moment-timezone';
|
import moment from 'moment-timezone';
|
||||||
import debug from 'debug';
|
import { MYSQL, POSTGRESQL, getDatabaseType } from 'lib/db';
|
||||||
import { PRISMA, MYSQL, POSTGRESQL, getDatabaseType } from 'lib/db';
|
|
||||||
import { FILTER_IGNORED } from 'lib/constants';
|
import { FILTER_IGNORED } from 'lib/constants';
|
||||||
import { PrismaClientOptions } from '@prisma/client/runtime';
|
|
||||||
|
|
||||||
const MYSQL_DATE_FORMATS = {
|
const MYSQL_DATE_FORMATS = {
|
||||||
minute: '%Y-%m-%d %H:%i:00',
|
minute: '%Y-%m-%d %H:%i:00',
|
||||||
@ -22,39 +19,7 @@ const POSTGRESQL_DATE_FORMATS = {
|
|||||||
year: 'YYYY-01-01',
|
year: 'YYYY-01-01',
|
||||||
};
|
};
|
||||||
|
|
||||||
const log = debug('umami:prisma');
|
function getDateQuery(field: string, unit: string, timezone?: string): string {
|
||||||
|
|
||||||
const PRISMA_OPTIONS = {
|
|
||||||
log: [
|
|
||||||
{
|
|
||||||
emit: 'event',
|
|
||||||
level: 'query',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
function logQuery(e) {
|
|
||||||
log(chalk.yellow(e.params), '->', e.query, chalk.greenBright(`${e.duration}ms`));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getClient(options) {
|
|
||||||
const prisma: PrismaClient<PrismaClientOptions, 'query' | 'error' | 'info' | 'warn'> =
|
|
||||||
new PrismaClient(options);
|
|
||||||
|
|
||||||
if (process.env.LOG_QUERY) {
|
|
||||||
prisma.$on('query', logQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
|
||||||
global[PRISMA] = prisma;
|
|
||||||
}
|
|
||||||
|
|
||||||
log('Prisma initialized');
|
|
||||||
|
|
||||||
return prisma;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDateQuery(field, unit, timezone?): string {
|
|
||||||
const db = getDatabaseType(process.env.DATABASE_URL);
|
const db = getDatabaseType(process.env.DATABASE_URL);
|
||||||
|
|
||||||
if (db === POSTGRESQL) {
|
if (db === POSTGRESQL) {
|
||||||
@ -75,7 +40,7 @@ function getDateQuery(field, unit, timezone?): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTimestampInterval(field): string {
|
function getTimestampInterval(field: string): string {
|
||||||
const db = getDatabaseType(process.env.DATABASE_URL);
|
const db = getDatabaseType(process.env.DATABASE_URL);
|
||||||
|
|
||||||
if (db === POSTGRESQL) {
|
if (db === POSTGRESQL) {
|
||||||
@ -207,7 +172,7 @@ function parseFilters(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function rawQuery(query, params = []): Promise<any> {
|
async function rawQuery(query: string, params: never[] = []): Promise<any> {
|
||||||
const db = getDatabaseType(process.env.DATABASE_URL);
|
const db = getDatabaseType(process.env.DATABASE_URL);
|
||||||
|
|
||||||
if (db !== POSTGRESQL && db !== MYSQL) {
|
if (db !== POSTGRESQL && db !== MYSQL) {
|
||||||
@ -216,20 +181,11 @@ async function rawQuery(query, params = []): Promise<any> {
|
|||||||
|
|
||||||
const sql = db === MYSQL ? query.replace(/\$[0-9]+/g, '?') : query;
|
const sql = db === MYSQL ? query.replace(/\$[0-9]+/g, '?') : query;
|
||||||
|
|
||||||
return prisma.$queryRawUnsafe.apply(prisma, [sql, ...params]);
|
return prisma.rawQuery(sql, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function transaction(queries): Promise<any> {
|
|
||||||
return prisma.$transaction(queries);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialization
|
|
||||||
const prisma: PrismaClient<PrismaClientOptions, 'query' | 'error' | 'info' | 'warn'> =
|
|
||||||
global[PRISMA] || getClient(PRISMA_OPTIONS);
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
client: prisma,
|
...prisma,
|
||||||
log,
|
|
||||||
getDateQuery,
|
getDateQuery,
|
||||||
getTimestampInterval,
|
getTimestampInterval,
|
||||||
getFilterQuery,
|
getFilterQuery,
|
||||||
@ -237,5 +193,4 @@ export default {
|
|||||||
getEventDataFilterQuery,
|
getEventDataFilterQuery,
|
||||||
parseFilters,
|
parseFilters,
|
||||||
rawQuery,
|
rawQuery,
|
||||||
transaction,
|
|
||||||
};
|
};
|
||||||
|
62
lib/redis.js
62
lib/redis.js
@ -1,62 +0,0 @@
|
|||||||
import { createClient } from 'redis';
|
|
||||||
import debug from 'debug';
|
|
||||||
|
|
||||||
const log = debug('umami:redis');
|
|
||||||
const REDIS = Symbol();
|
|
||||||
const DELETED = 'DELETED';
|
|
||||||
|
|
||||||
let redis;
|
|
||||||
const url = process.env.REDIS_URL;
|
|
||||||
const enabled = Boolean(url);
|
|
||||||
|
|
||||||
async function getClient() {
|
|
||||||
if (!enabled) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const client = createClient({ url });
|
|
||||||
client.on('error', err => log(err));
|
|
||||||
await client.connect();
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
|
||||||
global[REDIS] = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
log('Redis initialized');
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function get(key) {
|
|
||||||
await connect();
|
|
||||||
|
|
||||||
const data = await redis.get(key);
|
|
||||||
|
|
||||||
try {
|
|
||||||
return JSON.parse(data);
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function set(key, value) {
|
|
||||||
await connect();
|
|
||||||
|
|
||||||
return redis.set(key, JSON.stringify(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
async function del(key) {
|
|
||||||
await connect();
|
|
||||||
|
|
||||||
return redis.del(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function connect() {
|
|
||||||
if (!redis && enabled) {
|
|
||||||
redis = global[REDIS] || (await getClient());
|
|
||||||
}
|
|
||||||
|
|
||||||
return redis;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default { enabled, client: redis, log, connect, get, set, del, DELETED };
|
|
@ -61,6 +61,8 @@
|
|||||||
"@fontsource/inter": "4.5.7",
|
"@fontsource/inter": "4.5.7",
|
||||||
"@prisma/client": "4.8.0",
|
"@prisma/client": "4.8.0",
|
||||||
"@tanstack/react-query": "^4.16.1",
|
"@tanstack/react-query": "^4.16.1",
|
||||||
|
"@umami/prisma-client": "^0.1.0",
|
||||||
|
"@umami/redis-client": "^0.1.0",
|
||||||
"chalk": "^4.1.1",
|
"chalk": "^4.1.1",
|
||||||
"chart.js": "^2.9.4",
|
"chart.js": "^2.9.4",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
|
@ -7,9 +7,9 @@ import {
|
|||||||
methodNotAllowed,
|
methodNotAllowed,
|
||||||
getRandomChars,
|
getRandomChars,
|
||||||
} from 'next-basics';
|
} from 'next-basics';
|
||||||
|
import redis from '@umami/redis-client';
|
||||||
import { getUser, User } from 'queries';
|
import { getUser, User } from 'queries';
|
||||||
import { secret } from 'lib/crypto';
|
import { secret } from 'lib/crypto';
|
||||||
import redis from 'lib/redis';
|
|
||||||
import { NextApiRequestQueryBody } from 'lib/types';
|
import { NextApiRequestQueryBody } from 'lib/types';
|
||||||
import { NextApiResponse } from 'next';
|
import { NextApiResponse } from 'next';
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { methodNotAllowed, ok } from 'next-basics';
|
import { methodNotAllowed, ok } from 'next-basics';
|
||||||
|
import redis from '@umami/redis-client';
|
||||||
import { useAuth } from 'lib/middleware';
|
import { useAuth } from 'lib/middleware';
|
||||||
import redis from 'lib/redis';
|
|
||||||
import { getAuthToken } from 'lib/auth';
|
import { getAuthToken } from 'lib/auth';
|
||||||
import { NextApiRequest, NextApiResponse } from 'next';
|
import { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
|
||||||
|
17
yarn.lock
17
yarn.lock
@ -2290,6 +2290,21 @@
|
|||||||
"@typescript-eslint/types" "5.45.0"
|
"@typescript-eslint/types" "5.45.0"
|
||||||
eslint-visitor-keys "^3.3.0"
|
eslint-visitor-keys "^3.3.0"
|
||||||
|
|
||||||
|
"@umami/prisma-client@^0.1.0":
|
||||||
|
version "0.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@umami/prisma-client/-/prisma-client-0.1.0.tgz#4ecc17b1998cb738b8f2027b80b003864beef6a4"
|
||||||
|
integrity sha512-2qTXN0dtMUT+HVhz37eVC02lDSwz9TGUGHRRO0LPRHdfJPfSkUF0D8pgksX7ETy3IZoIQP1h45tiXsM0pKBMZA==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.3.4"
|
||||||
|
|
||||||
|
"@umami/redis-client@^0.1.0":
|
||||||
|
version "0.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@umami/redis-client/-/redis-client-0.1.0.tgz#69599b1243406a3aef83927bb8655a3ef4c0c031"
|
||||||
|
integrity sha512-XCqCdc3xA5KDOorIUvOVlz+/F/SEyL9cKWfCCGYYZix1b9yFo+5BzM0C0q7Yu/qV+1jYd+viNsBQQSM6a8sfjg==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.3.4"
|
||||||
|
redis "^4.5.1"
|
||||||
|
|
||||||
"@vercel/node-bridge@^2.1.0":
|
"@vercel/node-bridge@^2.1.0":
|
||||||
version "2.2.2"
|
version "2.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/@vercel/node-bridge/-/node-bridge-2.2.2.tgz#f63466ab6a2588afdc6262c2d060289bfe8baa6b"
|
resolved "https://registry.yarnpkg.com/@vercel/node-bridge/-/node-bridge-2.2.2.tgz#f63466ab6a2588afdc6262c2d060289bfe8baa6b"
|
||||||
@ -6632,7 +6647,7 @@ redis-parser@^3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
redis-errors "^1.0.0"
|
redis-errors "^1.0.0"
|
||||||
|
|
||||||
redis@^4.5.0:
|
redis@^4.5.0, redis@^4.5.1:
|
||||||
version "4.5.1"
|
version "4.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/redis/-/redis-4.5.1.tgz#f5a818970bb2dc5d60540bab41308640604c7d33"
|
resolved "https://registry.yarnpkg.com/redis/-/redis-4.5.1.tgz#f5a818970bb2dc5d60540bab41308640604c7d33"
|
||||||
integrity sha512-oxXSoIqMJCQVBTfxP6BNTCtDMyh9G6Vi5wjdPdV/sRKkufyZslDqCScSGcOr6XGR/reAWZefz7E4leM31RgdBA==
|
integrity sha512-oxXSoIqMJCQVBTfxP6BNTCtDMyh9G6Vi5wjdPdV/sRKkufyZslDqCScSGcOr6XGR/reAWZefz7E4leM31RgdBA==
|
||||||
|
Loading…
x
Reference in New Issue
Block a user