const Setting = require('./settingModel') const AppError = require('../../globalErrorHandler/AppError') const DEFAULT_SEARCH_PAGES = [ { pageKey: 'properties', title: 'املاک (Properties)', description: 'جستجوی املاک، کد نوسازی، شناسه ملی جغرافیایی، مشخصات سند، مالک و پلاک ثبتی', defaultMethod: 'typesense', supportedMethods: ['typesense', 'mongo'], endpointTypesense: '/api/properties/admin/search', endpointMongo: '/api/properties/admin/search-mongo', routePath: '/property/list-properties', icon: 'pi pi-file', }, { pageKey: 'transactions', title: 'تراکنش‌های املاک (Transactions)', description: 'جستجوی تراکنش‌های واریز و برداشت، توضیحات، نام کاربر و ملک مرتبط', defaultMethod: 'typesense', supportedMethods: ['typesense', 'mongo'], endpointTypesense: '/api/transactions/admin/search', endpointMongo: '/api/transactions/admin/search-mongo', routePath: '/transactions/list-transactions', icon: 'pi pi-history', }, { pageKey: 'warehouseItems', title: 'اقلام انبار (Warehouse Items)', description: 'جستجوی اقلام کالا، نام فارسی، نام انگلیسی، کد کالا و دسته‌بندی', defaultMethod: 'mongo', supportedMethods: ['mongo', 'typesense'], endpointTypesense: '/api/warehouse-items/admin/items', endpointMongo: '/api/warehouse-items/admin/items', routePath: '/warehouse-items/list', icon: 'pi pi-box', }, { pageKey: 'warehouses', title: 'مکان‌های انبار (Warehouses)', description: 'جستجوی نام انبار، کد و آدرس انبارها', defaultMethod: 'mongo', supportedMethods: ['mongo', 'typesense'], endpointTypesense: '/api/warehouses/admin/get-all', endpointMongo: '/api/warehouses/admin/get-all', routePath: '/warehouse-items/warehouses', icon: 'pi pi-map', }, { pageKey: 'categories', title: 'دسته‌بندی‌ها (Categories)', description: 'جستجوی دسته‌بندی‌های املاک بر اساس نام فارسی و انگلیسی', defaultMethod: 'mongo', supportedMethods: ['mongo', 'typesense'], endpointTypesense: '/api/categories/admin/get-all', endpointMongo: '/api/categories/admin/get-all', routePath: '/categories/list-categories', icon: 'pi pi-th-large', }, { pageKey: 'users', title: 'کاربران (Users)', description: 'جستجوی کاربران سیستم بر اساس نام، ایمیل و نقش کاربری', defaultMethod: 'mongo', supportedMethods: ['mongo', 'typesense'], endpointTypesense: '/api/users/admin/get-all', endpointMongo: '/api/users/admin/get-all', routePath: '/users/list-users', icon: 'pi pi-users', }, { pageKey: 'roles', title: 'نقش‌ها و دسترسی‌ها (Roles)', description: 'جستجوی نقش‌ها بر اساس عنوان فارسی و انگلیسی', defaultMethod: 'mongo', supportedMethods: ['mongo', 'typesense'], endpointTypesense: '/api/roles/admin/get-all', endpointMongo: '/api/roles/admin/get-all', routePath: '/roles/list-roles', icon: 'pi pi-shield', }, ] const getSearchSettings = async () => { const dbSettings = await Setting.find({ category: 'search' }).lean() const dbSettingsMap = new Map() dbSettings.forEach((s) => { dbSettingsMap.set(s.pageKey, s) }) return DEFAULT_SEARCH_PAGES.map((pageDef) => { const dbRecord = dbSettingsMap.get(pageDef.pageKey) if (dbRecord) { return { ...pageDef, _id: dbRecord._id, searchMethod: dbRecord.searchMethod || pageDef.defaultMethod, isPersisted: true, updatedAt: dbRecord.updatedAt, createdAt: dbRecord.createdAt, } } return { ...pageDef, searchMethod: pageDef.defaultMethod, isPersisted: false, } }) } const getSearchSettingByPage = async (pageKey) => { const pageDef = DEFAULT_SEARCH_PAGES.find((p) => p.pageKey === pageKey) if (!pageDef) { throw new AppError('PageNotFound', 404, { message: `Page key ${pageKey} not found in search configurations` }) } const dbRecord = await Setting.findOne({ pageKey, category: 'search' }).lean() if (dbRecord) { return { ...pageDef, _id: dbRecord._id, searchMethod: dbRecord.searchMethod || pageDef.defaultMethod, isPersisted: true, updatedAt: dbRecord.updatedAt, createdAt: dbRecord.createdAt, } } return { ...pageDef, searchMethod: pageDef.defaultMethod, isPersisted: false, } } const setSearchMethod = async (pageKey, searchMethod, extraConfig = {}) => { if (!['typesense', 'mongo'].includes(searchMethod)) { throw new AppError('InvalidSearchMethod', 400, { message: 'Search method must be either "typesense" or "mongo"' }) } const pageDef = DEFAULT_SEARCH_PAGES.find((p) => p.pageKey === pageKey) || { pageKey, title: pageKey, description: `Settings for ${pageKey}`, defaultMethod: 'mongo', } const setting = await Setting.findOneAndUpdate( { pageKey, category: 'search' }, { key: `search_${pageKey}`, category: 'search', pageKey, title: pageDef.title, description: pageDef.description, searchMethod, extraConfig, }, { upsert: true, new: true, setDefaultsOnInsert: true } ) return { ...pageDef, _id: setting._id, searchMethod: setting.searchMethod, isPersisted: true, updatedAt: setting.updatedAt, createdAt: setting.createdAt, } } const seederRunner = require('../../seeder/seederRunner') const bulkUpdateSearchSettings = async (settingsArray) => { if (!Array.isArray(settingsArray)) { throw new AppError('InvalidDataFormat', 400, { message: 'Expected an array of settings' }) } const results = [] for (const item of settingsArray) { if (item.pageKey && item.searchMethod) { const updated = await setSearchMethod(item.pageKey, item.searchMethod, item.extraConfig || {}) results.push(updated) } } return results } const getSeedStatus = async () => { const record = await Setting.findOne({ key: 'system_database_seeded' }).lean() if (record && record.extraConfig && record.extraConfig.isSeeded) { return { isSeeded: true, seededAt: record.extraConfig.seededAt || record.updatedAt, seededBy: record.extraConfig.seededBy || null, } } return { isSeeded: false, seededAt: null, seededBy: null, } } const seedDatabase = async (userId = null) => { const currentStatus = await getSeedStatus() if (currentStatus.isSeeded) { throw new AppError('DatabaseAlreadySeeded', 400, { message: 'پایگاه داده قبلاً مقداردهی شده است و امکان مقداردهی مجدد وجود ندارد.', }) } await seederRunner.run() const record = await Setting.findOneAndUpdate( { key: 'system_database_seeded' }, { key: 'system_database_seeded', category: 'system', pageKey: 'system_seeder', title: 'مقداردهی اولیه پایگاه داده', description: 'وضعیت اجرای مقداردهی اولیه داده‌های پایه سیستم', extraConfig: { isSeeded: true, seededAt: new Date(), seededBy: userId, }, }, { upsert: true, new: true, setDefaultsOnInsert: true } ) return { isSeeded: true, seededAt: record.extraConfig.seededAt, message: 'پایگاه داده با موفقیت مقداردهی اولیه شد.', } } module.exports = { DEFAULT_SEARCH_PAGES, getSearchSettings, getSearchSettingByPage, setSearchMethod, bulkUpdateSearchSettings, getSeedStatus, seedDatabase, }