Skip to content

Commit

Permalink
Merge pull request #203 from hicsail/backup
Browse files Browse the repository at this point in the history
Backup
  • Loading branch information
gregfrasco committed Aug 28, 2018
2 parents 0264bbb + 140344c commit 734d6a0
Show file tree
Hide file tree
Showing 6 changed files with 425 additions and 5 deletions.
15 changes: 15 additions & 0 deletions manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,21 @@ const manifest = {
},
{
plugin: './server/anchor/anchor-api'
},
{
plugin: 'hapi-cron',
options: {
jobs: [{
name: 'backup',
time: '0 0 0 * * *',
timezone: 'America/New_York',
request: {
method: 'POST',
url: '/api/backup/internal',
allowInternals: true
}
}]
}
}
]
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"hapi-auth-basic": "5.x.x",
"hapi-auth-cookie": "9.x.x",
"hapi-auth-jwt2": "8.x.x",
"hapi-cron": "1.x.x",
"hapi-cron": "^1.0.4",
"hapi-remote-address": "1.x.x",
"hoek": "5.x.x",
"inert": "5.x.x",
Expand Down
3 changes: 3 additions & 0 deletions server/anchor/anchor-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,9 @@ class AnchorModel {
if (!doc.createdAt) {
doc.createdAt = new Date();
}
if (typeof doc._id === 'string') {
doc._id = this._idClass(doc._id);
}
}
}
const db = dbFromArgs(args);
Expand Down
200 changes: 200 additions & 0 deletions server/api/backup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
'use strict';
const Backup = require('../models/backup');
const Boom = require('boom');
const Fs = require('fs');
const Path = require('path');

const register = function (server, serverOptions) {

server.route({
method: 'POST',
path: '/api/backup',
options: {
auth: false
},
handler: async function (request, h) {

return await createBackup();
}
});

server.route({
method: 'POST',
path: '/api/backup/internal',
options: {
auth: false,
isInternal: true
},
handler: async function (request, h) {

return await createBackup();
}
});

server.route({
method: 'GET',
path: '/api/backup/{id}/data',
options: {
auth: false
},
handler: async function (request, h) {

const backup = await Backup.findById(request.params.id);
const path = Path.join(__dirname, '../backups/', backup.filename);

backup.data = await readFile(path);

return backup;
}
});

server.route({
method: 'POST',
path: '/api/backup/data',
options: {
auth: false,
validate: {
payload: Backup.payload
}
},
handler: async function (request, h) {

const filename = request.payload.filename + '.json';
const path = Path.join(__dirname, '../backups/', filename);

await writeFile(path, request.payload.data);

return await Backup.create({
filename,
local: true
});
}
});

server.route({
method: 'POST',
path: '/api/backup/restore/{id}',
options: {
auth: false
},
handler: async function (request, h) {

const backup = await Backup.findById(request.params.id);

if (!backup) {
return Boom.notFound('Backup not found');
}

const path = Path.join(__dirname, '../backups/', backup.filename);
const data = await readFile(path);

for (const collectionName in server.plugins['hapi-anchor-model'].models) {
const model = server.plugins['hapi-anchor-model'].models[collectionName];
if (data[collectionName]) {
await model.deleteMany({});
}
if (data[collectionName].length > 0) {
await model.insertMany(data[collectionName]);
}
}

await Backup.deleteMany({});
await createBackupsFromDisk();

return { message: 'Success' };
}
});

const createBackup = async () => {

const data = {};
for (const collectionName in server.plugins['hapi-anchor-model'].models) {
data[collectionName] = await server.plugins['hapi-anchor-model'].models[collectionName].find({});
}

const filename = new Date().toISOString() + '.json';
const path = Path.join(__dirname, '../backups/', filename);

await writeFile(path, data);

return await Backup.create({
filename,
local: true
});

};

const createBackupsFromDisk = async () => {

const files = (await readDir(Path.join(__dirname, '../backups/'))).filter((filename) => {

return filename.slice(-5) === '.json';
});

const backups = [];
for (const filename of files) {
backups.push(await Backup.create({
filename,
local: true,
createdAt: new Date(filename).getTime()
}));
}

return backups;
};

const writeFile = (path, data) => {

return new Promise((resolve, reject) => {

Fs.writeFile(path, JSON.stringify(data), (err) => {

if (err) {
return reject(err);
}
resolve(true);
});
});
};

const readFile = (path) => {

return new Promise((resolve, reject) => {

Fs.readFile(path, 'utf8', (err, data) => {

if (err) {
return reject(err);
}
resolve(JSON.parse(data));
});
});
};

const readDir = (path, opts = 'utf8') =>

new Promise((res, rej) => {

Fs.readdir(path, opts, (err, data) => {

if (err) {
rej(err);
}
else {
res(data);
}
});
});
};

module.exports = {
name: 'api-backups',
dependencies: [
'hapi-auth-basic',
'hapi-auth-cookie',
'hapi-auth-jwt2',
'hapi-anchor-model',
'hapi-remote-address'
],
register
};
7 changes: 3 additions & 4 deletions server/models/backup.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,15 @@ Backup.collectionName = 'backups';
Backup.schema = Joi.object({
_id: Joi.object(),
filename: Joi.string().required(),
local: Joi.boolean().required(),
s3: Joi.boolean().required(),
local: Joi.boolean(),
s3: Joi.boolean(),
createdAt: Joi.date(),
updatedAt: Joi.date()
});

Backup.payload = Joi.object({
filename: Joi.string().required(),
local: Joi.boolean().required(),
s3: Joi.boolean().required()
data: Joi.object().required()
});

Backup.routes = Hoek.applyToDefaults(AnchorModel.routes, {
Expand Down

0 comments on commit 734d6a0

Please sign in to comment.