mirror of
https://github.com/seerr-team/seerr.git
synced 2026-10-12 02:22:17 +00:00
fix(datasource): register entities and subscribers explicitly (#3375)
This commit is contained in:
+1
-1
@@ -7,7 +7,7 @@
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"postinstall": "next telemetry disable",
|
||||
"dev": "nodemon -e ts,json,yml --watch server --watch seerr-api.yml --exec 'ts-node -r tsconfig-paths/register --files --project server/tsconfig.json server/index.ts'",
|
||||
"build:server": "tsc --project server/tsconfig.json && copyfiles -u 2 server/templates/**/*.{html,pug} dist/templates && copyfiles -u 2 \"server/i18n/locale/*.json\" dist/i18n && tsc-alias -p server/tsconfig.json",
|
||||
"build:server": "tsc --project server/tsconfig.build.json && copyfiles -u 2 server/templates/**/*.{html,pug} dist/templates && copyfiles -u 2 \"server/i18n/locale/*.json\" dist/i18n && tsc-alias -p server/tsconfig.build.json",
|
||||
"build:next": "next build",
|
||||
"build": "pnpm build:next && pnpm build:server",
|
||||
"lint": "eslint \"./server/**/*.{ts,tsx}\" \"./src/**/*.{ts,tsx}\" --cache",
|
||||
|
||||
+52
-10
@@ -1,3 +1,21 @@
|
||||
import { Blocklist } from '@server/entity/Blocklist';
|
||||
import DiscoverSlider from '@server/entity/DiscoverSlider';
|
||||
import Issue from '@server/entity/Issue';
|
||||
import IssueComment from '@server/entity/IssueComment';
|
||||
import Media from '@server/entity/Media';
|
||||
import { MediaRequest } from '@server/entity/MediaRequest';
|
||||
import OverrideRule from '@server/entity/OverrideRule';
|
||||
import Season from '@server/entity/Season';
|
||||
import SeasonRequest from '@server/entity/SeasonRequest';
|
||||
import { Session } from '@server/entity/Session';
|
||||
import { User } from '@server/entity/User';
|
||||
import { UserPushSubscription } from '@server/entity/UserPushSubscription';
|
||||
import { UserSettings } from '@server/entity/UserSettings';
|
||||
import { Watchlist } from '@server/entity/Watchlist';
|
||||
import { IssueCommentSubscriber } from '@server/subscriber/IssueCommentSubscriber';
|
||||
import { IssueSubscriber } from '@server/subscriber/IssueSubscriber';
|
||||
import { MediaRequestSubscriber } from '@server/subscriber/MediaRequestSubscriber';
|
||||
import { MediaSubscriber } from '@server/subscriber/MediaSubscriber';
|
||||
import fs from 'fs';
|
||||
import type { TlsOptions } from 'tls';
|
||||
import type { DataSourceOptions, EntityTarget, Repository } from 'typeorm';
|
||||
@@ -5,6 +23,30 @@ import { DataSource } from 'typeorm';
|
||||
|
||||
const DB_SSL_PREFIX = 'DB_SSL_';
|
||||
|
||||
const entities = [
|
||||
Blocklist,
|
||||
DiscoverSlider,
|
||||
Issue,
|
||||
IssueComment,
|
||||
Media,
|
||||
MediaRequest,
|
||||
OverrideRule,
|
||||
Season,
|
||||
SeasonRequest,
|
||||
Session,
|
||||
User,
|
||||
UserPushSubscription,
|
||||
UserSettings,
|
||||
Watchlist,
|
||||
];
|
||||
|
||||
const subscribers = [
|
||||
IssueCommentSubscriber,
|
||||
IssueSubscriber,
|
||||
MediaRequestSubscriber,
|
||||
MediaSubscriber,
|
||||
];
|
||||
|
||||
function boolFromEnv(envVar: string, defaultVal = false) {
|
||||
if (process.env[envVar]) {
|
||||
return process.env[envVar]?.toLowerCase() === 'true';
|
||||
@@ -53,9 +95,9 @@ const testConfig: DataSourceOptions = {
|
||||
synchronize: true,
|
||||
dropSchema: true,
|
||||
logging: boolFromEnv('DB_LOG_QUERIES'),
|
||||
entities: ['server/entity/**/*.ts'],
|
||||
entities,
|
||||
migrations: ['server/migration/sqlite/**/*.ts'],
|
||||
subscribers: ['server/subscriber/**/*.ts'],
|
||||
subscribers,
|
||||
};
|
||||
|
||||
const devConfig: DataSourceOptions = {
|
||||
@@ -67,9 +109,9 @@ const devConfig: DataSourceOptions = {
|
||||
migrationsRun: false,
|
||||
logging: boolFromEnv('DB_LOG_QUERIES'),
|
||||
enableWAL: true,
|
||||
entities: ['server/entity/**/*.ts'],
|
||||
entities,
|
||||
migrations: ['server/migration/sqlite/**/*.ts'],
|
||||
subscribers: ['server/subscriber/**/*.ts'],
|
||||
subscribers,
|
||||
};
|
||||
|
||||
const prodConfig: DataSourceOptions = {
|
||||
@@ -81,9 +123,9 @@ const prodConfig: DataSourceOptions = {
|
||||
migrationsRun: false,
|
||||
logging: boolFromEnv('DB_LOG_QUERIES'),
|
||||
enableWAL: true,
|
||||
entities: ['dist/entity/**/*.js'],
|
||||
entities,
|
||||
migrations: ['dist/migration/sqlite/**/*.js'],
|
||||
subscribers: ['dist/subscriber/**/*.js'],
|
||||
subscribers,
|
||||
};
|
||||
|
||||
const postgresDevConfig: DataSourceOptions = {
|
||||
@@ -102,9 +144,9 @@ const postgresDevConfig: DataSourceOptions = {
|
||||
synchronize: false,
|
||||
migrationsRun: true,
|
||||
logging: boolFromEnv('DB_LOG_QUERIES'),
|
||||
entities: ['server/entity/**/*.ts'],
|
||||
entities,
|
||||
migrations: ['server/migration/postgres/**/*.ts'],
|
||||
subscribers: ['server/subscriber/**/*.ts'],
|
||||
subscribers,
|
||||
};
|
||||
|
||||
const postgresProdConfig: DataSourceOptions = {
|
||||
@@ -123,9 +165,9 @@ const postgresProdConfig: DataSourceOptions = {
|
||||
synchronize: false,
|
||||
migrationsRun: false,
|
||||
logging: boolFromEnv('DB_LOG_QUERIES'),
|
||||
entities: ['dist/entity/**/*.js'],
|
||||
entities,
|
||||
migrations: ['dist/migration/postgres/**/*.js'],
|
||||
subscribers: ['dist/subscriber/**/*.js'],
|
||||
subscribers,
|
||||
};
|
||||
|
||||
export const isPgsql = process.env.DB_TYPE === 'postgres';
|
||||
|
||||
@@ -12,6 +12,7 @@ const prepareDb = async () => {
|
||||
await seedTestDb({
|
||||
preserveDb: process.env.PRESERVE_DB === 'true',
|
||||
withMigrations: process.env.WITH_MIGRATIONS === 'true',
|
||||
allowOutsideTest: true,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["**/*.test.ts"]
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { afterEach, describe, it } from 'node:test';
|
||||
|
||||
import { resetTestDb, seedTestDb } from '@server/utils/seedTestDb';
|
||||
|
||||
// NODE_ENV is typed readonly, so it is swapped through the whole env object
|
||||
function setNodeEnv(value: string | undefined) {
|
||||
Object.assign(process.env, { NODE_ENV: value });
|
||||
}
|
||||
|
||||
describe('test database guard', () => {
|
||||
const originalNodeEnv = process.env.NODE_ENV;
|
||||
|
||||
afterEach(() => {
|
||||
setNodeEnv(originalNodeEnv);
|
||||
});
|
||||
|
||||
it('refuses to seed when NODE_ENV is not test', async () => {
|
||||
setNodeEnv('production');
|
||||
|
||||
await assert.rejects(() => seedTestDb(), /Refusing to seed/);
|
||||
});
|
||||
|
||||
it('refuses to reset when NODE_ENV is not test', async () => {
|
||||
setNodeEnv('production');
|
||||
|
||||
await assert.rejects(() => resetTestDb(), /Refusing to reset/);
|
||||
});
|
||||
});
|
||||
@@ -8,6 +8,8 @@ export interface SeedDbOptions {
|
||||
preserveDb?: boolean;
|
||||
/** If true, runs migrations instead of synchronizing schema */
|
||||
withMigrations?: boolean;
|
||||
/** If true, permits seeding while NODE_ENV is not test */
|
||||
allowOutsideTest?: boolean;
|
||||
}
|
||||
|
||||
// Precomputed bcrypt hash of 'test1234'. We precompute this to avoid
|
||||
@@ -15,6 +17,16 @@ export interface SeedDbOptions {
|
||||
const TEST_USER_PASSWORD_HASH =
|
||||
'$2b$12$Z5V2P5HZgmx4/AnWFMZN1.aD5AM1NucNi.mhNTSQ9oVtmdzu7Le/a';
|
||||
|
||||
function assertTestDatabase(operation: string, allowOutsideTest = false): void {
|
||||
if (allowOutsideTest || process.env.NODE_ENV === 'test') {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Refusing to ${operation} while NODE_ENV is not test: this drops every table and seeds accounts with a known password.`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeds test users into the database.
|
||||
* Assumes the database schema is already set up.
|
||||
@@ -68,6 +80,8 @@ async function seedTestUsers(): Promise<void> {
|
||||
* Used by both Cypress tests and Vitest unit tests.
|
||||
*/
|
||||
export async function seedTestDb(options: SeedDbOptions = {}): Promise<void> {
|
||||
assertTestDatabase('seed the test database', options.allowOutsideTest);
|
||||
|
||||
const dbConnection = dataSource.isInitialized
|
||||
? dataSource
|
||||
: await dataSource.initialize();
|
||||
@@ -91,6 +105,8 @@ export async function seedTestDb(options: SeedDbOptions = {}): Promise<void> {
|
||||
* Assumes DB has been initialized.
|
||||
*/
|
||||
export async function resetTestDb(): Promise<void> {
|
||||
assertTestDatabase('reset the test database');
|
||||
|
||||
await dataSource.synchronize(true);
|
||||
await seedTestUsers();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user