fix: resolve MongoDB connection and port configuration issues
- Added dotenv configuration for environment variables - Fixed MongoDB connection string loading - Configured server port to 3005 - Updated cron jobs for expired messages
This commit is contained in:
@@ -1,211 +1,211 @@
|
||||
const { exec } = require('child_process')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const SettingModel = require('../../../models/SettingsModel')
|
||||
|
||||
const CDN_KEYS = [
|
||||
'cdn_enabled',
|
||||
'cdn_domain',
|
||||
'cdn_origin_url',
|
||||
'cdn_ns1',
|
||||
'cdn_ns2',
|
||||
'cdn_cache_ttl',
|
||||
'ssl_enabled',
|
||||
'ssl_auto_renew',
|
||||
'ssl_status',
|
||||
'ssl_expires_at',
|
||||
'rate_limit_requests',
|
||||
'rate_limit_window_minutes',
|
||||
]
|
||||
|
||||
const DEFAULT_CDN_SETTINGS = {
|
||||
cdn_enabled: 'false',
|
||||
cdn_domain: 'cdn.modstagram.com',
|
||||
cdn_origin_url: 'https://api.modstagram.com',
|
||||
cdn_ns1: 'ns1.modstagram.com',
|
||||
cdn_ns2: 'ns2.modstagram.com',
|
||||
cdn_cache_ttl: '3600',
|
||||
ssl_enabled: 'false',
|
||||
ssl_auto_renew: 'true',
|
||||
ssl_status: 'none',
|
||||
ssl_expires_at: '',
|
||||
rate_limit_requests: '3000',
|
||||
rate_limit_window_minutes: '3',
|
||||
}
|
||||
|
||||
const upsertSetting = async (key, value) => {
|
||||
await SettingModel.findOneAndUpdate(
|
||||
{ key },
|
||||
{ value: String(value) },
|
||||
{ new: true, upsert: true }
|
||||
)
|
||||
}
|
||||
|
||||
const getSettingsMap = async () => {
|
||||
const settings = await SettingModel.find({ key: { $in: CDN_KEYS } })
|
||||
const map = { ...DEFAULT_CDN_SETTINGS }
|
||||
settings.forEach((item) => {
|
||||
map[item.key] = item.value
|
||||
})
|
||||
return map
|
||||
}
|
||||
|
||||
const getCdnSettings = async (req, res, next) => {
|
||||
try {
|
||||
const settings = await getSettingsMap()
|
||||
res.status(200).json({ settings })
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
const updateCdnSettings = async (req, res, next) => {
|
||||
try {
|
||||
const { settings } = req.body
|
||||
if (!settings || typeof settings !== 'object') {
|
||||
return res.status(400).json({ message: 'دادههای تنظیمات نامعتبر است' })
|
||||
}
|
||||
|
||||
const updates = Object.entries(settings).filter(([key]) => CDN_KEYS.includes(key))
|
||||
await Promise.all(updates.map(([key, value]) => upsertSetting(key, value)))
|
||||
|
||||
res.status(200).json({
|
||||
message: 'تنظیمات CDN با موفقیت ذخیره شد',
|
||||
settings: await getSettingsMap(),
|
||||
})
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
const readCertInfo = (domain) =>
|
||||
new Promise((resolve) => {
|
||||
const certPath =
|
||||
process.env.SSL_CERT_PATH ||
|
||||
`/etc/letsencrypt/live/${domain}/fullchain.pem`
|
||||
|
||||
if (!fs.existsSync(certPath)) {
|
||||
resolve({ found: false, certPath })
|
||||
return
|
||||
}
|
||||
|
||||
exec(
|
||||
`openssl x509 -in "${certPath}" -noout -enddate`,
|
||||
{ timeout: 10000 },
|
||||
(error, stdout) => {
|
||||
if (error) {
|
||||
resolve({ found: true, certPath, valid: false })
|
||||
return
|
||||
}
|
||||
|
||||
const match = stdout.match(/notAfter=(.+)/)
|
||||
const expiresAt = match ? new Date(match[1].trim()).toISOString() : null
|
||||
const valid = expiresAt ? new Date(expiresAt) > new Date() : false
|
||||
resolve({ found: true, certPath, valid, expiresAt })
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const getSslStatus = async (req, res, next) => {
|
||||
try {
|
||||
const settings = await getSettingsMap()
|
||||
const domain = settings.cdn_domain
|
||||
const certInfo = await readCertInfo(domain)
|
||||
|
||||
let status = settings.ssl_status
|
||||
if (certInfo.found && certInfo.valid) {
|
||||
status = 'active'
|
||||
if (certInfo.expiresAt) {
|
||||
await upsertSetting('ssl_expires_at', certInfo.expiresAt)
|
||||
await upsertSetting('ssl_status', 'active')
|
||||
await upsertSetting('ssl_enabled', 'true')
|
||||
}
|
||||
} else if (certInfo.found && !certInfo.valid) {
|
||||
status = 'expired'
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
domain,
|
||||
status,
|
||||
ssl_enabled: settings.ssl_enabled === 'true',
|
||||
ssl_auto_renew: settings.ssl_auto_renew === 'true',
|
||||
expires_at: certInfo.expiresAt || settings.ssl_expires_at || null,
|
||||
cert_path: certInfo.certPath,
|
||||
cert_found: certInfo.found,
|
||||
})
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
const activateSsl = async (req, res, next) => {
|
||||
try {
|
||||
const settings = await getSettingsMap()
|
||||
const domain = req.body?.domain || settings.cdn_domain
|
||||
const email = req.body?.email || process.env.SSL_ADMIN_EMAIL || 'admin@modstagram.com'
|
||||
|
||||
if (!domain) {
|
||||
return res.status(400).json({ message: 'دامنه CDN تنظیم نشده است' })
|
||||
}
|
||||
|
||||
await upsertSetting('ssl_status', 'pending')
|
||||
|
||||
const scriptPath = path.join(__dirname, '../../../scripts/cdn-ssl.sh')
|
||||
const command = `bash "${scriptPath}" "${domain}" "${email}"`
|
||||
|
||||
exec(command, { timeout: 180000 }, async (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
await upsertSetting('ssl_status', 'failed')
|
||||
return res.status(500).json({
|
||||
message: 'خطا در فعالسازی SSL',
|
||||
details: stderr || error.message,
|
||||
output: stdout,
|
||||
})
|
||||
}
|
||||
|
||||
const certInfo = await readCertInfo(domain)
|
||||
await upsertSetting('ssl_enabled', 'true')
|
||||
await upsertSetting('ssl_status', certInfo.valid ? 'active' : 'pending')
|
||||
if (certInfo.expiresAt) {
|
||||
await upsertSetting('ssl_expires_at', certInfo.expiresAt)
|
||||
}
|
||||
|
||||
return res.status(200).json({
|
||||
message: 'SSL رایگان با موفقیت فعال شد',
|
||||
status: certInfo.valid ? 'active' : 'pending',
|
||||
expires_at: certInfo.expiresAt || null,
|
||||
output: stdout,
|
||||
})
|
||||
})
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
const getPublicCdnConfig = async (req, res, next) => {
|
||||
try {
|
||||
const settings = await getSettingsMap()
|
||||
const cdnEnabled = settings.cdn_enabled === 'true'
|
||||
const cdnDomain = settings.cdn_domain
|
||||
const originUrl = settings.cdn_origin_url
|
||||
|
||||
res.status(200).json({
|
||||
cdn_enabled: cdnEnabled,
|
||||
cdn_domain: cdnDomain,
|
||||
image_base_url: cdnEnabled
|
||||
? `https://${cdnDomain.replace(/^https?:\/\//, '')}/storage`
|
||||
: `${originUrl}/storage`,
|
||||
ssl_enabled: settings.ssl_enabled === 'true',
|
||||
})
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getCdnSettings,
|
||||
updateCdnSettings,
|
||||
getSslStatus,
|
||||
activateSsl,
|
||||
getPublicCdnConfig,
|
||||
}
|
||||
const { exec } = require('child_process')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const SettingModel = require('../../../models/SettingsModel')
|
||||
|
||||
const CDN_KEYS = [
|
||||
'cdn_enabled',
|
||||
'cdn_domain',
|
||||
'cdn_origin_url',
|
||||
'cdn_ns1',
|
||||
'cdn_ns2',
|
||||
'cdn_cache_ttl',
|
||||
'ssl_enabled',
|
||||
'ssl_auto_renew',
|
||||
'ssl_status',
|
||||
'ssl_expires_at',
|
||||
'rate_limit_requests',
|
||||
'rate_limit_window_minutes',
|
||||
]
|
||||
|
||||
const DEFAULT_CDN_SETTINGS = {
|
||||
cdn_enabled: 'false',
|
||||
cdn_domain: 'cdn.modstagram.com',
|
||||
cdn_origin_url: 'https://api.modstagram.com',
|
||||
cdn_ns1: 'ns1.modstagram.com',
|
||||
cdn_ns2: 'ns2.modstagram.com',
|
||||
cdn_cache_ttl: '3600',
|
||||
ssl_enabled: 'false',
|
||||
ssl_auto_renew: 'true',
|
||||
ssl_status: 'none',
|
||||
ssl_expires_at: '',
|
||||
rate_limit_requests: '3000',
|
||||
rate_limit_window_minutes: '3',
|
||||
}
|
||||
|
||||
const upsertSetting = async (key, value) => {
|
||||
await SettingModel.findOneAndUpdate(
|
||||
{ key },
|
||||
{ value: String(value) },
|
||||
{ new: true, upsert: true }
|
||||
)
|
||||
}
|
||||
|
||||
const getSettingsMap = async () => {
|
||||
const settings = await SettingModel.find({ key: { $in: CDN_KEYS } })
|
||||
const map = { ...DEFAULT_CDN_SETTINGS }
|
||||
settings.forEach((item) => {
|
||||
map[item.key] = item.value
|
||||
})
|
||||
return map
|
||||
}
|
||||
|
||||
const getCdnSettings = async (req, res, next) => {
|
||||
try {
|
||||
const settings = await getSettingsMap()
|
||||
res.status(200).json({ settings })
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
const updateCdnSettings = async (req, res, next) => {
|
||||
try {
|
||||
const { settings } = req.body
|
||||
if (!settings || typeof settings !== 'object') {
|
||||
return res.status(400).json({ message: 'دادههای تنظیمات نامعتبر است' })
|
||||
}
|
||||
|
||||
const updates = Object.entries(settings).filter(([key]) => CDN_KEYS.includes(key))
|
||||
await Promise.all(updates.map(([key, value]) => upsertSetting(key, value)))
|
||||
|
||||
res.status(200).json({
|
||||
message: 'تنظیمات CDN با موفقیت ذخیره شد',
|
||||
settings: await getSettingsMap(),
|
||||
})
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
const readCertInfo = (domain) =>
|
||||
new Promise((resolve) => {
|
||||
const certPath =
|
||||
process.env.SSL_CERT_PATH ||
|
||||
`/etc/letsencrypt/live/${domain}/fullchain.pem`
|
||||
|
||||
if (!fs.existsSync(certPath)) {
|
||||
resolve({ found: false, certPath })
|
||||
return
|
||||
}
|
||||
|
||||
exec(
|
||||
`openssl x509 -in "${certPath}" -noout -enddate`,
|
||||
{ timeout: 10000 },
|
||||
(error, stdout) => {
|
||||
if (error) {
|
||||
resolve({ found: true, certPath, valid: false })
|
||||
return
|
||||
}
|
||||
|
||||
const match = stdout.match(/notAfter=(.+)/)
|
||||
const expiresAt = match ? new Date(match[1].trim()).toISOString() : null
|
||||
const valid = expiresAt ? new Date(expiresAt) > new Date() : false
|
||||
resolve({ found: true, certPath, valid, expiresAt })
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const getSslStatus = async (req, res, next) => {
|
||||
try {
|
||||
const settings = await getSettingsMap()
|
||||
const domain = settings.cdn_domain
|
||||
const certInfo = await readCertInfo(domain)
|
||||
|
||||
let status = settings.ssl_status
|
||||
if (certInfo.found && certInfo.valid) {
|
||||
status = 'active'
|
||||
if (certInfo.expiresAt) {
|
||||
await upsertSetting('ssl_expires_at', certInfo.expiresAt)
|
||||
await upsertSetting('ssl_status', 'active')
|
||||
await upsertSetting('ssl_enabled', 'true')
|
||||
}
|
||||
} else if (certInfo.found && !certInfo.valid) {
|
||||
status = 'expired'
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
domain,
|
||||
status,
|
||||
ssl_enabled: settings.ssl_enabled === 'true',
|
||||
ssl_auto_renew: settings.ssl_auto_renew === 'true',
|
||||
expires_at: certInfo.expiresAt || settings.ssl_expires_at || null,
|
||||
cert_path: certInfo.certPath,
|
||||
cert_found: certInfo.found,
|
||||
})
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
const activateSsl = async (req, res, next) => {
|
||||
try {
|
||||
const settings = await getSettingsMap()
|
||||
const domain = req.body?.domain || settings.cdn_domain
|
||||
const email = req.body?.email || process.env.SSL_ADMIN_EMAIL || 'admin@modstagram.com'
|
||||
|
||||
if (!domain) {
|
||||
return res.status(400).json({ message: 'دامنه CDN تنظیم نشده است' })
|
||||
}
|
||||
|
||||
await upsertSetting('ssl_status', 'pending')
|
||||
|
||||
const scriptPath = path.join(__dirname, '../../../scripts/cdn-ssl.sh')
|
||||
const command = `bash "${scriptPath}" "${domain}" "${email}"`
|
||||
|
||||
exec(command, { timeout: 180000 }, async (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
await upsertSetting('ssl_status', 'failed')
|
||||
return res.status(500).json({
|
||||
message: 'خطا در فعالسازی SSL',
|
||||
details: stderr || error.message,
|
||||
output: stdout,
|
||||
})
|
||||
}
|
||||
|
||||
const certInfo = await readCertInfo(domain)
|
||||
await upsertSetting('ssl_enabled', 'true')
|
||||
await upsertSetting('ssl_status', certInfo.valid ? 'active' : 'pending')
|
||||
if (certInfo.expiresAt) {
|
||||
await upsertSetting('ssl_expires_at', certInfo.expiresAt)
|
||||
}
|
||||
|
||||
return res.status(200).json({
|
||||
message: 'SSL رایگان با موفقیت فعال شد',
|
||||
status: certInfo.valid ? 'active' : 'pending',
|
||||
expires_at: certInfo.expiresAt || null,
|
||||
output: stdout,
|
||||
})
|
||||
})
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
const getPublicCdnConfig = async (req, res, next) => {
|
||||
try {
|
||||
const settings = await getSettingsMap()
|
||||
const cdnEnabled = settings.cdn_enabled === 'true'
|
||||
const cdnDomain = settings.cdn_domain
|
||||
const originUrl = settings.cdn_origin_url
|
||||
|
||||
res.status(200).json({
|
||||
cdn_enabled: cdnEnabled,
|
||||
cdn_domain: cdnDomain,
|
||||
image_base_url: cdnEnabled
|
||||
? `https://${cdnDomain.replace(/^https?:\/\//, '')}/storage`
|
||||
: `${originUrl}/storage`,
|
||||
ssl_enabled: settings.ssl_enabled === 'true',
|
||||
})
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getCdnSettings,
|
||||
updateCdnSettings,
|
||||
getSslStatus,
|
||||
activateSsl,
|
||||
getPublicCdnConfig,
|
||||
}
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
// controllers/settingController.js
|
||||
|
||||
const SettingModel = require('../../../models/SettingsModel')
|
||||
|
||||
// متد برای دریافت تنظیمات بر اساس key
|
||||
const getSetting = async (req, res, next) => {
|
||||
try {
|
||||
const { key } = req.params
|
||||
const setting = await SettingModel.findOne({ key })
|
||||
if (!setting) {
|
||||
return res.status(404).json({ message: 'تنظیمات مورد نظر یافت نشد' })
|
||||
}
|
||||
res.status(200).json(setting)
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
// متد برای بهروزرسانی تنظیمات بر اساس key
|
||||
const updateSetting = async (req, res, next) => {
|
||||
try {
|
||||
const { key } = req.params
|
||||
const { value } = req.body
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const setting = await SettingModel.findOneAndUpdate(
|
||||
{ key },
|
||||
{ value },
|
||||
{ new: true, upsert: true } // اگر وجود نداشت، آن را ایجاد کن
|
||||
)
|
||||
res.status(200).json({ message: 'تنظیمات با موفقیت بروز شد' })
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { getSetting, updateSetting }
|
||||
// controllers/settingController.js
|
||||
|
||||
const SettingModel = require('../../../models/SettingsModel')
|
||||
|
||||
// متد برای دریافت تنظیمات بر اساس key
|
||||
const getSetting = async (req, res, next) => {
|
||||
try {
|
||||
const { key } = req.params
|
||||
const setting = await SettingModel.findOne({ key })
|
||||
if (!setting) {
|
||||
return res.status(404).json({ message: 'تنظیمات مورد نظر یافت نشد' })
|
||||
}
|
||||
res.status(200).json(setting)
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
// متد برای بهروزرسانی تنظیمات بر اساس key
|
||||
const updateSetting = async (req, res, next) => {
|
||||
try {
|
||||
const { key } = req.params
|
||||
const { value } = req.body
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const setting = await SettingModel.findOneAndUpdate(
|
||||
{ key },
|
||||
{ value },
|
||||
{ new: true, upsert: true } // اگر وجود نداشت، آن را ایجاد کن
|
||||
)
|
||||
res.status(200).json({ message: 'تنظیمات با موفقیت بروز شد' })
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { getSetting, updateSetting }
|
||||
|
||||
Reference in New Issue
Block a user