Commit 4086307e authored by Denis Salem's avatar Denis Salem
Browse files

remove index.html for permalink if necessary, progress on path_encode

parent 8f313740
......@@ -38,7 +38,7 @@ disable_chapters: false
disable_categories: true
disable_single_entries: true
banner: 'https://download.tuxfamily.org/dsalem/img/2017_-_Denis_Salem_-_CC_By_SA_-_VenC-logo.svg'
path_encoding: 'windows-1252'
path_encoding: ''
server_port: 8888
sort_by: 'chapter'
enable_jsonld: True
......
......@@ -11,47 +11,45 @@ __blog_configuration.yaml__ est un document Yaml à la racine du projet définis
Immédiatement après avoir créé votre blog, il s'agira sans doute du premier fichier que vous éditerez. Après avoir rempli ces champs dont l'usage est détaillé ci-dessous, vous n'aurez normalement plus besoin d'y retoucher.
- __.:DisableMarkup::blog_name:.__ : Sans surprise, il s'agit du titre de votre blog.
- __.:DisableMarkup::disable_threads:.__ : Empêche VenC de générer les fils de publications spécifiés dans une liste. Les noms de fils peuvent appartenir à des catégories ou à des archives. Ces noms sont listé en étant séparés par une virgule.
- __.:DisableMarkup::disable_archives:.__ : Empêche VenC de générer les fils publications des archives. Ce champ est un booléen, fixé à *False* par défaut.
- __.:DisableMarkup::disable_chapters:.__ : Empêche VenC de générer les chapitres. Ce champ est un booléen, fixé à *True* par défaut.
- __.:DisableMarkup::disable_categories:.__ : Empêche VenC de générer les fils publications des catégories. Ce champ est un booléen, fixé à *False* par défaut.
- __.:DisableMarkup::disable_single_entries:.__ : Empêche VenC de générer les pages des publications individuelles. Ce champ est un booléen, fixé à *False* par défaut.
- __.:DisableMarkup::disable_main_thread:.__ : Empêche VenC de générer le fil principal de publication. Ce champ est un booléen, fixé à *False* par défaut.
- __.:DisableMarkup::disable_rss_feed:.__ : Empêche VenC de générer un flux Atom. Ce champ est un booléen, fixé à *False* par défaut.
- __.:DisableMarkup::disable_atom_feed:.__ : Empêche VenC de générer un flux Atom. Ce champ est un booléen, fixé à *False* par défaut.
- __.:DisableMarkup::text_editor:.__ : L'éditeur de texte choisi pour éditer une nouvelle publication du blog.
- __.:DisableMarkup::date_format:.__ : "%A %d. %B %Y" par défaut. Définit le format de date utilisé à l'intérieur du blog. Le format des dates est en fait le même que celui utilisé par python. Pour en savoir plus sur ce format rendez vous [ici](http://strftime.org).
- __.:DisableMarkup::author_name:.__: Le nom de l'administrateur ou l'auteur du blog.
- __.:DisableMarkup::ftp_host:.__ : Le nom d'hôte de votre serveur FTP.
- __.:DisableMarkup::blog_description:.__ : Un très court résumé de ce dont parle votre site.
- __.:DisableMarkup::blog_keywords:.__ : Les mots clefs associés au site.
- __.:DisableMarkup::author_description:.__ : Un court texte à propos de l'auteur du blog.
- __license__ : La licence appliquée au contenu de votre site.
- __.:DisableMarkup::blog_url:.__ : L'url du blog. Peut être laissée vide, selon le thème utilisé.
- __.:DisableMarkup::ftp_host:.__ : Le nom d'hôte de votre serveur FTP.
- __.:DisableMarkup::blog_language:.__ : Définit la langue du site.
- __.:DisableMarkup::author_email:.__ : Votre adresse e-mail.
- __columns__ : "1" par défaut. Ce champ définit le nombre de colonnes dans une page.
- __.:DisableMarkup::rss_thread_lenght:.__ : "5" par défaut. Définit le nombre de publications à afficher dans le flux RSS.
- __.:DisableMarkup::thread_order:.__ : "latest first" par défaut. Définit l'ordre de publication. Du plus anciens au plus récent, ou l'inverse. Ce champ peut prendre comme valeur soit "oldest first", soit "latest first".
- __.:DisableMarkup::code_highlight_css_override:.__ :
- __path__ : Il s'agit d'une variable contenant différents chemins, vous ne devriez normalement pas avoir besoin d'y toucher. La liste de ces chemins est détaillé ci-dessous
- __ftp__ : Le chemin absolu du répertoire de destination sur votre serveur ftp.
- __entries_sub_folders__ :
- __categories_sub_folders__ :
- __archives_sub_folders__ :
- __.:DisableMarkup::entries_sub_folders:.__ :
- __.:DisableMarkup::categories_sub_folders:.__ :
- __.:DisableMarkup::archives_sub_folders:.__ :
- __.:DisableMarkup::index_file_name:.__ : "index{page_number}.html" par défaut. Le nom de fichier formaté des pages du fil principal de publications. Devrait toujours contenir la variable {page_number}.
- __.:DisableMarkup::category_directory_name:.__ : "{category}" par défaut. Définit le répertoire où sera exporté un fil de publication spécifique à une catégorie de publication. Ce champ devrait donc toujours contenir la variable {category}.
- __.:DisableMarkup::chapter_directory_name:.__ :
- __.:DisableMarkup::archives_directory_name:.__ : "%Y-%m" par défaut. Définit le format de date utilisé pour les noms de répertoires de fils de publications associés à des dates. Le format des dates est en fait le même que celui utilisé par python. Pour en savoir plus sur ce format rendez vous [ici](http://strftime.org).
- __.:DisableMarkup::entry_file_name:.__ : "entry{entry_id}.html" par défaut. Définit le nom de fichier d'une publication unique. Ce champ devrait toujours contenir la variable {entry_id}.
- __.:DisableMarkup::rss_file_name:.__ : "feed.xml" par défaut. Définit le nom de fichier du flux rss.
- __.:DisableMarkup::entries_per_pages:.__ : "10" par défaut. Définit évidemment le nombre de publications par page.
- __columns__ :
- __feed_lenght__ :
- __reverse_thread_order__ :
- __markup_language__ :
- __path_encoding__ :
- __server_port__ :
- __sort_by__ :
- __enable_jsonld__ :
- __enable_jsonp__ :
- __disable_rss_feed__ :
- __disable_atom_feed__ :
- __disable_main_thread__ :
- __disable_threads__ :
- __disable_archives__ :
- __disable_chapters__ :
- __disable_categories__ :
- __disable_single_entries__ :
- __.:DisableMarkup::rss_file_name:.__ : "rss.xml" par défaut. Définit le nom de fichier du flux rss.
- __.:DisableMarkup::atom_file_name:.__ : "atom.xml" par défaut. Définit le nom de fichier du flux atom.
- __.:DisableMarkup::entries_per_pages:.__ : *10* par défaut. Définit le nombre de publications par page.
- __columns__ : 1 par défaut. Ce champ définit le nombre de colonnes dans une page.
- __.:DisableMarkup::feed_lenght:.__ : *5* par défaut. Définit le nombre de publications à afficher dans le flux RSS.
- __.:DisableMarkup::reverse_thread_order:.__ : Définit l'ordre de publication. Du plus récent au plus anciens, ou l'inverse. Ce champ est un booléen, fixé à *True* par défaut.
- __.:DisableMarkup::markup_language:.__ :
- __.:DisableMarkup::path_encoding:.__ :
- __.:DisableMarkup::server_port:.__ :
- __.:DisableMarkup::sort_by:.__ :
- __.:DisableMarkup::enable_jsonld:.__ :
- __.:DisableMarkup::enable_jsonp:.__ :
......@@ -21,6 +21,4 @@
.:Chapters::<ul class="chapter-level{level}">::<li>{index}. <a href="{path}">{title}</a>::</li>::</ul>:.
</aside>
<div id="content">
.:IncludeFile::test.html:.
cd # version 1.0.0 Last minute edition :p
# version 1.0.0 Last minute edition :p
DONE | Copy recursively, if necessary, data from extra.
DONE | Copy recursively, if necessary data from assets.
......@@ -165,6 +165,7 @@ cd # version 1.0.0 Last minute edition :p
DONE | Add IfChapters and use it in academik to hide/show chapters navigation.
DONE | Fix and clean Tessellation theme.
DONE | Add IfInMainThread pattern.
DONE | Make entry URL nicer when filename is index.html and has subfolder.
TODO | Use built in list in yaml instead to turn str to list.
TODO | Fix url with special char in chapter.
WIP | Reorganize themes dependencies in setup.
......@@ -176,6 +177,7 @@ cd # version 1.0.0 Last minute edition :p
TODO | Change nomenclature: Most of the usual patterns are changed. Fix doc.
# version 2.1.x
TODO | Allow markdown2 setup.
TODO | Add --insert-chapter command.
TODO | Warn about metadata that should be list but are str.
TODO | Add folder for blog_configuration, with multiple configuration file (for splitting the actual one).
......@@ -209,7 +211,6 @@ cd # version 1.0.0 Last minute edition :p
TODO | Optimize and refine JSON-LD processing.
TODO | Embed as much as possible microdata/JSON-LD into blog.
TODO | Automatically add entries categories to entries tags.
TODO | Make entry URL nicer when filename is index.html and has subfolder.
TODO | Improve sub folder management in Entry and EntriesThread.
TODO | Optimize objects dereferencing.
TODO | Add draft support.
......
......@@ -57,7 +57,7 @@ def replace_patterns(string):
string = string.replace(".:For::EntryTags:",".:ForEntryTags:")
string = string.replace(".:For::EntryAuthors:",".:ForEntryAuthors:")
string = string.replace(".:For::BlogDates:",".:ForBlogDates:")
string = string.replace(".:For::BlogDates:",".:ForBlogArchives:")
string = string.replace(".:PagesList:",".:ForPages:")
string = string.replace("{0[tag]}", "{value}")
string = string.replace("{0[categoryPath]}", "{path}")
......
......@@ -161,7 +161,7 @@ def new_blog(argv):
"feed_lenght": 5,
"reverse_thread_order": True,
"markup_language": "Markdown",
"path_encoding": "utf-8",
"path_encoding": "",
"server_port": 8888,
"sort_by": "id",
"enable_jsonld": False,
......
......@@ -17,10 +17,11 @@
# You should have received a copy of the GNU General Public License
# along with VenC. If not, see <http://www.gnu.org/licenses/>.
import hashlib
import os
import datetime
import hashlib
import json
import os
import unidecode
from urllib.parse import quote as urllib_parse_quote
......@@ -106,6 +107,9 @@ class DataStore:
self.entries = sorted(self.entries, key = lambda entry : self.sort(entry))
path_categories_sub_folders = self.blog_configuration["path"]["categories_sub_folders"]+'/'
path_archives_directory_name = self.blog_configuration["path"]["archives_directory_name"]
path_chapters_sub_folders = self.blog_configuration["path"]["chapters_sub_folders"]
for entry_index in range(0, len(self.entries)):
current_entry = self.entries[entry_index]
if entry_index > 0:
......@@ -113,7 +117,7 @@ class DataStore:
current_entry.previous_entry = self.entries[entry_index-1]
# Update entriesPerDates
if self.blog_configuration["path"]["archives_directory_name"] != '':
if path_archives_directory_name != '':
formatted_date = current_entry.formatted_date
entries_index = self.get_entries_index_for_given_date(formatted_date)
if entries_index != None:
......@@ -125,18 +129,20 @@ class DataStore:
# Update entriesPerCategories
try:
sub_folders = urllib_parse_quote(self.blog_configuration["path"]["categories_sub_folders"]+'/', encoding=self.path_encoding)
if self.path_encoding == '':
sub_folders = unidecode.unidecode(path_categories_sub_folders).replace(' ','-')
else:
sub_folders = urllib_parse_quote(path_categories_sub_folders, encoding=self.path_encoding)
except UnicodeEncodeError as e:
sub_folders = self.blog_configuration["path"]["categories_sub_folders"]+'/'
notify("\"{0}\": ".format(sub_folders)+str(e), color="YELLOW")
notify("\"{0}\": ".format(path_categories_sub_folders)+str(e), color="YELLOW")
sub_folders = sub_folders if sub_folders != '/' else ''
build_categories_tree(entry_index, current_entry.raw_categories, self.entries_per_categories, self.categories_leaves, self.max_category_weight, self.set_max_category_weight, encoding=self.path_encoding, sub_folders=sub_folders)
self.update_chapters(current_entry)
# build chapters index
chapters_sub_folders = self.blog_configuration["path"]["chapters_sub_folders"]
chapters_sub_folders = path_chapters_sub_folders
for chapter in sorted(self.raw_chapters.keys()):
top = self.chapters_index
index = ''
......@@ -169,14 +175,17 @@ class DataStore:
# Setup BlogArchives Data
self.blog_archives = list()
""" Should use encoding for path value as well """
path_archives_sub_folders = self.blog_configuration["path"]["archives_sub_folders"]+'/'
for node in self.entries_per_archives:
try:
sub_folders = urllib_parse_quote(self.blog_configuration["path"]["archives_sub_folders"]+'/', encoding=self.path_encoding)
if self.path_encoding == '':
sub_folders = unidecode.unidecode(path_archives_sub_folders).replace(' ','-')
else:
sub_folders = urllib_parse_quote(path_archives_sub_folders, encoding=self.path_encoding)
except UnicodeEncodeError as e:
sub_folders = self.blog_configuration["path"]["archives_sub_folders"]+'/'
notify("\"{0}\": ".format(sub_folders)+str(e), color="YELLOW")
notify("\"{0}\": ".format(path_archives_sub_folders)+str(e), color="YELLOW")
sub_folders = sub_folders if sub_folders != '/' else ''
......@@ -416,14 +425,25 @@ class DataStore:
"chapter_name" : sub_chapter.entry.title,
"chapter_index" : sub_chapter.index
})
except KeyError as e:
from venc2.helpers import die
die(messages.variable_error_in_filename.format(e))
try:
if path_encoding == '':
path = unidecode.unidecode(path).replace(' ','-')
else:
path = urllib_parse_quote(path, encoding=path_encoding)
except UnicodeEncodeError as e:
notify("\"{0}\": ".format(chapter_sub_folder)+str(e), color="YELLOW")
output += io.format(**{
"index": sub_chapter.index,
"title": sub_chapter.entry.title,
"path": ".:GetRelativeOrigin:."+urllib_parse_quote(path, encoding=path_encoding),
"path": ".:GetRelativeOrigin:."+path,
"level": level
})
output += self.build_html_chapters(argv, sub_chapter.sub_chapters, level+1)
......
......@@ -20,6 +20,7 @@
import datetime
import os
import time
import unidecode
import urllib.parse
import yaml
......@@ -138,14 +139,29 @@ class Entry:
"entry_id": self.id,
"entry_title": self.title
}
sf = paths["entries_sub_folders"].format(**params).replace(' ','-')
self.sub_folder = urllib.parse.quote(sf, encoding=encoding)+'/' if sf != '' else ''
try:
self.url = ".:GetRelativeOrigin:."+self.sub_folder+urllib.parse.quote(paths["entry_file_name"].format(**params), encoding=encoding)
# TODO MAY BE OPTIMIZED
sf = paths["entries_sub_folders"].format(**params)
if encoding == '':
self.sub_folder = unidecode.unidecode(sf).replace(' ','-').replace('\'','-')+'/' if sf != '' else ''
self.url = ".:GetRelativeOrigin:."+self.sub_folder
if self.sub_folder == '' or paths["entry_file_name"] != "index.html":
self.url += unidecode.unidecode(
paths["entry_file_name"].format(**params)
).replace(' ','-').replace('\'','-')
else:
try:
self.sub_folder = urllib.parse.quote(sf, encoding=encoding)+'/' if sf != '' else ''
self.url = ".:GetRelativeOrigin:."+self.sub_folder
if self.sub_folder == '' or paths["entry_file_name"] != "index.html":
self.url += urllib.parse.quote(paths["entry_file_name"].format(**params), encoding=encoding)
except UnicodeEncodeError as e:
self.url = ".:GetRelativeOrigin:."+self.sub_folder+paths["entry_file_name"].format(**params)
notify("\"{0}\": ".format(sf+paths["entry_file_name"].format(**params))+str(e), color="YELLOW")
except UnicodeEncodeError as e:
self.url = ".:GetRelativeOrigin:."+self.sub_folder+paths["entry_file_name"].format(**params)
notify("\"{0}\": ".format(sf+paths["entry_file_name"].format(**params))+str(e), color="YELLOW")
self.categories_leaves = list()
self.raw_categories = [ c.strip() for c in metadata["categories"].split(',')]
......
......@@ -19,7 +19,7 @@
import datetime
import urllib.parse
import unidecode
from venc2.prompt import notify
class Chapter:
......@@ -57,7 +57,11 @@ def build_categories_tree(entry_index, input_list, output_tree, output_leaves, m
output_leaves.append(root[-1])
try:
root[-1].path = ".:GetRelativeOrigin:."+urllib.parse.quote(path, encoding=encoding)
if encoding == '':
root[-1].path = ".:GetRelativeOrigin:."+unidecode.unidecode(path).replace(' ','-')
else:
root[-1].path = ".:GetRelativeOrigin:."+urllib.parse.quote(path, encoding=encoding)
except UnicodeEncodeError as e:
root[-1].path = ".:GetRelativeOrigin:."+path
notify("\"{0}\": ".format(root[-1].path)+str(e), color="YELLOW")
......
......@@ -20,9 +20,9 @@
import codecs
from copy import deepcopy
from math import ceil
import unidecode
from venc2.prompt import notify
from venc2.prompt import die
from venc2.l10n import messages
from venc2.patterns.exceptions import PatternInvalidArgument
from venc2.patterns.processor import Processor
......@@ -30,6 +30,7 @@ from venc2.patterns.processor import Processor
current_source = None
def undefined_variable(match):
from venc2.prompt import die
die(
messages.undefined_variable.format(
match,
......@@ -46,6 +47,7 @@ class Thread:
self.indentation_level = "│ "
self.patterns_map = patterns_map
self.datastore = datastore
self.path_encoding = datastore.blog_configuration["path_encoding"]
# Notify wich thread is processed
if prompt != "":
notify("├─ "+prompt)
......@@ -73,6 +75,12 @@ class Thread:
for pattern_name in patterns_map.contextual["names"].keys():
self.processor.set_function(pattern_name, getattr(self, patterns_map.contextual["names"][pattern_name]))
def path_encode(self, path):
if self.path_encoding == '':
return unidecode.unidecode(path).replace(' ', '-').replace('\'', '-')
return path
def return_page_around(self, string, params):
try:
return string.format(**params)
......@@ -230,16 +238,21 @@ class Thread:
def format_filename(self, value):
try:
if value == 0:
return self.filename.format(**{
'page_number':''
})
return self.path_encode(
self.filename.format(**{
'page_number':''
})
)
else:
return self.filename.format(**{
'page_number':value
})
return self.path_encode(
self.filename.format(**{
'page_number':value
})
)
except KeyError as e:
from venc2.prompt import die
die(messages.variable_error_in_filename.format(str(e)))
# Overridden in child class (EntriesThread)
......
......@@ -47,7 +47,8 @@ class ArchivesThread(Thread):
notify("│\t "+tree_special_char+"─ "+archive.value+"...")
self.export_path = str("blog/"+self.sub_folders+'/'+archive.value+'/').replace(' ','-')
self.export_path = str("blog/"+self.sub_folders+'/'+archive.value+'/')
self.export_path = self.path_encode(self.export_path)
os.makedirs(self.export_path)
self.organize_entries([
entry for entry in self.datastore.get_entries_for_given_date(
......
......@@ -79,7 +79,7 @@ class CategoriesThread(Thread):
category_as_jsonld["@id"] = blog_url+'/'+self.sub_folders+self.category_value+"categories.jsonld"
category_as_jsonld["url"] = blog_url+'/'+self.sub_folders+self.category_value
dump = json.dumps(category_as_jsonld)
f = open(("blog/"+self.sub_folders+self.category_value+"categories.jsonld").replace(' ','-'), 'w')
f = open((self.export_path+"categories.jsonld").replace(' ','-'), 'w')
f.write(dump)
def setup_category_context(self, i, root, len_root):
......@@ -98,7 +98,7 @@ class CategoriesThread(Thread):
export_path = self.export_path
category_value = self.category_value
self.category_value += node.value+'/'
self.export_path += str(node.value+'/').replace(' ','-')
self.export_path += self.path_encode(node.value)+'/'
self.relative_origin = ''.join([ '../' for f in self.export_path.split("/")[1:] if f != '' ]).replace("//",'/')
try:
......
......@@ -56,10 +56,11 @@ class ChaptersThread(Thread):
notify(self.indentation_level+tree_special_char+"─ "+node.index+' '+node.entry.title+"...")
self.export_path = "blog/"+self.sub_folders+'/'+self.folder_name
self.export_path = self.export_path.replace(' ','-').format(**{
self.export_path = self.export_path.format(**{
"chapter_name" : node.entry.title,
"chapter_index": node.index
})
self.export_path = self.path_encode(self.export_path)
self.relative_origin = ''.join([ '../' for f in self.export_path.split("/")[1:] if f != '' ]).replace("//",'/')
try:
......
......@@ -104,14 +104,15 @@ class EntriesThread(Thread):
'entry_id': self.current_entry.id,
'entry_title': self.current_entry.title
}).replace(' ','-')
export_path = self.path_encode(export_path)
self.relative_origin = str(''.join([ "../" for p in export_path.split('/')[1:] if p != ''])).replace("//",'/')
os.makedirs(export_path, exist_ok=True)
def write_file(self, output, file_id):
export_path = self.export_path.format(**{
export_path = self.path_encode(self.export_path.format(**{
'entry_id': self.current_entry.id,
'entry_title': self.current_entry.title
}).replace(' ','-')
}))
stream = codecs.open(
export_path+'/'+self.format_filename(),
'w',
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment