Files
ostandari/server/controllers/dataBackupController.js
T
2024-10-21 10:22:26 +03:30

188 lines
8.3 KiB
JavaScript

const fs = require('fs')
const archiver = require('archiver')
const moment = require('moment')
const jwt = require('jsonwebtoken')
const {secretKey} = require('../authentication')
const {_sr} = require('../plugins/serverResponses')
// models
const Category = require('../models/Category')
const Comment = require('../models/Comment')
const ContactUs = require('../models/ContactUs')
const Content = require('../models/Content')
const Gallery = require('../models/Gallery')
const HomePage = require('../models/HomePage')
const Links = require('../models/Links')
const Meeting = require('../models/Meeting')
const News = require('../models/News')
const NewsFile = require('../models/NewsFile')
const Occasion = require('../models/Occasion')
const Services = require('../models/Services')
const Slider = require('../models/Slider')
const User = require('../models/User')
const YearBanner = require('../models/YearBanner')
module.exports.createBackUp = [
// check user token and permission to backup
async (req, res, next) => {
const token = req.params.token
if (!token) return res.status(401).json({message: 'unauthorized'})
try {
// check if token is not destroyed
const user = await User.findOne({token: token})
if (!user) return res.status(401).json({message: 'unauthorized'})
// verify token
const checkToken = await jwt.verify(user.token.replace(/^Bearer\s/, ''), secretKey)
if (!checkToken) return res.status(401).json({message: 'unauthorized'})
// check user permissions
const permissions = user.permissions
if (!permissions.includes('superAdmin')) res.status(401).json({message: 'unauthorized'})
return next()
} catch (e) {
res.status(401).json({message: 'unauthorized'})
}
},
// do backup :)
async (req, res) => {
try {
console.log('backup started')
const dataBaseQueries = [
// categories
Category.find(),
// comments
Comment.find(),
// contact us
ContactUs.find(),
// content
Content.find(),
// gallery
Gallery.find(),
// home page
HomePage.find(),
// links
Links.find(),
// meetings
Meeting.find(),
// news
News.find(),
// newsFile
NewsFile.find(),
// services
Services.find(),
// sliders
Slider.find(),
// users
User.find(),
// year banner
YearBanner.find(),
// occasion
Occasion.find()
]
const [categories, comments, contactus, contents, galleries, homepage, links, meetings, news, newsFiles, services, sliders, users, yearBanner, occasion] = await Promise.all(dataBaseQueries)
if (await !fs.existsSync('./backup/database')) await fs.mkdirSync('./backup/database')
await Promise.all([
fs.writeFileSync(`./backup/database/categories_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(categories)),
fs.writeFileSync(`./backup/database/comments_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(comments)),
fs.writeFileSync(`./backup/database/contactus_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(contactus)),
fs.writeFileSync(`./backup/database/contents_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(contents)),
fs.writeFileSync(`./backup/database/galleries_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(galleries)),
fs.writeFileSync(`./backup/database/homepage_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(homepage)),
fs.writeFileSync(`./backup/database/links_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(links)),
fs.writeFileSync(`./backup/database/meetings_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(meetings)),
fs.writeFileSync(`./backup/database/news_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(news)),
fs.writeFileSync(`./backup/database/newsFiles_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(newsFiles)),
fs.writeFileSync(`./backup/database/services_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(services)),
fs.writeFileSync(`./backup/database/sliders_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(sliders)),
fs.writeFileSync(`./backup/database/users_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(users)),
fs.writeFileSync(`./backup/database/yearBanner_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(yearBanner)),
fs.writeFileSync(`./backup/database/occasion_${moment(Date.now()).format('YYYY-MM-DD')}.json`, JSON.stringify(occasion))
])
/////////////////// create backup zip file
const backupName = 'backup_' + moment(Date.now()).format('YYYY-MM-DD') + '.zip'
// create a file to stream archive data to.
const output = fs.createWriteStream(`./backup/${backupName}`)
const archive = archiver('zip', {
zlib: {level: 9} // Sets the compression level.
})
// listen for all archive data to be written
// 'close' event is fired only when a file descriptor is involved
output.on('close', function () {
console.log(archive.pointer() + ' total bytes')
console.log('archiver has been finalized and the output file descriptor has closed.')
return res.download(`./backup/${backupName}`)
})
// This event is fired when the data source is drained no matter what was the data source.
// It is not part of this library but rather from the NodeJS Stream API.
// @see: https://nodejs.org/api/stream.html#stream_event_end
output.on('end', function () {
console.log('Data has been drained')
return res.status(500).send('<h1 style="margin-top: 150px;text-align: center;direction: rtl;color: red;">فضای هاست پر میباشد.لطفا نسبت به پاک کردن بکاپ های قبلی یا افزایش فضای هاست اقدام فرمایید.</h1>')
})
// good practice to catch warnings (ie stat failures and other non-blocking errors)
archive.on('warning', function (err) {
if (err.code === 'ENOENT') {
// log warning
console.log('On archiver warning -- ENOENT error code', err)
} else {
// throw error
console.log('On archiver warning -- other error codes ', err)
}
return res.status(500).send('<h1 style="margin-top: 150px;text-align: center;direction: rtl;color: red;">فضای هاست پر میباشد.لطفا نسبت به پاک کردن بکاپ های قبلی یا افزایش فضای هاست اقدام فرمایید.</h1>')
})
// good practice to catch this error explicitly
archive.on('error', function (err) {
// throw err
console.log(err)
return res.status(500).json({message: 'مشکلی پیش آمده'})
})
// pipe archive data to the file
await archive.pipe(output)
// append files from a sub-directory and naming it `new-subdir` within the archive
await archive.directory(`./static/uploads/`, 'uploads')
await archive.directory(`./backup/database/`, 'database')
// finalize the archive (ie we are done appending files but streams have to finish yet)
// 'close', 'end' or 'finish' may be fired right after calling this method so register to them beforehand
await archive.finalize()
await fs.rmdirSync('./backup/database', {recursive: true})
} catch (e) {
return res.status(500).send('<h1 style="margin-top: 150px;text-align: center;direction: rtl;color: red;">فضای هاست پر میباشد.لطفا نسبت به پاک کردن بکاپ های قبلی یا افزایش فضای هاست اقدام فرمایید.</h1>')
}
}
]
module.exports.removeOldBackups = [
async (req, res) => {
try {
const files = await fs.readdirSync('./backup')
for await (const file of files) {
const isDirectory = await fs.statSync(`./backup/${file}`).isDirectory()
if (isDirectory) await fs.rmdirSync(`./backup/${file}`, {recursive: true})
else await fs.unlinkSync(`./backup/${file}`)
}
return res.json({message: _sr['fa'].response.success_remove})
} catch (e) {
return res.status(500).json({message: e})
}
}
]