1
0
Fork 0
mirror of https://github.com/codex-team/codex.docs.git synced 2025-08-09 07:25:21 +02:00

Added abiltity to support few pages with same title

This commit is contained in:
DorofeevMark 2018-12-14 22:00:29 +03:00
parent 88172e7d34
commit 77f671b052
8 changed files with 185 additions and 34 deletions

View file

@ -12,6 +12,7 @@
},
"dependencies": {
"@babel/polyfill": "^7.0.0",
"blueimp-md5": "^2.10.0",
"body-parser": "latest",
"codex.editor": "^2.1.3",
"codex.editor.header": "^2.0.5",

View file

@ -1,7 +1,7 @@
const Model = require('../models/page');
const Alias = require('../models/alias');
const aliasTypes = require('../constants/aliasTypes');
const getHashFromString = require('../utils/hash');
const md5 = require('blueimp-md5');
/**
* @class Pages
@ -15,7 +15,7 @@ class Pages {
* @returns {['title', 'body']}
*/
static get REQUIRED_FIELDS() {
return [ 'body' ];
return ['body'];
}
/**
@ -53,20 +53,18 @@ class Pages {
static async insert(data) {
try {
Pages.validate(data);
console.log('data', data);
const page = new Model(data);
const pagePromise = page.save();
const updatedPage = await pagePromise;
pagePromise.then(() => {
const alias = new Alias({
id: page._id,
id: updatedPage._id,
type: aliasTypes.PAGE,
hash: getHashFromString(page.uri).toString()
hash: md5(updatedPage.uri)
});
alias.save();
});
return pagePromise;
} catch (validationError) {
@ -119,10 +117,22 @@ class Pages {
if (!page._id) {
throw new Error('Page with given id does not exist');
}
const oldAlias = page.uri;
page.data = data;
const pagePromise = page.save();
const updatedPage = await pagePromise;
return page.save();
Alias.markAsDeprecated(oldAlias);
const alias = new Alias({
id: updatedPage._id,
type: aliasTypes.PAGE,
hash: md5(updatedPage.uri)
});
alias.save();
return pagePromise;
}
/**

View file

@ -1,11 +1,11 @@
const {aliases: aliasesDb} = require('../utils/database/index');
const getHashFromString = require('../utils/hash');
const md5 = require('blueimp-md5');
/**
* @typedef {Object} AliasData
* @property {string} _id - alias id
* @property {string} hash - alias hash
* @property {string} type - entity type
* @property {boolean} deprecated - indicate if alias deprecated
* @property {string} id - entity id
*
*/
@ -15,6 +15,7 @@ const getHashFromString = require('../utils/hash');
* @property {string} _id - alias id
* @property {string} hash - alias hash
* @property {string} type - entity type
* @property {boolean} deprecated - indicate if alias deprecated
* @property {string} id - entity title
*/
class Alias {
@ -24,7 +25,7 @@ class Alias {
* @returns {Promise<Alias>}
*/
static async get(aliasName) {
const hash = getHashFromString(aliasName).toString();
const hash = md5(aliasName);
const data = await aliasesDb.findOne({hash});
return new Alias(data);
@ -42,25 +43,65 @@ class Alias {
if (data._id) {
this._id = data._id;
}
this.id = data.id;
this.type = data.type;
this.hash = data.hash;
this.data = data;
}
/**
* Save or update page data in the database
* Save or update alias data in the database
*
* @returns {Promise<Alias>}
*/
async save() {
if (!this._id) {
const insertedRow = await aliasesDb.insert({id: this.id, type: this.type, hash: this.hash});
const insertedRow = await aliasesDb.insert(this.data);
} else {
await aliasesDb.update({_id: this._id}, this.data);
}
return this;
}
/**
* Set AliasData object fields to internal model fields
*
* @param {AliasData} aliasData
*/
set data(aliasData) {
const {id, type, hash, deprecated} = aliasData;
this.id = id || this.id;
this.type = type || this.type;
this.hash = hash || this.hash;
this.deprecated = deprecated || false;
}
/**
* Return AliasData object
*
* @returns {AliasData}
*/
get data() {
return {
_id: this._id,
id: this.id,
type: this.type,
hash: this.hash,
deprecated: this.deprecated
};
}
/**
* Mark alias as deprecated
* @param {string} aliasName - alias of entity
* @returns {Promise<Alias>}
*/
static async markAsDeprecated(aliasName) {
const alias = await Alias.get(aliasName);
alias.deprecated = true;
return alias.save();
}
}
module.exports = Alias;

View file

@ -1,5 +1,6 @@
const {pages: pagesDb} = require('../utils/database/index');
const {aliases: aliasesDb} = require('../utils/database/index');
const translateString = require('../utils/translation');
/**
* @typedef {Object} PageData
@ -33,6 +34,17 @@ class Page {
return new Page(data);
}
/**
* Find and return model of page with given uri
* @param {string} uri - page uri
* @returns {Promise<Page>}
*/
static async getByUri(uri) {
const data = await pagesDb.findOne({uri});
return new Page(data);
}
/**
* Find all pages which match passed query object
*
@ -72,7 +84,7 @@ class Page {
this.body = body || this.body;
this.title = this.extractTitleFromBody();
this.uri = uri || this.title.toLowerCase().split(' ').join('-');
this.uri = uri || translateString(this.title.toLowerCase()).split(' ').join('-');
this._parent = parent || this._parent;
}
@ -136,15 +148,29 @@ class Page {
* @returns {Promise<Page>}
*/
async save() {
let newUri = translateString(this.title.toLowerCase()).split(' ').join('-');
let pageWithSameUri = await Page.getByUri(newUri);
let pageWithSameUriCount = 0;
while (pageWithSameUri._id) {
pageWithSameUriCount++;
pageWithSameUri = await Page.getByUri(newUri + `-${pageWithSameUriCount}`);
}
this.uri = pageWithSameUriCount ? newUri + `-${pageWithSameUriCount}` : newUri;
if (!this._id) {
const insertedRow = await pagesDb.insert({
...this.data,
uri: this.title.toLowerCase().split(' ').join('-')
uri: this.uri
});
this._id = insertedRow._id;
} else {
await pagesDb.update({_id: this._id}, this.data);
await pagesDb.update({_id: this._id}, {
...this.data,
uri: this.uri
});
}
return this;

View file

@ -1,10 +0,0 @@
/**
* Function for getting hash from stringToHash
*
* @param stringToHash - stringToHash to encode
* @returns {string} - hash index
*/
module.exports = function getHashFromString(stringToHash) {
return stringToHash.split('').reduce((previousHashValue, currentChar) =>
(((previousHashValue << 5) - previousHashValue) + currentChar.charCodeAt(0)) | 0, 0);
};

78
src/utils/translation.js Normal file
View file

@ -0,0 +1,78 @@
const translationTable = {
'а': 'a',
'б': 'b',
'в': 'v',
'г': 'g',
'д': 'd',
'е': 'e',
'ж': 'g',
'з': 'z',
'и': 'i',
'й': 'y',
'к': 'k',
'л': 'l',
'м': 'm',
'н': 'n',
'о': 'o',
'п': 'p',
'р': 'r',
'с': 's',
'т': 't',
'у': 'u',
'ф': 'f',
'ы': 'i',
'э': 'e',
'А': 'A',
'Б': 'B',
'В': 'V',
'Г': 'G',
'Д': 'D',
'Е': 'E',
'Ж': 'G',
'З': 'Z',
'И': 'I',
'Й': 'Y',
'К': 'K',
'Л': 'L',
'М': 'M',
'Н': 'N',
'О': 'O',
'П': 'P',
'Р': 'R',
'С': 'S',
'Т': 'T',
'У': 'U',
'Ф': 'F',
'Ы': 'I',
'Э': 'E',
'ё': 'yo',
'х': 'h',
'ц': 'ts',
'ч': 'ch',
'ш': 'sh',
'щ': 'shch',
'ъ': '',
'ь': '',
'ю': 'yu',
'я': 'ya',
'Ё': 'YO',
'Х': 'H',
'Ц': 'TS',
'Ч': 'CH',
'Ш': 'SH',
'Щ': 'SHCH',
'Ъ': '',
'Ь': '',
'Ю': 'YU',
'Я': 'YA'
};
/**
* Function to translate string
*
* @param string - string to translate
* @returns {string} - translated string
*/
module.exports = function translateString(string) {
return string.replace(/[А-яёЁ]/g, (char) => translationTable[char] || char);
};

View file

@ -8,7 +8,7 @@
<ul class="docs-aside__section-list">
{% for child in firstLevelPage.children %}
<li>
<a href="/page/{{ child._id }}">
<a href="{{ child.uri }}">
{{ child.title }}
</a>
</li>

View file

@ -1162,6 +1162,11 @@ bluebird@^3.5.1:
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7"
integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==
blueimp-md5@^2.10.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.10.0.tgz#02f0843921f90dca14f5b8920a38593201d6964d"
integrity sha512-EkNUOi7tpV68TqjpiUz9D9NcT8um2+qtgntmMbi5UKssVX2m/2PLqotcric0RE63pB3HPN/fjf3cKHN2ufGSUQ==
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
version "4.11.8"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"