mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
refactor(addons): the transit-provider setting and photo-provider routes move into the shared kernel
AddonsService read the transit backend through transit/transit-provider.ts and built photo-provider endpoint paths with memories.helpers, so the addons domain, which nearly every domain imports for its gates, depended on transit and memories. Both are free functions over a repository or plain strings; they move unchanged to common/, where the transit and admin sides read them too.
This commit is contained in:
@@ -3,44 +3,21 @@
|
||||
"domainCycles": [
|
||||
"accommodations -> assignments",
|
||||
"accommodations -> places",
|
||||
"addons -> memories",
|
||||
"addons -> transit",
|
||||
"assignments -> days",
|
||||
"assignments -> journey",
|
||||
"atlas -> addons",
|
||||
"auth -> plugins",
|
||||
"budget -> addons",
|
||||
"days -> accommodations",
|
||||
"days -> assignments",
|
||||
"days -> places",
|
||||
"geo -> maps",
|
||||
"integrations -> addons",
|
||||
"integrations -> assignments",
|
||||
"integrations -> atlas",
|
||||
"integrations -> journey",
|
||||
"integrations -> places",
|
||||
"integrations -> reservations",
|
||||
"journey -> addons",
|
||||
"journey -> atlas",
|
||||
"journey -> memories",
|
||||
"journey -> photos",
|
||||
"maps -> geo",
|
||||
"memories -> addons",
|
||||
"memories -> photos",
|
||||
"photos -> memories",
|
||||
"places -> accommodations",
|
||||
"places -> assignments",
|
||||
"places -> atlas",
|
||||
"places -> journey",
|
||||
"plugins -> trips",
|
||||
"plugins -> vacay",
|
||||
"reservations -> accommodations",
|
||||
"reservations -> assignments",
|
||||
"reservations -> budget",
|
||||
"reservations -> days",
|
||||
"reservations -> integrations",
|
||||
"transit -> days",
|
||||
"transit -> reservations",
|
||||
"trip-members -> auth",
|
||||
"trip-members -> trips",
|
||||
"trip-read-model -> trip-members",
|
||||
@@ -57,11 +34,8 @@
|
||||
"nest/common/validate-route-guards.ts -> nest/public-api/api-token.guard.ts"
|
||||
],
|
||||
"domainInternals": [
|
||||
"addons -> memories/memories.helpers.ts",
|
||||
"addons -> settings/instance-api-keys.ts",
|
||||
"addons -> transit/transit-provider.ts",
|
||||
"admin -> llm-parse/llm-config.ts",
|
||||
"admin -> memories/memories.helpers.ts",
|
||||
"atlas -> geo/nominatim.client.ts",
|
||||
"atlas -> public-api/public-api-request.ts",
|
||||
"auth -> maps/maps.helpers.ts",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@mikro-orm/nestjs';
|
||||
import { ADDON_IDS } from '../../addons';
|
||||
import { getPhotoProviderConfig } from '../memories/memories.helpers';
|
||||
import { readTransitProvider, writeTransitProvider } from '../transit/transit-provider';
|
||||
import { getPhotoProviderConfig } from '../common/photo-provider-config';
|
||||
import { readTransitProvider, writeTransitProvider } from '../common/transit-provider';
|
||||
import { resolveApiKey, type ApiKeySource } from '../settings/instance-api-keys';
|
||||
import { readEnv } from '../../app-config';
|
||||
import type { TransitProvider } from '@trek/shared';
|
||||
@@ -233,7 +233,7 @@ export class AddonsService {
|
||||
|
||||
// ── Transit backend (#1699) ────────────────────────────────────────────────
|
||||
// Not a flag: two named backends, so it stores the name rather than a
|
||||
// boolean. The read/write pair lives in transit/transit-provider.ts because
|
||||
// boolean. The read/write pair lives in common/transit-provider.ts because
|
||||
// TransitService reads the same row on every request — one key, one reader,
|
||||
// one writer. Neither that module nor instance-api-keys.ts (below) is one of
|
||||
// this plan's six domains, so they stay on DatabaseService until their own
|
||||
|
||||
@@ -18,7 +18,7 @@ import { maybe_encrypt_api_key, decrypt_api_key } from '../common/crypto/apiKeyC
|
||||
import { avatarUrl } from '../common/avatarUrl';
|
||||
import { DATABASE_BACKUP, type DatabaseBackupStrategy } from '../database/database-backup.interface';
|
||||
import { prepareLlmAddonConfigForWrite, maskLlmAddonConfig } from '../llm-parse/llm-config';
|
||||
import { getPhotoProviderConfig } from '../memories/memories.helpers';
|
||||
import { getPhotoProviderConfig } from '../common/photo-provider-config';
|
||||
import { validatePassword } from '../common/passwordPolicy';
|
||||
import { UserCleanupService } from '../auth/user-cleanup.service';
|
||||
import { UnitOfWork } from '../database/unit-of-work';
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Where the client finds a provider's settings/status/test endpoints. Pure
|
||||
* string building in the shared kernel: the admin and addons surfaces both
|
||||
* read it, and neither should have to import the memories domain to do so.
|
||||
*/
|
||||
export interface PhotoProviderConfig {
|
||||
settings_get: string;
|
||||
settings_put: string;
|
||||
status_get: string;
|
||||
test_post: string;
|
||||
}
|
||||
|
||||
export function getPhotoProviderConfig(providerId: string): PhotoProviderConfig {
|
||||
const prefix = `/integrations/memories/${providerId}`;
|
||||
return {
|
||||
settings_get: `${prefix}/settings`,
|
||||
settings_put: `${prefix}/settings`,
|
||||
status_get: `${prefix}/status`,
|
||||
test_post: `${prefix}/test`,
|
||||
};
|
||||
}
|
||||
@@ -360,28 +360,3 @@ export async function pipeAsset(url: string, response: Response, headers?: Recor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Route shape for the settings page ─────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Where the client finds a provider's settings/status/test endpoints. Pure
|
||||
* string building, so it stays here rather than on a service — the admin and
|
||||
* addons surfaces both read it and neither should have to import the memories
|
||||
* domain to do so.
|
||||
*/
|
||||
export interface PhotoProviderConfig {
|
||||
settings_get: string;
|
||||
settings_put: string;
|
||||
status_get: string;
|
||||
test_post: string;
|
||||
}
|
||||
|
||||
export function getPhotoProviderConfig(providerId: string): PhotoProviderConfig {
|
||||
const prefix = `/integrations/memories/${providerId}`;
|
||||
return {
|
||||
settings_get: `${prefix}/settings`,
|
||||
settings_put: `${prefix}/settings`,
|
||||
status_get: `${prefix}/status`,
|
||||
test_post: `${prefix}/test`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { AppSettingsRepository } from '../../db/repositories/AppSettings.re
|
||||
import { Users } from '../../db/entities/Users.entity';
|
||||
import type { UsersRepository } from '../../db/repositories/Users.repository';
|
||||
import { GoogleQuotaService } from '../google-quota/google-quota.service';
|
||||
import { readTransitProvider } from './transit-provider';
|
||||
import { readTransitProvider } from '../common/transit-provider';
|
||||
import {
|
||||
decodePolyline,
|
||||
deriveTransitStats,
|
||||
|
||||
@@ -35,7 +35,7 @@ db.exec('DELETE FROM app_settings');
|
||||
const { getPhotoProviderConfig } = vi.hoisted(() => ({
|
||||
getPhotoProviderConfig: vi.fn(() => ({ url: 'https://immich.example' })),
|
||||
}));
|
||||
vi.mock('../../src/nest/memories/memories.helpers', () => ({ getPhotoProviderConfig }));
|
||||
vi.mock('../../src/nest/common/photo-provider-config', () => ({ getPhotoProviderConfig }));
|
||||
|
||||
import { AddonsModule } from '../../src/nest/addons/addons.module';
|
||||
import { TrekExceptionFilter } from '../../src/nest/common/trek-exception.filter';
|
||||
|
||||
@@ -43,7 +43,7 @@ import { PlaceShadowPicks } from '../../../src/db/entities/PlaceShadowPicks.enti
|
||||
import type { UsersRepository } from '../../../src/db/repositories/Users.repository';
|
||||
|
||||
const { getPhotoProviderConfig } = vi.hoisted(() => ({ getPhotoProviderConfig: vi.fn(() => ({})) }));
|
||||
vi.mock('../../../src/nest/memories/memories.helpers', () => ({ getPhotoProviderConfig }));
|
||||
vi.mock('../../../src/nest/common/photo-provider-config', () => ({ getPhotoProviderConfig }));
|
||||
|
||||
const testDb = createSnapshotTestDb();
|
||||
let t: TestOrm;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { AppSettingsRepository } from '../../../../src/db/repositories/AppSettings.repository';
|
||||
import {
|
||||
DEFAULT_TRANSIT_PROVIDER,
|
||||
readTransitProvider,
|
||||
TRANSIT_PROVIDER_SETTING,
|
||||
writeTransitProvider,
|
||||
} from '../../../../src/nest/common/transit-provider';
|
||||
import { getPhotoProviderConfig } from '../../../../src/nest/common/photo-provider-config';
|
||||
|
||||
function settings(value: string | null) {
|
||||
return { getValue: vi.fn(async () => value), setValue: vi.fn(async () => undefined) };
|
||||
}
|
||||
|
||||
describe('transit provider setting', () => {
|
||||
it('reads a known backend as stored', async () => {
|
||||
const repo = settings('google');
|
||||
expect(await readTransitProvider(repo as unknown as AppSettingsRepository)).toBe('google');
|
||||
expect(repo.getValue).toHaveBeenCalledWith(TRANSIT_PROVIDER_SETTING);
|
||||
});
|
||||
|
||||
it('falls back to Transitous for a missing row or a name this version does not know', async () => {
|
||||
expect(await readTransitProvider(settings(null) as unknown as AppSettingsRepository)).toBe(DEFAULT_TRANSIT_PROVIDER);
|
||||
expect(await readTransitProvider(settings('rail-x') as unknown as AppSettingsRepository)).toBe(DEFAULT_TRANSIT_PROVIDER);
|
||||
});
|
||||
|
||||
it('writes the name under its one key and hands it back', async () => {
|
||||
const repo = settings(null);
|
||||
expect(await writeTransitProvider(repo as unknown as AppSettingsRepository, 'google')).toBe('google');
|
||||
expect(repo.setValue).toHaveBeenCalledWith(TRANSIT_PROVIDER_SETTING, 'google');
|
||||
});
|
||||
});
|
||||
|
||||
describe('photo provider config', () => {
|
||||
it('points every endpoint under the provider prefix', () => {
|
||||
expect(getPhotoProviderConfig('immich')).toEqual({
|
||||
settings_get: '/integrations/memories/immich/settings',
|
||||
settings_put: '/integrations/memories/immich/settings',
|
||||
status_get: '/integrations/memories/immich/status',
|
||||
test_post: '/integrations/memories/immich/test',
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user