165 lines
3.6 KiB
TypeScript
165 lines
3.6 KiB
TypeScript
const mongoose = require("mongoose");
|
|
import { MetadataSource } from "./comic.model";
|
|
|
|
// Source priority configuration
|
|
const SourcePrioritySchema = new mongoose.Schema(
|
|
{
|
|
_id: false,
|
|
source: {
|
|
type: String,
|
|
enum: Object.values(MetadataSource),
|
|
required: true,
|
|
},
|
|
priority: {
|
|
type: Number,
|
|
required: true,
|
|
min: 1,
|
|
}, // Lower number = higher priority (1 is highest)
|
|
enabled: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
// Field-specific overrides
|
|
fieldOverrides: {
|
|
type: Map,
|
|
of: Number, // field name -> priority for that specific field
|
|
default: new Map(),
|
|
},
|
|
},
|
|
{ _id: false }
|
|
);
|
|
|
|
// Conflict resolution strategy
|
|
export enum ConflictResolutionStrategy {
|
|
PRIORITY = "priority", // Use source priority
|
|
CONFIDENCE = "confidence", // Use confidence score
|
|
RECENCY = "recency", // Use most recently fetched
|
|
MANUAL = "manual", // Always prefer manual entries
|
|
HYBRID = "hybrid", // Combine priority and confidence
|
|
}
|
|
|
|
// User preferences for metadata resolution
|
|
const UserPreferencesSchema = new mongoose.Schema(
|
|
{
|
|
userId: {
|
|
type: String,
|
|
required: true,
|
|
unique: true,
|
|
default: "default",
|
|
}, // Support for multi-user in future
|
|
|
|
// Source priority configuration
|
|
sourcePriorities: {
|
|
type: [SourcePrioritySchema],
|
|
default: [
|
|
{
|
|
source: MetadataSource.MANUAL,
|
|
priority: 1,
|
|
enabled: true,
|
|
},
|
|
{
|
|
source: MetadataSource.COMICVINE,
|
|
priority: 2,
|
|
enabled: true,
|
|
},
|
|
{
|
|
source: MetadataSource.METRON,
|
|
priority: 3,
|
|
enabled: true,
|
|
},
|
|
{
|
|
source: MetadataSource.GRAND_COMICS_DATABASE,
|
|
priority: 4,
|
|
enabled: true,
|
|
},
|
|
{
|
|
source: MetadataSource.LOCG,
|
|
priority: 5,
|
|
enabled: true,
|
|
},
|
|
{
|
|
source: MetadataSource.COMICINFO_XML,
|
|
priority: 6,
|
|
enabled: true,
|
|
},
|
|
],
|
|
},
|
|
|
|
// Global conflict resolution strategy
|
|
conflictResolution: {
|
|
type: String,
|
|
enum: Object.values(ConflictResolutionStrategy),
|
|
default: ConflictResolutionStrategy.HYBRID,
|
|
},
|
|
|
|
// Minimum confidence threshold (0-1)
|
|
minConfidenceThreshold: {
|
|
type: Number,
|
|
min: 0,
|
|
max: 1,
|
|
default: 0.5,
|
|
},
|
|
|
|
// Prefer newer data when confidence/priority are equal
|
|
preferRecent: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
|
|
// Field-specific preferences
|
|
fieldPreferences: {
|
|
// Always prefer certain sources for specific fields
|
|
// e.g., { "description": "comicvine", "coverImage": "locg" }
|
|
type: Map,
|
|
of: String,
|
|
default: new Map(),
|
|
},
|
|
|
|
// Auto-merge settings
|
|
autoMerge: {
|
|
enabled: { type: Boolean, default: true },
|
|
onImport: { type: Boolean, default: true },
|
|
onMetadataUpdate: { type: Boolean, default: true },
|
|
},
|
|
},
|
|
{ timestamps: true }
|
|
);
|
|
|
|
// Helper method to get priority for a source
|
|
UserPreferencesSchema.methods.getSourcePriority = function (
|
|
source: MetadataSource,
|
|
field?: string
|
|
): number {
|
|
const sourcePriority = this.sourcePriorities.find(
|
|
(sp: any) => sp.source === source && sp.enabled
|
|
);
|
|
|
|
if (!sourcePriority) {
|
|
return Infinity; // Disabled or not configured
|
|
}
|
|
|
|
// Check for field-specific override
|
|
if (field && sourcePriority.fieldOverrides.has(field)) {
|
|
return sourcePriority.fieldOverrides.get(field);
|
|
}
|
|
|
|
return sourcePriority.priority;
|
|
};
|
|
|
|
// Helper method to check if source is enabled
|
|
UserPreferencesSchema.methods.isSourceEnabled = function (
|
|
source: MetadataSource
|
|
): boolean {
|
|
const sourcePriority = this.sourcePriorities.find(
|
|
(sp: any) => sp.source === source
|
|
);
|
|
return sourcePriority ? sourcePriority.enabled : false;
|
|
};
|
|
|
|
const UserPreferences = mongoose.model(
|
|
"UserPreferences",
|
|
UserPreferencesSchema
|
|
);
|
|
|
|
export default UserPreferences;
|