feat(Directus): Mise à jour de l'export Directus
This commit is contained in:
parent
8d6c4b429f
commit
daa3a528fd
32
.drone.yml
32
.drone.yml
|
@ -2,38 +2,31 @@
|
|||
# drone encrypt weko/lestoitsduval $REGISTRY_PASSWORD
|
||||
kind: secret
|
||||
name: REGISTRY_PASSWORD
|
||||
data: RrJX1Ir1Fqp83P43po3iQh4RE+SULN060LDe/PkEYw+mxPLrdDREEoQNKfh8RvAMjvocNojY9OuxXaZSpC72GOpi8qzslnHAbHhQfCX/
|
||||
data: Q/Y+XPpJN0vxgDWzGVIVUZJ8PE0ngvYT/1NEFG+ZfnvoFa1c+ZSkhCeMk8OE/IC12Uw2VGebBsD1iCrkffKnA5GPIS+uCmtF1K/2o4+/
|
||||
|
||||
---
|
||||
# drone encrypt weko/lestoitsduval $REGISTRY_USER
|
||||
kind: secret
|
||||
name: REGISTRY_USER
|
||||
data: fyPAM/EECUhDI5XGhj3RbQWgzbGija2DAwepuAWmnEx1+A==
|
||||
data: wr3cyRh4G34wu8sbhEm96IUXZft0rDeGkkc5M/1N501H9Q==
|
||||
|
||||
---
|
||||
# drone encrypt weko/lestoitsduval "{\"auths\":{\"https://registry.weko.io\":{\"auth\":\"$(echo -n "$REGISTRY_USER:$REGISTRY_PASSWORD" | base64)\",\"email\":\"$REGISTRY_USER\"}}}"
|
||||
kind: secret
|
||||
name: REGISTRY_CONFIG
|
||||
data: NsJ77R/8TEmyCM7h6OXkOeGhKAdctofukKezjfjIMGaBv5aGYN4CKYCIBlLsBWfFvMb+0SIDqrExyLw4i5dFWfDepwdNacJXNRmjIEkxuaJmvGxV8BZpcof28LjhB4psKrKjmTFpGioS3kG1MRfnljD/AlwckUd6S4KYNfGgJW0hQccxbamW9M0tqagPddayGEDghwxUfzqQk937rmOV7ngI+mon9f4DCWVA
|
||||
data: lmQ25YQEai7VpYj8lUz9859JAV/aeQ9V5ulZhqVVQcni8usA9LF2IQFisekF69yu6ksp+9PBDHNKQA4GX7N/tFAlEdJySHUyr3qtrjUXRBs54E1G/GHVzY1/NwCytIT8Ro9d9H0XRiAbGnOQA2sjPFcb7CZ5kDZRmNHHHq6fplOdIM5ysYhiDIYH7TW+7dYm4ke8SBFhk4oKR7OMsAC+mo9++2dJ5W0FCro/
|
||||
|
||||
---
|
||||
# drone encrypt weko/lestoitsduval $DIRECTUS_URL
|
||||
kind: secret
|
||||
name: DIRECTUS_URL
|
||||
data: 8yxEqiZv9pFrjT9kS7kMkuG3M0ezKsWf8EVrYqc2U5MpE1iVBOwj87DXJ4UVWZ5t7INKpDmxi2Nk6mXM
|
||||
data: hYUC351igGt4WLCCbtrT1R3szBAuzdEv/n1J6onJJRQUTLZ8v4Hj/wysho0smBsASoZv/hzdZrPRy0gi
|
||||
|
||||
---
|
||||
# drone encrypt weko/lestoitsduval $DIRECTUS_EMAIL
|
||||
# drone encrypt weko/lestoitsduval $DIRECTUS_TOKEN
|
||||
kind: secret
|
||||
name: DIRECTUS_EMAIL
|
||||
data: L+dV9HpRrUTjv7/CI2LHPJr8X2778GoHLswMNUamNMqiAgbQGr6agdU=
|
||||
|
||||
---
|
||||
|
||||
# drone encrypt weko/lestoitsduval $DIRECTUS_PASSWORD
|
||||
kind: secret
|
||||
name: DIRECTUS_PASSWORD
|
||||
data: h5KEej5axDgJgrP9CSmtoA8gyScxGU2oSInrFon5fCuzFdJYDUtJIiNSKXJspwztaOZ+VaF4aq4KoX9KYuq6Zp2rsPJlFkZc
|
||||
name: DIRECTUS_TOKEN
|
||||
data: 1aojESEVwAY0jmHQfpWt5bGbbnMtFiv6mQMEQjC368oJZeMSFPTZL9/mTQAAqSbEHyEHV1r19Hf/k/Oq
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
|
@ -54,21 +47,16 @@ steps:
|
|||
- name: install npm
|
||||
image: node:current-alpine
|
||||
volumes:
|
||||
- name: hugo-theme-directus-import_node_modules
|
||||
path: /drone/src/themes/hugo-theme-directus-import/node_modules
|
||||
- name: hugo-theme-lowtech_node_modules
|
||||
path: /drone/src/themes/hugo-theme-lowtech/node_modules
|
||||
environment:
|
||||
DIRECTUS_URL:
|
||||
from_secret: DIRECTUS_URL
|
||||
DIRECTUS_EMAIL:
|
||||
from_secret: DIRECTUS_EMAIL
|
||||
DIRECTUS_PASSWORD:
|
||||
from_secret: DIRECTUS_PASSWORD
|
||||
DIRECTUS_TOKEN:
|
||||
from_secret: DIRECTUS_TOKEN
|
||||
commands:
|
||||
- (cd themes/hugo-theme-lowtech && npm i)
|
||||
- (cd themes/hugo-theme-directus-import && npm i)
|
||||
- node themes/hugo-theme-directus-import/import.js
|
||||
- node scripts/directus-to-markdown/index.js
|
||||
|
||||
- name: build website
|
||||
image: jakejarvis/hugo-extended
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import DirectusToMarkdown from '@resilien/directus-to-markdown'
|
||||
import urlslug from 'url-slug'
|
||||
|
||||
const config = {
|
||||
contentKey: 'body',
|
||||
collections: {
|
||||
actualites: {
|
||||
readManyOption: {
|
||||
fields: ['title', 'slug', 'date', 'image', 'image_credit', 'draft', 'body'],
|
||||
filter: { draft: { _eq: 'false' } }
|
||||
},
|
||||
pathBuilder: (article) => {
|
||||
if (article.slug) {
|
||||
return `./content/actualites/${article.slug}`
|
||||
}
|
||||
return `./content/actualites/${article.date}-${urlslug(article.title, { remove: /\./g })}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new DirectusToMarkdown(config).export();
|
1
scripts/directus-to-markdown/node_modules/@resilien/directus-to-markdown
generated
vendored
Symbolic link
1
scripts/directus-to-markdown/node_modules/@resilien/directus-to-markdown
generated
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../../themes/hugo-theme-lowtech/node_modules/@resilien/directus-to-markdown
|
|
@ -0,0 +1 @@
|
|||
../../../themes/hugo-theme-lowtech/node_modules/url-slug
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "directus-to-markdown",
|
||||
"version": "0.0.0",
|
||||
"description": "Translates content from Directus.io to gohugo.io",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@resilien/directus-to-markdown": "file:../../themes/hugo-theme-lowtech/node_modules/@resilien/directus-to-markdown",
|
||||
"url-slug": "file:../../themes/hugo-theme-lowtech/node_modules/url-slug"
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
node_modules
|
|
@ -1,23 +0,0 @@
|
|||
const DirectusHugoDriver = require('.');
|
||||
|
||||
const driverOptions = {
|
||||
url: process.env.DIRECTUS_URL,
|
||||
email: process.env.DIRECTUS_EMAIL,
|
||||
password: process.env.DIRECTUS_PASSWORD,
|
||||
buildDrafts: false,
|
||||
collections: {
|
||||
'actualites': {
|
||||
pathBuilder: (path, article, urlslug) => {
|
||||
if (article.slug) {
|
||||
return `${path}/actualites/${article.slug}`
|
||||
}
|
||||
return `${path}/actualites/${article.date}-${urlslug(article.title, { remove: /\./g })}`;
|
||||
}
|
||||
}
|
||||
},
|
||||
content: {
|
||||
path: './content'
|
||||
}
|
||||
}
|
||||
const driver = new DirectusHugoDriver(driverOptions);
|
||||
driver.import()
|
|
@ -1,241 +0,0 @@
|
|||
const util = require('util');
|
||||
|
||||
const DirectusSDK = require('@directus/sdk-js');
|
||||
const yaml = require('js-yaml');
|
||||
const urlslug = require('url-slug');
|
||||
const fs = require('fs');
|
||||
const mime = require('mime-types');
|
||||
|
||||
const express = require('express')
|
||||
const bodyParser = require('body-parser');
|
||||
|
||||
const { exec } = require("child_process");
|
||||
|
||||
const uuidregex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
||||
|
||||
|
||||
class Driver {
|
||||
constructor(config = {}, directusConfig = {}){
|
||||
this.url = config.url || 'http://localhost:8055';
|
||||
this.email = config.email || '';
|
||||
this.password = config.password || '';
|
||||
this.frontMatter = (config.frontMatter && config.frontMatter.toUpperCase()) || 'YAML'; // TODO: Add TOML and JSON frontmatter support
|
||||
this.collection = config.collection
|
||||
this.collections = config.collections
|
||||
|
||||
this.content = {}
|
||||
this.content.path = (config.content && config.content.path) ? config.content.path : 'content';
|
||||
this.content.home = (config.content && config.content.home) ? config.content.home.toLowerCase() : 'home';
|
||||
this.content.index = (config.content && config.content.index) ? config.content.index.toLowerCase() : 'index';
|
||||
this.content.map = (config.content && config.content.map) ? config.content.map : [];
|
||||
|
||||
this.directus = new DirectusSDK(this.url, directusConfig);
|
||||
|
||||
this.pathMethod = config.pathBuilder || this._pathBuilder;
|
||||
this._auth = null;
|
||||
|
||||
this.buildDrafts = config.buildDrafts || false;
|
||||
// Auto-rebuild server related
|
||||
this.buildPort = config.buildPort || 8060;
|
||||
this.buildHost = config.buildHost || 'http://localhost';
|
||||
this.autoWebhook = config.autoWebhook || true;
|
||||
}
|
||||
|
||||
_checkAuth(){
|
||||
return new Promise(resolve => {
|
||||
if (this.email && this.password && this._auth === null){
|
||||
this._auth = this.directus.auth.login({ email: this.email, password: this.password })
|
||||
.then(() => {
|
||||
console.info('Login with user', this.email);
|
||||
resolve()
|
||||
})
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
static emptyPromise(){
|
||||
return new Promise(resolve => resolve())
|
||||
}
|
||||
|
||||
getCollections(){
|
||||
return this.directus.collections.read()
|
||||
// Let not following .then() confuse you. It is an arrow function running an arrow filter.
|
||||
// The Directus internal system fields have "meta.system == true" and those we discard here.
|
||||
// .then(data => {
|
||||
// console.log(util.inspect(data, false, null, true /* enable colors */))
|
||||
// return data
|
||||
// })
|
||||
.then(data => data.data.filter(collection => !collection.meta.system))
|
||||
}
|
||||
|
||||
/**
|
||||
* Build path string where the articles will be stored exlcluding individual article slug
|
||||
* @param {*} article
|
||||
* @param {*} collection
|
||||
* @returns {string}
|
||||
*/
|
||||
_pathBuilder(article, collection){
|
||||
console.log('article', article);
|
||||
// console.log('collection', collection);
|
||||
|
||||
if (this.collections && this.collections[collection.collection] && this.collections[collection.collection].pathBuilder) {
|
||||
return this.collections[collection.collection].pathBuilder(this.content.path, article, urlslug)
|
||||
}
|
||||
|
||||
if (this._isHome(article, collection)) {
|
||||
return `${this.content.path}`;
|
||||
}
|
||||
if (this._isBranch(article, collection) || this._isPage(article, collection)){
|
||||
return `${this.content.path}/${collection.collection}`;
|
||||
}
|
||||
|
||||
const [year, mouth, day] = article.date.split('-')
|
||||
return `${this.content.path}/actualites/${year}/${mouth}/${article.date.replaceAll('-', '_')}-${urlslug(article.title, { remove: /\./g })}`;
|
||||
}
|
||||
|
||||
_isHome(article, collection){
|
||||
return (collection.meta.singleton === true && collection.collection === this.content.home)
|
||||
}
|
||||
|
||||
_isBranch(article, collection){
|
||||
return (collection.meta.singleton === false && article.title.toLowerCase() === this.content.index)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
_isPage(article, collection){
|
||||
return (collection.meta.singleton === true)
|
||||
}
|
||||
|
||||
_formatFrontMatter(article, collection = {}){
|
||||
let front = { ...article };
|
||||
|
||||
// Manipulate some variable property names
|
||||
if (front.date_created){
|
||||
if (!front.date) {
|
||||
front.date = front.date_created
|
||||
}
|
||||
delete front.date_created
|
||||
}
|
||||
if (front.date_updated){
|
||||
front.lastmod = front.date_updated
|
||||
delete front.date_updated
|
||||
}
|
||||
delete front.body
|
||||
|
||||
// Finally, transform from object to string
|
||||
if (this.frontMatter === 'YAML'){
|
||||
front = `---\r\n${yaml.safeDump(front).trim()}\r\n---\r\n`
|
||||
}
|
||||
return front
|
||||
}
|
||||
|
||||
static _writeFileStream(path, readstream, passtrough = {}){
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileWriter = fs.createWriteStream(path);
|
||||
fileWriter.on('finish', () => {
|
||||
resolve(passtrough)
|
||||
});
|
||||
fileWriter.on('error', error => {
|
||||
console.log(error)
|
||||
fileWriter.close();
|
||||
reject(error);
|
||||
});
|
||||
readstream.pipe(fileWriter);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {object} article
|
||||
* @param {object} collection
|
||||
* @returns {promise}
|
||||
*/
|
||||
_importItem(originArticle, collection){
|
||||
const article = { ...originArticle }
|
||||
const itemPath = this.pathMethod(article, collection);
|
||||
const indexName = this._isHome(article, collection) || this._isBranch(article, collection) || this._isPage(article, collection) ? '_index' : 'index'
|
||||
|
||||
// Only continue if this is a published article or we have explicitly set to import Drafts
|
||||
// Archived items would be always discarded
|
||||
|
||||
if ((article.status === 'archived') || (article.draft === 'true' && this.buildDrafts === false)){
|
||||
return Driver.emptyPromise();
|
||||
}
|
||||
|
||||
// if ((article.status !== 'published') && (article.status === 'draft' && this.buildDrafts === false)){
|
||||
// return Driver.emptyPromise();
|
||||
// }
|
||||
|
||||
if (!fs.existsSync(itemPath)){
|
||||
fs.mkdirSync(itemPath, { recursive: true });
|
||||
}
|
||||
|
||||
const writePromises = []
|
||||
|
||||
for (const [key, value] of Object.entries(article)){
|
||||
// TODO: instead of trying to pull asset and hope for the best,
|
||||
// crosscheck things with the /fields and play by the rules
|
||||
if (typeof value === 'string' && value.match(uuidregex)) {
|
||||
// console.log([key, value]);
|
||||
|
||||
const downloadPromise = this.directus.axios.get(`assets/${value}?download`, { responseType: 'stream' })
|
||||
.then(response => {
|
||||
const disposition = response.headers['content-disposition'].match(/filename="(.*)"/);
|
||||
const downloadName = disposition ? disposition[1] : `${value}.${mime.extension(response.headers['content-type'])}`;
|
||||
const savePath = `${itemPath}/${downloadName}`;
|
||||
return Driver._writeFileStream(savePath, response.data, { key, downloadName })
|
||||
})
|
||||
.then(passtrough => {
|
||||
article[passtrough.key] = passtrough.downloadName
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.response && error.response.status && error.response.status !== 403) {
|
||||
console.error(error.response.status, error.response.statusText)
|
||||
}
|
||||
});
|
||||
writePromises.push(downloadPromise);
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(writePromises).then(() => {
|
||||
const frontMatter = this._formatFrontMatter(article, collection);
|
||||
const itemContent = `${frontMatter}${article.body ? article.body.toString() : ''}`
|
||||
fs.writeFileSync(`${itemPath}/${indexName}.md`, itemContent)
|
||||
})
|
||||
}
|
||||
|
||||
_importCollection(collection){
|
||||
const col = this.directus.items(collection.collection).read() // TODO: IMPORTANT handle pagination when a lot of content in CMS
|
||||
return col
|
||||
.then(data => {
|
||||
// normalize to always have an array of content.
|
||||
const content = (collection.meta.singleton === true) ? [data.data] : data.data;
|
||||
return content.map(article => this._importItem(article, collection))
|
||||
})
|
||||
}
|
||||
|
||||
import() {
|
||||
console.info('Let\'s import from', this.url);
|
||||
this._checkAuth()
|
||||
.then(() => this.getCollections())
|
||||
.then(collections => {
|
||||
if (this.collections) {
|
||||
return collections.filter(collection => Object.keys(this.collections).includes(collection.collection))
|
||||
}
|
||||
return collections
|
||||
})
|
||||
.then(collections => {
|
||||
return collections.map(collection => this._importCollection(collection))
|
||||
})
|
||||
.then(collectionPromises => {
|
||||
return Promise.all(collectionPromises)
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Driver
|
File diff suppressed because it is too large
Load Diff
|
@ -1,41 +0,0 @@
|
|||
{
|
||||
"name": "directus-hugo-driver",
|
||||
"version": "0.0.0",
|
||||
"description": "Translates content from Directus.io to gohugo.io",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/pilskalns/directus-hugo-driver.git"
|
||||
},
|
||||
"keywords": [
|
||||
"directus",
|
||||
"hugo",
|
||||
"npm",
|
||||
"cms",
|
||||
"headless",
|
||||
"headless-cms",
|
||||
"automation"
|
||||
],
|
||||
"author": "Andžs Pilskalns",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/pilskalns/directus-hugo-driver/issues"
|
||||
},
|
||||
"homepage": "https://github.com/pilskalns/directus-hugo-driver#readme",
|
||||
"dependencies": {
|
||||
"@directus/sdk-js": "^9.0.0-rc.32",
|
||||
"body-parser": "^1.19.0",
|
||||
"express": "^4.17.1",
|
||||
"js-yaml": "^3.14.1",
|
||||
"mime-types": "^2.1.28",
|
||||
"url-slug": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^7.18.0",
|
||||
"eslint-config-airbnb-base": "^14.2.1",
|
||||
"eslint-plugin-import": "^2.22.1"
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
Subproject commit 437ab76c51a94e646333f77162934b147b5163ac
|
||||
Subproject commit fde8378910aef64dca93c2931f79c509352e6da2
|
Loading…
Reference in New Issue