Merge branch 'main' of github.com:ghostfolio/ghostfolio
All checks were successful
Docker image CD / build_and_push (push) Successful in 21m57s
All checks were successful
Docker image CD / build_and_push (push) Successful in 21m57s
This commit is contained in:
commit
c393aeeb9a
@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgraded `nestjs` from version `10.4.15` to `11.0.12`
|
||||
|
||||
## 2.161.0 - 2025-05-06
|
||||
|
||||
### Added
|
||||
|
@ -21,10 +21,13 @@ export class ApiKeyStrategy extends PassportStrategy(
|
||||
private readonly prismaService: PrismaService,
|
||||
private readonly userService: UserService
|
||||
) {
|
||||
super(
|
||||
{ header: HEADER_KEY_TOKEN, prefix: 'Api-Key ' },
|
||||
true,
|
||||
async (apiKey: string, done: (error: any, user?: any) => void) => {
|
||||
super({ header: HEADER_KEY_TOKEN, prefix: 'Api-Key ' }, true);
|
||||
}
|
||||
|
||||
public async validate(
|
||||
apiKey: string,
|
||||
done: (error: any, user?: any) => void
|
||||
) {
|
||||
try {
|
||||
const user = await this.validateApiKey(apiKey);
|
||||
|
||||
@ -51,8 +54,6 @@ export class ApiKeyStrategy extends PassportStrategy(
|
||||
done(error, null);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private async validateApiKey(apiKey: string) {
|
||||
if (!apiKey) {
|
||||
|
@ -1,17 +1,16 @@
|
||||
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
|
||||
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
|
||||
|
||||
import { createKeyv } from '@keyv/redis';
|
||||
import { CacheModule } from '@nestjs/cache-manager';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { redisStore } from 'cache-manager-redis-yet';
|
||||
import type { RedisClientOptions } from 'redis';
|
||||
|
||||
import { RedisCacheService } from './redis-cache.service';
|
||||
|
||||
@Module({
|
||||
exports: [RedisCacheService],
|
||||
imports: [
|
||||
CacheModule.registerAsync<RedisClientOptions>({
|
||||
CacheModule.registerAsync({
|
||||
imports: [ConfigurationModule],
|
||||
inject: [ConfigurationService],
|
||||
useFactory: async (configurationService: ConfigurationService) => {
|
||||
@ -20,10 +19,13 @@ import { RedisCacheService } from './redis-cache.service';
|
||||
);
|
||||
|
||||
return {
|
||||
store: redisStore,
|
||||
ttl: configurationService.get('CACHE_TTL'),
|
||||
url: `redis://${redisPassword ? `:${redisPassword}` : ''}@${configurationService.get('REDIS_HOST')}:${configurationService.get('REDIS_PORT')}/${configurationService.get('REDIS_DB')}`
|
||||
} as RedisClientOptions;
|
||||
stores: [
|
||||
createKeyv(
|
||||
`redis://${redisPassword ? `:${redisPassword}` : ''}@${configurationService.get('REDIS_HOST')}:${configurationService.get('REDIS_PORT')}/${configurationService.get('REDIS_DB')}`
|
||||
)
|
||||
],
|
||||
ttl: configurationService.get('CACHE_TTL')
|
||||
};
|
||||
}
|
||||
}),
|
||||
ConfigurationModule
|
||||
|
@ -2,20 +2,18 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con
|
||||
import { getAssetProfileIdentifier } from '@ghostfolio/common/helper';
|
||||
import { AssetProfileIdentifier, Filter } from '@ghostfolio/common/interfaces';
|
||||
|
||||
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { CACHE_MANAGER, Cache } from '@nestjs/cache-manager';
|
||||
import { Inject, Injectable, Logger } from '@nestjs/common';
|
||||
import { Milliseconds } from 'cache-manager';
|
||||
import { RedisCache } from 'cache-manager-redis-yet';
|
||||
import { createHash } from 'crypto';
|
||||
import ms from 'ms';
|
||||
|
||||
@Injectable()
|
||||
export class RedisCacheService {
|
||||
public constructor(
|
||||
@Inject(CACHE_MANAGER) private readonly cache: RedisCache,
|
||||
@Inject(CACHE_MANAGER) private readonly cache: Cache,
|
||||
private readonly configurationService: ConfigurationService
|
||||
) {
|
||||
const client = cache.store.client;
|
||||
const client = cache.stores[0];
|
||||
|
||||
client.on('error', (error) => {
|
||||
Logger.error(error, 'RedisCacheService');
|
||||
@ -27,13 +25,33 @@ export class RedisCacheService {
|
||||
}
|
||||
|
||||
public async getKeys(aPrefix?: string): Promise<string[]> {
|
||||
let prefix = aPrefix;
|
||||
const keys: string[] = [];
|
||||
const prefix = aPrefix;
|
||||
|
||||
if (prefix) {
|
||||
prefix = `${prefix}*`;
|
||||
this.cache.stores[0].deserialize = (value) => {
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch (error: any) {
|
||||
if (error instanceof SyntaxError) {
|
||||
Logger.debug(
|
||||
`Failed to parse json, returning the value as String: ${value}`,
|
||||
'RedisCacheService'
|
||||
);
|
||||
|
||||
return value;
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for await (const [key] of this.cache.stores[0].iterator({})) {
|
||||
if ((prefix && key.startsWith(prefix)) || !prefix) {
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
return this.cache.store.keys(prefix);
|
||||
return keys;
|
||||
}
|
||||
|
||||
public getPortfolioSnapshotKey({
|
||||
@ -62,10 +80,8 @@ export class RedisCacheService {
|
||||
|
||||
public async isHealthy() {
|
||||
try {
|
||||
const client = this.cache.store.client;
|
||||
|
||||
const isHealthy = await Promise.race([
|
||||
client.ping(),
|
||||
this.getKeys(),
|
||||
new Promise((_, reject) =>
|
||||
setTimeout(
|
||||
() => reject(new Error('Redis health check timeout')),
|
||||
@ -93,16 +109,14 @@ export class RedisCacheService {
|
||||
`${this.getPortfolioSnapshotKey({ userId })}`
|
||||
);
|
||||
|
||||
for (const key of keys) {
|
||||
await this.remove(key);
|
||||
}
|
||||
return this.cache.mdel(keys);
|
||||
}
|
||||
|
||||
public async reset() {
|
||||
return this.cache.reset();
|
||||
return this.cache.clear();
|
||||
}
|
||||
|
||||
public async set(key: string, value: string, ttl?: Milliseconds) {
|
||||
public async set(key: string, value: string, ttl?: number) {
|
||||
return this.cache.set(
|
||||
key,
|
||||
value,
|
||||
|
2932
package-lock.json
generated
2932
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
@ -76,17 +76,18 @@
|
||||
"@dfinity/principal": "0.15.7",
|
||||
"@dinero.js/currencies": "2.0.0-alpha.8",
|
||||
"@internationalized/number": "3.6.0",
|
||||
"@nestjs/bull": "10.2.3",
|
||||
"@nestjs/cache-manager": "2.3.0",
|
||||
"@nestjs/common": "10.4.15",
|
||||
"@nestjs/config": "3.3.0",
|
||||
"@nestjs/core": "10.4.15",
|
||||
"@nestjs/event-emitter": "2.1.1",
|
||||
"@nestjs/jwt": "10.2.0",
|
||||
"@nestjs/passport": "10.0.3",
|
||||
"@nestjs/platform-express": "10.4.15",
|
||||
"@nestjs/schedule": "4.1.2",
|
||||
"@nestjs/serve-static": "4.0.2",
|
||||
"@keyv/redis": "4.3.4",
|
||||
"@nestjs/bull": "11.0.2",
|
||||
"@nestjs/cache-manager": "3.0.1",
|
||||
"@nestjs/common": "11.1.0",
|
||||
"@nestjs/config": "4.0.2",
|
||||
"@nestjs/core": "11.1.0",
|
||||
"@nestjs/event-emitter": "3.0.1",
|
||||
"@nestjs/jwt": "11.0.0",
|
||||
"@nestjs/passport": "11.0.5",
|
||||
"@nestjs/platform-express": "11.1.0",
|
||||
"@nestjs/schedule": "6.0.0",
|
||||
"@nestjs/serve-static": "5.0.3",
|
||||
"@prisma/client": "6.7.0",
|
||||
"@simplewebauthn/browser": "13.1.0",
|
||||
"@simplewebauthn/server": "13.1.1",
|
||||
@ -95,8 +96,6 @@
|
||||
"big.js": "6.2.2",
|
||||
"bootstrap": "4.6.2",
|
||||
"bull": "4.16.5",
|
||||
"cache-manager": "5.7.6",
|
||||
"cache-manager-redis-yet": "5.1.4",
|
||||
"chart.js": "4.4.9",
|
||||
"chartjs-adapter-date-fns": "3.0.0",
|
||||
"chartjs-chart-treemap": "3.1.0",
|
||||
@ -153,8 +152,8 @@
|
||||
"@angular/pwa": "19.2.1",
|
||||
"@eslint/eslintrc": "3.3.1",
|
||||
"@eslint/js": "9.24.0",
|
||||
"@nestjs/schematics": "10.2.3",
|
||||
"@nestjs/testing": "10.4.15",
|
||||
"@nestjs/schematics": "11.0.5",
|
||||
"@nestjs/testing": "11.1.0",
|
||||
"@nx/angular": "20.8.1",
|
||||
"@nx/cypress": "20.8.1",
|
||||
"@nx/eslint-plugin": "20.8.1",
|
||||
@ -173,7 +172,6 @@
|
||||
"@storybook/core-server": "8.6.12",
|
||||
"@trivago/prettier-plugin-sort-imports": "5.2.2",
|
||||
"@types/big.js": "6.2.2",
|
||||
"@types/cache-manager": "4.0.6",
|
||||
"@types/google-spreadsheet": "3.1.5",
|
||||
"@types/jest": "29.5.13",
|
||||
"@types/lodash": "4.17.16",
|
||||
|
Loading…
x
Reference in New Issue
Block a user