node를 사용하여 Ghost 블로그를 자동으로 백업하는 방법js
TL:DR: If you're after the source code, check out this [Github Repository](https://github.com/tq-bit/ghost-backups.git):
고스트는 PHP가 구동하는 맏형 워드프레스와 같은 콘텐츠 관리 시스템이다.WP에서 거의 모든 것의 용례 (플러그인) 를 찾을 수 있지만, Ghost의 방법은 Node가 동력을 제공하는 효율적이다.js, 콘텐츠 창설에 전념하는 세분 시장 사용자를 대상으로 뛰어난 개발자 체험을 제공합니다.나는 최근에 그것으로 블로그를 쓰기 시작했는데, 그것이 제공하는 API를 매우 좋아한다.이것이 바로 내가 아래 항목을 세운 동기다.
Note: To follow along, you will need a dedicated instance of Ghost, including a domain and admin access. In case you don't have one but would still like to explore its functionality, there's a demo for the content endpoint. It's read-only, but it'll do. https://demo.ghost.io/ghost/api/v3/content/posts/?key=22444f78447824223cefc48062
선결 조건
당신이 따라야 할 최저 요구는 기계에 설치된 Node.js 작업 실례입니다.나는 Raspberry Pi 3+를 사용하여 백업을 하고 있다. 백업을 저장하는 경로를 알 수 있지만, 다른 컴퓨터도 괜찮다.위에서 설명한 대로 Ghost 인스턴스가 없는 경우에도 사용할 수 있습니다demo.
요컨대 유령 API
고스트는 itheadless CMS를 통해 무두REST admin-endpoint로 조작할 수 있다.읽기 전용content-endpoint도 제공하지만 전자는 어떤 클라이언트를 사용하든 내용에 대해 다양한 방법을 포함한다.그러나 소통을 하려면 몇 가지 간단한 절차가 필요하다.
새로운 Ghost 통합 설정
If you are following along for the content-endpoint, skip this step.
# Make a curl GET request to the ghost demo endpoint in your terminal
$ curl https://demo.ghost.io/ghost/api/v3/content/posts/?key=22444f78447824223cefc48062
개시하다
프로젝트 구조 준비
선택한 디렉터리로 전환하고 새 npm 항목을 초기화합니다:
$ cd /path/to/project
$ npm init -y
다음은 우리 응용 프로그램의 기본 구조를 설정합니다.하나는 구성이고 다른 하나는 서비스입니다.
설정이라고 합니다.js, 또 다른 util.js
npm i chalk isomorphic-fetch jsonwebtoken rimraf
마지막으로, 코드를 실행하기 위해 npm 스크립트를 추가합니다.# Add to your package.json file
{
[...],
scripts: {
"start": "node index"
},
[...]
}
만일 모든 것이 순조롭다면, 당신의 프로젝트는 현재 아래의 구조와 모든 관련 노드 모듈을 설치할 것입니다. 우리는 계속 전진하고 생명을 부여할 준비가 되어 있습니다./
| - config
| | - config.js
| | - util.js
| - node_modules
| - services
| | - backupContent.js
| - index.js
구성 설정
다음 코드를 설정에 추가합니다.js 파일.여기서 정의한 변수는 다음과 같은 용도로 API 및 백업 구성 정보를 포함합니다.
변수 이름
의 목적
고스타피울
ghost 관리 종결점의 루트 경로
ghostApiPaths
백업 데이터를 가져올 경로
고스타틴기
이전에 기록한 통합 관리 키
백업 간격
업데이트 간격(밀리초)
백업 경로
백업 컴퓨터에 저장된 데이터의 경로
시간을 거슬러 올라가다
오래된 업데이트를 보존하는 데 몇 달이 걸린다
genBackupDirPath
고유 백업 디렉토리 생성 함수
const { join } = require('path');
// Configure the relevant API params
const ghostApiUrl = 'https://<your-ghost-domain>/ghost/api/v3/admin';
// If you are following along with the demo, uncomment the following:
// const ghostApiUrl = 'https://demo.ghost.io/ghost/api/v3/content/'
// Also, make sure to append the query in the service that utilizes this parameter
const ghostApiPaths = ['posts', 'pages', 'site', 'users'];
const ghostAdminKey = '<your-admin-key>';
// Configure the backup settings
const backupInterval = 1000 /* Miliseconds */ * 60 /* Seconds */ * 60 /* Minutes */ * 24 /* Hours*/ * 1; /* Days */
const backupDirPath = '/home/pi/Backups';
const backupLifetime = 4; /* Months */
const genBackupDirPath = () => {
const date = new Date();
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, 0);
const day = date.getDate().toString().padStart(2, 0);
const hour = date.getHours().toString().padStart(2, 0);
const min = date.getMinutes().toString().padStart(2, 0);
const now = `${year}_${month}_${day}-${hour}_${min}`;
return join(backupDirPath, now);
};
module.exports = {
ghostApiUrl,
ghostApiPaths,
ghostAdminKey,
backupInterval,
backupLifetime,
backupDirPath,
genBackupDirPath,
};
유틸리티 함수 준비
백업 서비스에는 두 가지 유틸리티가 필요합니다.
// Import the necessary functions
const { promises } = require('fs');
const { sign } = require('jsonwebtoken');
const rimraf = require('rimraf');
/**
* @desc Create the authorization header to authenticate against the
* Ghost admin-endpoint
*
* @param {String} ghostAdminKey
*
* @returns {Object} The headers to be appended to the http request
*/
function genAdminHeaders(ghostAdminKey) {
// Extract the secret from the Ghost admin key
const [id, secret] = ghostAdminKey.split(':');
// Create a token with an empty payload and encode it.
const token = sign({}, Buffer.from(secret, 'hex'), {
keyid: id,
algorithm: 'HS256',
expiresIn: '5m',
audience: '/v3/admin',
});
// Create the headers object that's added to the request
const headers = {Authorization: `Ghost ${token}`}
return headers;
}
/**
* @desc Delete backup directories that are older than the backupLifetime.
*
* @param {String} dirPath The path to where backups are being stored
* @param {Number} backupLifetime The amount of months a backup is to be stored
*
* @returns {Array} An array of paths that have been deleted
*/
async function deleteOldDirectories(dirPath, backupLifetime) {
const dir = await promises.opendir(dirPath);
let deletedBackups = [];
for await (const dirent of dir) {
const date = new Date();
const year = date.getFullYear();
const month = date.getMonth() + 1;
// For each backup entry, extract the year and month in which is was created
const createdYear = +dirent.name.split('_')[0];
const createdMonth = +dirent.name.split('_')[1];
// In case backup was made this year,
// check if createdMonth + lifetime are less than current month
if (createdYear === year) {
if (createdMonth - backupLifetime >= month) {
deletedBackups.push(dirent.name)
rimraf.sync(`${dirPath}/${dirent.name}`)
}
}
// In case backup was made last year,
// check if createdMonth + lifetime is smaller than 12
else {
if (createdMonth + backupLifetime <= 12) {
deletedBackups.push(dirent.name)
rimraf.sync(`${dirPath}/${dirent.name}`)
}
}
}
return deletedBackups;
}
module.exports = { getAdminHeaders, deleteOldDirectories };
쓰기 서비스
다음 내용을 백업 내용에 추가합니다.js 파일.무슨 일이 일어났는지 알고 싶으면 코드의 주석을 고려하십시오.
// Load relevant core package functions
const { join } = require('path');
const { mkdirSync, writeFileSync } = require('fs');
const { log } = require('console');
// Load npm modules
const fetch = require('isomorphic-fetch');
const { red, yellow, green } = require('chalk');
// Load config and utility functions
const { ghostApiUrl, ghostApiPaths, ghostAdminKey, backupDirPath, genBackupDirPath, backupLifetime } = require('../config/config');
const { genAdminHeaders, deleteOldDirectories } = require('../config/util');
// Main function for the backup service
async function runBackupContent() {
log(green(`⏳ Time to backup your content. Timestamp: ${new Date()}`));
try {
// Generate the backup directory and the authorization headers
const dir = genBackupDirPath();
const headers = genAdminHeaders(ghostAdminKey);
// e.g. /home/pi/Backups/2021_01_02-13_55/site.json
mkdirSync(dir);
// Check for old backups and clean them up
const deleted = deleteOldDirectories(backupDirPath, backupLifetime);
if (deleted.length > 0) {
deleted.forEach(deletedBackup => log(yellow(`☝ Deleted backup from ${deletedBackup}`)));
} else {
log(green('✅ No old backups to be deleted'));
}
// Make a backup for all the content specified in the api paths config
ghostApiPaths.forEach(async path => {
// Create the relevant variables
// The endpoint from where to receive backup data
// e.g. https://<your-ghost-domain>/ghost/api/v3/admin/posts
const url = `${ghostApiUrl}/${path}`;
// These options.headers will hold the Json Webtoken
// e.g. 'Authorization': 'Ghost eybf12bf.8712dh.128d7g12'
const options = { method: 'get', timeout: 1500, headers: { ...headers } };
// The name of the corresponding backup file in json
// e.g. posts.json
const filePath = join(dir, path + '.json');
const response = await fetch(url, options);
// If the http status is unexpected, log the error down in a separate file
if (response.status !== 200) {
const errPath = join(dir, path + 'error.json');
const data = await response.json();
writeFileSync(errPath, jsonStringify(data));
log(red(`❌ ${new Date()}: Something went wrong while trying to backup ${path}`));
// If the http status is returned as expected, write the result to a file
} else {
const data = await response.json();
writeFileSync(filePath, JSON.stringify(data));
log(green(`✅ Wrote backup for '${path}' - endpoint into ${filePath}`));
}
});
} catch (e) {
// Do appropriate error handling based on the response code
switch (e.code) {
// If, for some reason, two backups are made at the same time
case 'EEXIST':
log(red('❌ Tried to execute a backup for the same time period twice. Cancelling ... '));
break;
default:
log(red(e.message));
break;
}
}
}
module.exports = runBackupContent;
서비스 완료 및 실행
우리가 이룩한 성과를 간단명료하게 회고합시다
이제 이 서비스를 색인에 가져옵니다.js 파일 및 실행
// Load node modules
const { log } = require('console');
const { green } = require('chalk');
// Load the backup interval from the configuration
const { backupInterval } = require('./config/config');
// Load the service
const runBackupContent = require('./services/backupContent');
// Start the service with the given interval
log(green(`⏳ Scheduled backup job with a ${backupInterval / (1000 * 60 * 60)} - hour interval`));
runBackupContent();
setInterval(() => runBackupContent(), backupInterval);
그런 다음 콘솔에서 시작 스크립트를 실행합니다.$ npm run start
# Or run index directly
$ node index
다른 모든 것이 순조롭다고 가정하면 다음 콘솔 출력을 볼 수 있습니다.이제 당신은 그것을 가지고 있습니다. 기본적이지만 효과적인 블로그 게시물 백업 서비스입니다.
다음 단계 및 추가 기능
다음과 같은 기능도 포함될 수 있습니다.
This post was originally published at https://q-bit.me/how-to-make-backups-of-your-ghost-blog-with-node-js/
읽어주셔서 감사합니다.이 글이 마음에 드시면 트위터에 연락 주세요.🐤
Reference
이 문제에 관하여(node를 사용하여 Ghost 블로그를 자동으로 백업하는 방법js), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/tqbit/how-to-make-automated-backups-of-your-ghost-blog-with-node-js-12aj텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)