Commit 0bdbb65e authored by Denis Salem's avatar Denis Salem
Browse files

wip on custom sub folders

parent 14b4e593
......@@ -126,9 +126,9 @@
DONE | Export empty blog.
DONE | Allow disabling exportation of specific kind of thread.
DONE | Add categories tree in entry.
DONE | Remove illegal character from path.
DONE | Remove illegal character from paths.
DONE | Add support for embed content (oEmbed)
TODO | Export entry in nicely named folder instead of permalink
WIP | Add custom subfolders
TODO | Client-side search engine.
TODO | Fix unit test.
TODO | Serv page.
......@@ -139,6 +139,7 @@
TODO | fix FAQ https://stackoverflow.com/questions/14547631/python-locale-error-unsupported-locale-setting.
TODO | fix FAQ latex2mathml is incomplete.
TODO | fix FAQ categories separator is ' > ', not '>'
TODO | fix FAQ subfolders must not start with '/'
TODO | Change nomenclature: Most of the usual patterns are changed. Fix doc.
TODO | Add translation for Deutsch and Spanish.
......@@ -149,3 +150,4 @@
TODO | Access {count} and {weight} from LeavesForEntrycategories.
TODO | Split unit-test and themes from main branch
TODO | Add Yaml comments in blog configuration
TODO | Catch invalid encoding at startup
<div class="entry .:GetEntryMetadataIfExists::CSS:." id="entry.:GetEntryID:." data-venc-tags=".:ForEntryTags::{0[tag]}:: :.">
<div class="permalink">
<h1><a href=".:GetRelativeOrigin:.entry.:GetEntryID:..html">.:GetEntryTitle:.</a></h1>
<h1><a href=".:GetRelativeOrigin:..:GetEntryURL:.">.:GetEntryTitle:.</a></h1>
<p>.:GetEntryDate:.</p>
</div>
.:GetEntryContent:.
......
......@@ -18,7 +18,7 @@
<body>
<header>
<h1>
<a href=".:IfInThread:: ../.:GetRelativeOrigin:. :: index.html :. ">
<a href=".:IfInThread:: .:GetRelativeOrigin:. :: index.html :. ">
<img id="banner" src=".:GetRelativeOrigin:..:GetBlogMetadataIfExists::banner:." alt=".:GetBlogName:." title=".:GetBlogName:." />
</a>
</h1>
......
......@@ -125,6 +125,9 @@ def new_blog(argv):
"author_email": messages.your_email,
"code_highlight_css_override": False,
"path": {"ftp": messages.ftp_path,
"entries_sub_folders": "",
"categories_sub_folders": "",
"dates_sub_folders": "",
"index_file_name": "index{page_number}.html",
"category_directory_name": "{category}",
"dates_directory_name": "%Y-%m",
......
......@@ -20,6 +20,7 @@
import hashlib
import json
import os
import urllib.parse
from venc2.datastore.configuration import get_blog_configuration
from venc2.datastore.entry import yield_entries_content
......@@ -52,11 +53,11 @@ class DataStore:
entry_index = 0
for filename in yield_entries_content():
if len(self.entries):
self.entries.append(Entry(filename, previous_entry = self.entries[-1], encoding=self.blog_configuration["path_encoding"]))
self.entries.append(Entry(filename, self.blog_configuration["path"], previous_entry = self.entries[-1], encoding=self.blog_configuration["path_encoding"]))
self.entries[-2].next_entry = self.entries[-1]
else:
self.entries.append(Entry(filename))
self.entries.append(Entry(filename, self.blog_configuration["path"], encoding=self.blog_configuration["path_encoding"]))
''' Update entriesPerDates '''
if self.blog_configuration["path"]["dates_directory_name"] != '':
......@@ -70,15 +71,20 @@ class DataStore:
''' Update entriesPerCategories '''
build_categories_tree(entry_index, self.entries[-1].raw_categories, self.entries_per_categories, self.categories_leaves, self.max_category_weight, self.set_max_category_weight, encoding=self.blog_configuration["path_encoding"])
sub_folders = urllib.parse.quote(self.blog_configuration["path"]["categories_sub_folders"]+'/', encoding=self.blog_configuration["path_encoding"])
sub_folders = sub_folders if sub_folders != '/' else ''
build_categories_tree(entry_index, self.entries[-1].raw_categories, self.entries_per_categories, self.categories_leaves, self.max_category_weight, self.set_max_category_weight, encoding=self.blog_configuration["path_encoding"], sub_folders=sub_folders)
entry_index += 1
''' Setup BlogDates Data '''
self.blog_dates = list()
for node in self.entries_per_dates:
sub_folders = urllib.parse.quote(self.blog_configuration["path"]["dates_sub_folders"]+'/', encoding=self.blog_configuration["path_encoding"])
sub_folders = sub_folders if sub_folders != '/' else ''
self.blog_dates.append({
"date":node.value,
"dateUrl": ".:GetRelativeOrigin:."+node.value,
"dateUrl": ".:GetRelativeOrigin:."+sub_folders+node.value,
"count": node.count,
"weight": node.weight
})
......@@ -169,9 +175,16 @@ class DataStore:
return self.entries[self.requested_entry_index].date.strftime(self.blog_configuration["path"]["dates_directory_name"])
def get_entry_url(self, argv=list()):
return self.blog_configuration["path"]["entry_file_name"].format(**{
"entry_id" : self.entries[self.requested_entry_index].id
sub_folders = self.blog_configuration["path"]["entries_sub_folders"].format(**{
"entry_id" : self.entries[self.requested_entry_index].id,
"entry_title" : self.entries[self.requested_entry_index].title
})
sub_folders = sub_folders+'/' if sub_folders != '' else ''
filename = self.blog_configuration["path"]["entry_file_name"].format(**{
"entry_id" : self.entries[self.requested_entry_index].id,
"entry_title" : self.entries[self.requested_entry_index].title
})
return urllib.parse.quote(sub_folders+filename, encoding=self.blog_configuration["path_encoding"])
def get_author_name(self, argv=list()):
return self.blog_configuration["author_name"]
......
......@@ -66,7 +66,10 @@ def get_blog_configuration():
"dates_directory_name",
"entry_file_name",
"rss_file_name",
"ftp"
"ftp",
"entries_sub_folders",
"categories_sub_folders",
"dates_sub_folders"
]
for field in mandatory_fields:
......
......@@ -54,7 +54,7 @@ class EntryWrapper:
die(messages.missing_entry_content_inclusion)
class Entry:
def __init__(self, filename, previous_entry = None, encoding="utf-8"):
def __init__(self, filename, sub_folders, previous_entry = None, encoding="utf-8"):
self.previous_entry = previous_entry
self.next_entry = None
......@@ -134,7 +134,7 @@ class Entry:
pass
self.categories_tree = []
build_categories_tree(-1, self.raw_categories, self.categories_tree, None, -1, encoding=encoding)
build_categories_tree(-1, self.raw_categories, self.categories_tree, None, -1, encoding=encoding, sub_folders=sub_folders["categories_sub_folders"])
self.html_categories_tree = None
''' Iterate through entries folder '''
......
......@@ -29,21 +29,20 @@ class MetadataNode:
self.related_to = [entry_index]
self.childs = list()
def build_categories_tree(entry_index, input_list, output_tree, output_leaves, max_weight, set_max_weight=None, encoding="utf-8"):
def build_categories_tree(entry_index, input_list, output_tree, output_leaves, max_weight, set_max_weight=None, encoding="utf-8", sub_folders=''):
for category in input_list:
branch = category.split(' > ')
if not len(branch):
continue
leave = branch[-1]
path = ""
path = sub_folders
root = output_tree
for node_name in branch:
if node_name == '':
continue
path += node_name+'/'
if not node_name in [metadata.value for metadata in root]:
root.append(MetadataNode(node_name, entry_index))
if output_leaves != None and node_name == leave:
......
......@@ -175,27 +175,57 @@ class Thread:
try:
if value == 0:
return self.filename.format(**{
'entry_id':value,
'page_number':''
})
else:
return self.filename.format(**{
'entry_id':value,
'page_number':value
})
except KeyError as e:
die(messages.variable_error_in_filename.format(str(e)))
# Overridden in child class (EntriesThread)
def setup_sub_folders(self):
pass
def write_file(self, output, file_id):
if self.in_thread:
format_value = file_id
else:
format_value = page[0].id
stream = codecs.open(
self.export_path+'/'+self.format_filename(format_value),
'w',
encoding="utf-8"
)
stream.write(output)
stream.close()
def process_header(self):
self.processor.forbidden = self.forbidden
self.output = ''.join(self.processor.batch_process(self.theme.header, "header.html").sub_strings)
self.processor.forbidden = []
self.columns_number = self.datastore.blog_configuration["columns"]
self.columns_counter = 0
self.columns = [ '' for i in range(0, self.columns_number) ]
# Must be called in child class
def do(self):
page_number = 0
if self.pages_count == 0:
output = ''.join(self.processor.batch_process(self.theme.header, "header.html").sub_strings)
output += ''.join(self.processor.batch_process(self.theme.footer, "footer.html").sub_strings)
self.export_path.format(**{
"entry_id": '',
"entry_title":''
})
stream = codecs.open(
self.export_path + self.format_filename(0),
self.export_path +'/'+ self.format_filename(0),
'w',
encoding="utf-8"
)
......@@ -204,51 +234,34 @@ class Thread:
else:
for page in self.pages:
self.processor.forbidden = self.forbidden
output = ''.join(self.processor.batch_process(self.theme.header, "header.html").sub_strings)
self.processor.forbidden = []
columns_number = self.datastore.blog_configuration["columns"]
columns_counter = 0
columns = [ '' for i in range(0, columns_number) ]
self.process_header()
for entry in page:
self.current_entry = entry
columns[columns_counter] += ''.join(self.processor.batch_process(entry.html_wrapper.above, entry.filename).sub_strings)
self.setup_sub_folders() #setup relative origin as well
self.columns[self.columns_counter] += ''.join(self.processor.batch_process(entry.html_wrapper.above, entry.filename).sub_strings)
if entry.html_wrapper.required_content_pattern == ".:GetEntryPreview:.":
columns[columns_counter] += ''.join(self.processor.batch_process(entry.preview, entry.filename,).sub_strings)
self.columns[self.columns_counter] += ''.join(self.processor.batch_process(entry.preview, entry.filename,).sub_strings)
elif entry.html_wrapper.required_content_pattern == ".:PreviewIfInThreadElseContent:." and self.in_thread:
columns[columns_counter] += ''.join(self.processor.batch_process(entry.preview, entry.filename,).sub_strings)
self.columns[self.columns_counter] += ''.join(self.processor.batch_process(entry.preview, entry.filename,).sub_strings)
else:
columns[columns_counter] += ''.join(self.processor.batch_process(entry.content, entry.filename,).sub_strings)
self.columns[self.columns_counter] += ''.join(self.processor.batch_process(entry.content, entry.filename,).sub_strings)
columns[columns_counter] += ''.join(self.processor.batch_process(entry.html_wrapper.below, entry.filename).sub_strings)
self.columns[self.columns_counter] += ''.join(self.processor.batch_process(entry.html_wrapper.below, entry.filename).sub_strings)
columns_counter +=1
if columns_counter >= columns_number:
columns_counter = 0
self.columns_counter +=1
if self.columns_counter >= self.columns_number:
self.columns_counter = 0
columns_counter = 0
for column in columns:
output += '<div id="__VENC_COLUMN_'+str(columns_counter)+'__" class="__VENC_COLUMN__">'+column+'</div>'
self.columns_counter = 0
for column in self.columns:
self.output += '<div id="__VENC_COLUMN_'+str(self.columns_counter)+'__" class="__VENC_COLUMN__">'+column+'</div>'
self.processor.forbidden = self.forbidden
output += ''.join(self.processor.batch_process(self.theme.footer, "footer.html").sub_strings)
self.output += ''.join(self.processor.batch_process(self.theme.footer, "footer.html").sub_strings)
if self.in_thread:
format_value = page_number
else:
format_value = page[0].id
stream = codecs.open(
self.export_path + self.format_filename(format_value),
'w',
encoding="utf-8"
)
stream.write(output)
stream.close()
self.write_file(self.output, page_number)
page_number += 1
self.current_page = page_number
......@@ -18,6 +18,7 @@
# along with VenC. If not, see <http://www.gnu.org/licenses/>.
import os
import urllib.parse
from venc2.helpers import notify
from venc2.threads import Thread
......@@ -27,9 +28,9 @@ class CategoriesThread(Thread):
super().__init__(prompt, datastore, theme, patterns, forbidden)
self.filename = self.datastore.blog_configuration["path"]["index_file_name"]
self.export_path = "blog/"+self.datastore.blog_configuration["path"]["categories_sub_folders"]+'/'
self.relative_origin = ""
self.in_thread = True
self.export_path = "blog/"
def if_in_categories(self, argv):
return argv[0]
......@@ -46,7 +47,7 @@ class CategoriesThread(Thread):
export_path = self.export_path
self.export_path += node.value+'/'
self.relative_origin = ''.join([ '../' for a in self.export_path.split("/")[1:-1] ])
self.relative_origin = ''.join([ '../' for f in self.export_path.split("/")[1:] if f != '' ]).replace("//",'/')
# Get entries
try:
......
......@@ -18,6 +18,7 @@
# along with VenC. If not, see <http://www.gnu.org/licenses/>.
import os
import urllib.parse
from venc2.helpers import notify
from venc2.threads import Thread
......@@ -27,7 +28,8 @@ class DatesThread(Thread):
super().__init__(prompt, datastore, theme, patterns, forbidden)
self.filename = self.datastore.blog_configuration["path"]["index_file_name"]
self.relative_origin = "../"
self.sub_folders = self.datastore.blog_configuration["path"]["dates_sub_folders"]
self.relative_origin = str("../"+''.join([ "../" for p in self.sub_folders.split('/') if p != ''])).replace("//",'/')
self.in_thread = True
def if_in_archives(self, argv):
......@@ -39,7 +41,7 @@ class DatesThread(Thread):
continue
notify("\t"+thread.value+"...")
self.export_path = "blog/"+thread.value+'/'
self.export_path = "blog/"+self.sub_folders+'/'+thread.value+'/'
os.makedirs(self.export_path)
self.organize_entries([
entry for entry in self.datastore.get_entries_for_given_date(
......
......@@ -17,6 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with VenC. If not, see <http://www.gnu.org/licenses/>.
import codecs
import os
from venc2.helpers import notify
......@@ -33,8 +34,9 @@ class EntriesThread(Thread):
])
self.filename = self.datastore.blog_configuration["path"]["entry_file_name"]
self.relative_origin = str()
self.export_path = "blog/"
self.sub_folders = self.datastore.blog_configuration["path"]["entries_sub_folders"]
self.export_path = "blog/"+self.sub_folders
self.relative_origin = str(''.join([ "../" for p in self.sub_folders.split('/') if p != ''])).replace("//",'/')
self.in_thread = False
def if_in_first_page(self, argv):
......@@ -43,6 +45,17 @@ class EntriesThread(Thread):
def if_in_last_page(self, argv):
return argv[1]
def format_filename(self, value=None): #value ignored
try:
return self.filename.format(**{
'entry_id': self.current_entry.id,
'entry_title': self.current_entry.title
})
except KeyError as e:
die(messages.variable_error_in_filename.format(str(e)))
def if_in_entry_id(self, argv):
try:
if argv[0] == str(self.current_entry.id):
......@@ -54,6 +67,28 @@ class EntriesThread(Thread):
except AttributeError:
return argv[2]
def setup_sub_folders(self):
export_path = self.export_path.format(**{
'entry_id': self.current_entry.id,
'entry_title': self.current_entry.title
})
self.relative_origin = str(''.join([ "../" for p in export_path.split('/')[1:] if p != ''])).replace("//",'/')
print(export_path, self.relative_origin, export_path.split('/')[1:])
os.makedirs(export_path, exist_ok=True)
def write_file(self, output, file_id):
export_path = self.export_path.format(**{
'entry_id': self.current_entry.id,
'entry_title': self.current_entry.title
})
stream = codecs.open(
export_path+'/'+self.format_filename(),
'w',
encoding="utf-8"
)
stream.write(output)
stream.close()
def do(self):
if len(self.pages):
super().do()
......
Supports Markdown
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