This commit is contained in:
Cyrille L 2023-11-23 18:51:19 +01:00
parent cfb564eb23
commit 03960f733b
35 changed files with 796 additions and 122 deletions

View File

@ -10,6 +10,22 @@ Tyto - Littérateur
# CURRENTLY IN DEV (in devel branch) !
## [1.9.39]
- fix datepub in modules when "check domain"
- add Tyto - Littérateur generator links at HTML footer creation
- fix settings from command line options
- add "RSS" and "sitemap" links to default footer (not yet processed)
- add command "set 'MODULE_NAME'" to create default module (header, footer...)
- Create again all HTML modules with option -F, --force
- With option -E, --errors: only show warning and error logs
- Avoid creating a domain in a directory domain set yet
- better modules managed in "wip" process
- Added logs file (include ALL logs) in /var/log/tyto
- - current.log for current session only
- - archive.log for all sessions
- Sitemap (! In dev)
- - Create sitemaps in root and sub-directories
## [1.9.38]
- Moved: HTML footer in div site_container
- fix: main title in HTML page h1

View File

@ -216,7 +216,7 @@ abbr: css
#2 Une liste mixée {_<ol>, <ul>_}
((
<: mylist
+ numeric o: item 1
+ numeric ol item 1
++ numeric ol sub-Item 1
+++ numeric ol sub-sub-item 1
==== ul item >_top: Go to Top_<
@ -325,7 +325,7 @@ Here, i am
<h3 class="tyto">Une liste mixée <code class="tyto icode">&lt;ol&gt;, &lt;ul&gt;</code></h3>
<p class="tyto">
<ol class="mylist">
<li class="mylist">numeric o: item 1</li>
<li class="mylist">numeric ol item 1</li>
<ol>
<li class="mylist">numeric ol sub-Item 1</li>
<ol>

2
debian/control vendored
View File

@ -1,5 +1,5 @@
Package: tyto
Version: 1.9.38
Version: 1.9.39
Section: custom
Priority: optional
Architecture: all

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Version: 1.9.38
# Version: 1.9.39
# Updated: 2023-11-11 1699742831
# Tyto - Littérateur
@ -41,7 +41,7 @@
# file program :
#--------------------------
import os
import os, sys
#===============#
@ -56,8 +56,8 @@ def error_message(path):
# A little checker to be sure, all files are installed #
#------------------------------------------------------#
def check_install():
if not os.path.exists(libs): error_message(libs)
if not os.path.exists(trfs): error_message(trfs)
os.path.exists(libs) or error_message(libs)
os.path.exists(trfs) or error_message(trfs)
for f in prog_files:
f = os.path.join(libs, f + ".py")
@ -75,7 +75,6 @@ def check_install():
#======#=======================================================================
# MAIN #
#======#
import sys
if not __name__ == "__main__":
print("! Error: '%s' not '%s'"%(__name__, "__main__"))
sys.exit(1)

View File

@ -59,15 +59,21 @@ def get_target():
#================================#
# Searching options in arguments #
# Done only once #
#--------------------------------#
def get_options():
global dlogs, force, erron
global dlogs, force, erron, set_options
try: set_options ; return
except: pass
dlogs = force = erron = False
for arg in range(1, len(sys.argv)):
dlogs = sys.argv[arg] in tyto.debug_options
force = sys.argv[arg] in tyto.force_options
erron = sys.argv[arg] in tyto.debug_errors
if sys.argv[arg] in tyto.debug_options: dlogs = True
if sys.argv[arg] in tyto.force_options: force = True
if sys.argv[arg] in tyto.debug_errors: erron = True
set_options = True
#===========#
@ -75,6 +81,7 @@ def get_options():
#-----------#
def valid_action():
global action
if not action in tyto.actions:
debug.out(1, "[action]", action, False, 2, False)
action = "help"

View File

@ -67,6 +67,7 @@ def manage(action, target):
target == "domain" and wrk_domain()
target in ("wip", "www") and srv_domain(target)
#==========================================#
# Check some things used by current domain #
#------------------------------------------#
@ -80,24 +81,44 @@ def wrk_domain():
#==========================================================#
# Warn if unused registred file in wrk template/ directory #
# Done only once #
# - in case of "all" or direct "wip" #
#----------------------------------------------------------#
def wrk_template_files():
global check_tpl_files
try: check_tpl_files ; return
except: pass
for key, uri in domain.cf.items("USER_TEMPLATE_FILES"):
if not os.path.exists(uri):
debug.out(5, key, uri, True, 1, False)
check_tpl_files = True
#==================================#
#====================================#
# Check wip and www dirs and files #
#----------------------------------#
# Done only once #
# - in case of "all" or direct "wip" #
#------------------------------------#
def srv_domain(target):
global check_srv_domain
try: check_srv_domain ; return
except: pass
for section in ("%s_DIRS"%target.upper(), "%s_FILES"%target.upper()):
# Set err number for directories or files
if section.endswith("DIRS"): err = 6
else: err = 5
for key, uri in domain.cf.items(section):
if not os.path.exists(uri):
debug.out(err, key, uri, True, 1, False)
check_srv_domain = True
#================================#
# Check article(S) #
@ -111,7 +132,7 @@ def is_article(target):
# When all is OK
# Will create post database, but now, show some values
"""
print("Final texts string:")
print("> check: Final texts string...")
print('\n'.join(texts))
"""
@ -192,6 +213,7 @@ def valid(target):
# Head contents
# =============
# One Line targs in head_contents
debug.out(215, "check. Headers", post.cf_uri, False, 0, False)
post.error == 0 and ol_tags() \
or tools.exit(targets, post.error)
# Multiple and optional Tags on 3 linges
@ -253,7 +275,7 @@ def ol_tags():
global stats_total_files
stats_total_files = 0
sitemap = "True"
post.cf_set("HEADERS", "sitemap", "True")
stats_tyto_head_coms = 0
for ln, line in enumerate(headers, 1):
@ -614,6 +636,8 @@ def is_value2_file_exists(ln, tag, val2):
def sl_ptags(markers):
global texts
debug.out(215, "check. %s"%markers[2], post.cf_uri, False, 0, False)
convert = {
"bcodes" : wip.bcode,
"quotes" : wip.quote,
@ -736,6 +760,8 @@ def sl_ptags(markers):
def icodes():
global texts
debug.out(215, "check. icodes", post.cf_uri, False, 0, False)
stats_text_icodes = 0
markers = post.words_markers
@ -853,6 +879,8 @@ def icodes():
def sl_stags():
global anchors_ids, stats_tyto_text_coms
debug.out(215, "check. Contents", post.cf_uri, False, 0, False)
anchors_ids = () # Uniq anchors IDs
stats_tyto_text_coms = stats_html_coms = 0
stats_text_anc_ids = 0
@ -871,7 +899,9 @@ def sl_stags():
# Avoid wanting #6 - #9 (but accept #1x.. #5x.. as comments...)
elif linels[1].isdigit() and int(linels[1]) >= 6:
post.error = \
debug.out(52, "%s) %s..."%(ln, linels[0:10]), post.uri, True, 1, False)
debug.out(52, "%s) %s..."%(
ln, linels[0:10]
), post.uri, True, 1, False)
return False
stats_titles += 1

View File

@ -33,43 +33,19 @@
#--------------------------
import sys
import langs, args
import langs, args, logs
#===================================#
# Show all logs if "show" is True #
# or with -D argument #
# color is for "*" in message #
# - 3 colors levels: #
# - - 0 = Green #
# - - 1 = Yellow #
# - - 2 = Red #
# stop to sys exit with nbr if True #
#-----------------------------------#
def out(nbr, var, val, show, color, stop):
args.get_options()
logit = show or args.erron and color > 0 or args.dlogs
if not logit:
return nbr
#===================#
# Messages for logs #
#-------------------#
def set_messages():
global messages, got_messages
# COlors
CS = '\033[0;0m' # Unset
CL = '\033[0;2m' # Gray
CB = '\033[1;34m' # Blue
CC = '\033[1;36m' # Cyan
CR = '\033[1;31m' # Red
CG = '\033[1;32m' # Green
CY = '\033[1;33m' # Yellow
CP = '\033[1;35m' # Pink
try: got_messages ; return
except: pass
# Color of "*"
SC = CL # Default gray
if color == 0: SC = CG
elif color == 1: SC = CY
elif color == 2: SC = CR
# Messages for logs
messages = \
{
# ERRORS (1-100)
@ -83,6 +59,8 @@ def out(nbr, var, val, show, color, stop):
8 : langs.logs.err_lang,
9 : langs.logs.err_ini_file,
10 : langs.logs.err_post_global,
11 : langs.logs.err_post_not_chk,
13 : langs.logs.err_post_not_www,
20 : langs.logs.err_bad_uri,
21 : langs.logs.err_post_sep,
22 : langs.logs.err_post_head,
@ -114,10 +92,59 @@ def out(nbr, var, val, show, color, stop):
208 : langs.logs.website_lang,
209 : langs.logs.domain_on,
210 : langs.logs.post_chk_yet,
211 : langs.logs.checking_post,
212 : langs.logs.wipping_post,
214 : langs.logs.reading_domain,
215 : langs.logs.processing,
216 : langs.logs.create_sitemaps,
250 : langs.logs.completed,
254 : langs.logs.post_chk_ready,
255 : langs.logs.later,
}
got_messages = True
#===================================#
# Show all logs if "show" is True #
# or with -D argument #
# color is for "*" in message #
# - 3 colors levels: #
# - - 0 = Green #
# - - 1 = Yellow #
# - - 2 = Red #
# stop to sys exit with nbr if True #
#-----------------------------------#
def out(nbr, var, val, show, color, stop):
set_messages()
logs.add_line(nbr, messages[nbr], var, val)
args.get_options()
logit = show or args.erron and color > 0 or args.dlogs
if args.erron:
if color == 0:
logit = False
if not logit:
return nbr
# COlors
CS = '\033[0;0m' # Unset
CL = '\033[0;2m' # Gray
CB = '\033[1;34m' # Blue
CC = '\033[1;36m' # Cyan
CR = '\033[1;31m' # Red
CG = '\033[1;32m' # Green
CY = '\033[1;33m' # Yellow
CP = '\033[1;35m' # Pink
# Color of "*"
SC = CL # Default gray
if color == 0: SC = CG
elif color == 1: SC = CY
elif color == 2: SC = CR
# Print, acoording to parameters
print("%s*%s %s%s%s > %s%s%s < %s%s%s"%(

View File

@ -56,6 +56,7 @@ def cf_load():
cf = False
cf = configparser.ConfigParser()
cf.read(cf_uri)
debug.out(200, langs.logs.domain, cf_uri, False, 0, False)
#=====================================#
@ -221,6 +222,7 @@ def cf_set(section, key, default):
def cf_update_values(write):
# Load Domain Configuration file
cf_load()
debug.out(214, "...", cf_uri, False, 0, False)
# [DOMAIN]
# ========

View File

@ -0,0 +1,140 @@
#!/usr/bin/env python3
# Tyto - Littérateur
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib > im@echolib.re
#
# Description: Manage logs files in /var/log/tyto/
# File: /var/lib/tyto/program/logs.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines :
# file comments :
# file functions:
# file program :
#--------------------------
import os, sys, datetime
# 2 Files for logs
f_current = "/var/log/tyto/current.log" # Last session
f_archive = "/var/log/tyto/archive.log" # All sessions
#==============================#
# Set and return date and time #
#------------------------------#
def nowdate():
return(datetime.datetime.utcnow().isoformat())
#===================================#
# Create logs files (if not exists) #
#-----------------------------------#
def create_files():
global error_write, check
# Process done.
# In error case or files exist, not need to create again
try: check ; return
except: pass
# Process could not write file, no need to continue
try: error_write ; return
except: pass
CS = '\033[0;0m' # Unset
CL = '\033[0;2m' # Gray
CR = '\033[1;31m' # Red
for f in (f_current, f_archive):
if not os.path.exists(f):
try:
with open(f, "w") as f:
f.write("")
except:
print("%s!%s %sUnused%s %s"%(
CR,CS, CL,CS, f )
)
error_write = True
check = True
#=====================================#
# Create current.log for each session #
#
def add_line(nbr, message, var, val):
global first_log
# Create logs files (if not exists)
create_files()
# In error case (unused log file), return
try: error_write ; return
except: pass
# Merge current logs in archive logs (done only at first log)
archive_current_logs()
# At first log only, add command line to current logs
try:
first_log
except:
first_log = True
# Get command line
command = ""
for arg in range(1, len(sys.argv)):
command = command + sys.argv[arg] + " "
with open(f_current, "w") as f:
f.write("[%s] $ tyto %s"%(nowdate(), command))
# Create line for file
n_spaces = 3 - len(str(nbr))
with open(f_current, "a") as f:
f.write("\n[%s] %s%s => %s > %s < %s"%(
nowdate(), nbr, (n_spaces * " "), message, var, val
)
)
#==================================#
# Merge current.log to archive.log #
# Done only once, at first log #
#----------------------------------#
def archive_current_logs():
global merge_done
try: merge_done ; return
except: pass
# Load current logs file lines
current_logs = open(f_current, "r").read()
# No need to append empty current logs file
if current_logs:
# Append current logs file to archive logs
with open(f_archive, "a") as f:
f.write("%s\n\n"%(current_logs))
merge_done = True

View File

@ -32,7 +32,8 @@
# file program :
#--------------------------
import args, domain
import os
import args, domain, debug, sitemaps
#====================================#
@ -42,6 +43,7 @@ import args, domain
def manage(action, target):
do = {
"domain" : create_domain,
"sitemaps" : sitemaps.manage,
}
do[target]()
@ -54,8 +56,18 @@ def manage(action, target):
# or if user "force" option
#-----------------------------------#
def create_domain():
if not domain.cf_exists() or args.force:
# Check if in a domain set yet
d_uri = "/"
dirs = domain.user_dir.rsplit("/")
for d in dirs:
if not d:
continue
d_uri = d_uri + d + "/"
if os.path.exists(d_uri + "tyto_domain.ini"):
debug.out(202, d, d_uri, True, 2, True)
domain.cf_create()
return

View File

@ -49,6 +49,8 @@ write = False # When updating database in cf_set(), cf_write()
def is_article(target):
global error
debug.out(211, '"%s"'%target, "", False, 0, False)
# User MUST be in articles/
domain.user_dir.startswith(domain.wrk_articles) or \
debug.out(2, "-> articles/", domain.wrk_articles, True, 2, True)
@ -146,21 +148,26 @@ def is_tyto_format():
# return True, or False if unused (yet) #
#---------------------------------------#
def cf_load():
global cf
cf = False
global cf, not_chk
cf = not_chk = False
os.path.exists(cf_uri) or tools.create_file(cf_uri, ini_template)
if not os.path.exists(cf_uri):
not_chk = True
tools.create_file(cf_uri, ini_template)
cf = configparser.ConfigParser()
cf.read(cf_uri)
debug.out(200, uri_id, cf_uri, False, 0, False)
return True
#======================================#
# Load another post configuration file #
# Used by modules: navbar, sidebar #
#--------------------------------------#
def tmp_load(wrk_post, wrk_post_uri):
def tmp_load(module, wrk_post, wrk_post_uri):
global error
db_uri = os.path.join(
@ -170,17 +177,18 @@ def tmp_load(wrk_post, wrk_post_uri):
if not os.path.exists(db_uri):
error = \
debug.out(5, wrk_post, db_uri, True, 2, False)
debug.out(11, '%s. "%s"'%(module, wrk_post), db_uri, True, 2, False)
return False
global tmp_cf
tmp_cf = ""
tmp_cf = configparser.ConfigParser()
tmp_cf.read(db_uri)
debug.out(200, '%s. "%s"'%(module, wrk_post), db_uri, False, 0, False)
if tmp_cf.getboolean("CHECK", "errors"):
error = \
debug.out(10, "True", db_uri, True, 2, False)
debug.out(10, "check: %s"%langs.logs.error, db_uri, True, 2, False)
return False
global tmp_title, tmp_about, tmp_logo
@ -208,6 +216,55 @@ def tmp_load(wrk_post, wrk_post_uri):
return True
#=======================================#
# Load in tmp mode db post for sitemaps #
#---------------------------------------#
def tmp_load_db(article_uri):
global tmp_db, tmp_db_error
tmp_db_error = False
target = article_uri.rsplit(domain.wrk_articles)[1]
db_uri = domain.wrk_db + tools.get_filesum(article_uri, False) + ".ini"
if not os.path.exists(db_uri):
debug.out(11, 'Sitemap. "%s"'%target, db_uri, False, 0, False)
return False
tmp_db = ""
tmp_db = configparser.ConfigParser()
tmp_db.read(db_uri)
debug.out(200, 'Sitemap. "%s"'%target, db_uri, False, 0, False)
if not tmp_db_item("HEADERS", "sitemap", True):
tmp_db_error = True
return True
# Must be published to be included in sitemap
www_uri = tmp_db_item("WWW", "uri", False)
if not tmp_db_item("WWW", "hash", False):
tmp_db_error = True
debug.out(13, 'Sitemap. "%s"'%target, www_uri, False, 1, False)
return True
# Article is not in www server
if not os.path.exists(www_uri):
debug.out(5, 'Sitemap. "www/"', www_uri, False, 1, False)
tmp_db_error = True
return True
#===============================================#
# Get DB value (for sitemap, with tmp_load_db() #
#-----------------------------------------------#
def tmp_db_item(section, key, boolean):
if boolean:
try: return tmp_db.getboolean(section, key)
except: return False
try: return tmp_db.get(section, key)
except: return ""
#================================#
# Return value from section, key #
#--------------------------------#
@ -325,6 +382,7 @@ def cf_write():
if write:
with open(cf_uri, "w") as f:
cf.write(f)
debug.out(207, uri_id, cf_uri, False, 0, False)
write = False
@ -336,7 +394,7 @@ def find_tyto_article():
nothere = (domain.wrk_files, domain.wrk_images)
os.chdir(domain.wrk_articles)
for root,dirs,files in os.walk(domain.wrk_articles):
for root, dirs, files in os.walk(domain.wrk_articles):
if root.startswith(nothere):
continue

View File

@ -0,0 +1,252 @@
#!/usr/bin/env python3
# Tyto - Littérateur
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib > im@echolib.re
#
# Description: Create sitemaps
# File: /var/lib/tyto/program/sitemaps.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines :
# file comments :
# file functions:
# file program :
#--------------------------
import os
import args, debug, domain, post, langs, tools, check, wip
sitemap_post = """# %s Tyto - Littérateur
! NoSitemap
title: %s (%s)
about: %s (%s)
tags: %s
author: Tyto
date: %s
-----
#1 %s. %s%s "%s"
(( sitemap
<: sitemap-items
%s
:>
))
#1 %s
(( sitemap
<: sitemap-items
%s
:>
))
"""
sitemap_post_empty = """ %s Tyto - Littérateur
! NoSitemap
title: %s (%s)
about: %s (%s)
tags: %s
author: Tyto
date: %s
-----
(( sitemap
%s
))
"""
# Generic link for sitemap
link = ' %s <a class="%s sitemap" href="%s" title="%s [%s]">%s%s</a>'
#===========================#
# Manage sitemaps creations #
#---------------------------#
def manage():
domain.cf_update_values(False)
domain.ready()
if not domain.sitemaps:
return
global nowdate
nowdate = tools.nowdate().rsplit()[0]
debug.out(216, "sitemap.tyto", "sitemap.html", False, 0, False)
# Create sitemap for root and sub-directories
create_by_dir(domain.wrk_articles)
create_by_subdir()
#====================================================#
# Search in specific path directory #
# for Tyto articles, and filter them by newest first #
#---------------------------------------------------#
def articles_sorted(path):
os.chdir(path)
files = filter(os.path.isfile, os.listdir(path))
files = [os.path.join(path, f) for f in files if f.endswith(".tyto")]
files.sort(key=lambda t: os.path.getmtime(t), reverse=True)
return files
#=======================#
# Return post DB values #
#-----------------------#
def set_db_values():
return post.tmp_db_item("FILE", "target", False), \
post.tmp_db_item("FILE", "web", False), \
post.tmp_db_item("HEADERS", "title", False), \
post.tmp_db_item("HEADERS", "about", False), \
post.tmp_db_item("HEADERS", "date", False), \
post.tmp_db_item("HEADERS", "authors", False)
#=========================================================#
# Main function to make sitemap.tyto and sitemap.html #
# List Tyto articles by newest in each directory #
# Create 2 links lists (only if a valid article is added) #
# 1. directories pointing to sitemap.html
# 2. articles
# ...
#
def create_by_dir(path):
target_dir = path.rsplit(domain.wrk_articles[:-1])[1]
target_slashes = target_dir.count("/")
curr_root = root = list_pages_links = list_posts_links = ""
has_article = False
for root, dirs, files in os.walk(path):
articles = articles_sorted(root)
for article in articles:
has_article = True
if curr_root != root:
curr_root = root
add_page_link = True
else:
add_page_link = False
# Load post DB (if exists)
post.tmp_db_error = False
if not post.tmp_load_db(article) or post.tmp_db_error:
curr_root = ""
continue
target, web, title, about, date, authors = set_db_values()
web_slashes = web.count("/")
# Add page link (pointing to sitemap.html)
# Add only one same link if an article exists
if add_page_link:
# For sub directories, mark "="
# is the différence with web target and root domain
if path != domain.wrk_articles:
web_slashes = web_slashes - target_slashes
if list_pages_links: nl1 = "\n"
else: nl1 = ""
list_pages_links = \
list_pages_links + nl1 + link%(
"=" * web_slashes,
domain.css, "%ssitemap.html"%web,
"%s%s %s"%(
langs.site.sitemap, langs.logs.pp, web
), "Tyto", "", web
)
# Add article link
if list_posts_links: nl2 = "\n"
else: nl2 = ""
list_posts_links = \
list_posts_links + nl2 + link%(
"=" * web_slashes,
domain.css, web, about, authors, date + ", ", title
)
# A sitemap is created if a Tyto article file is found
if not list_posts_links and not has_article:
return
if not list_posts_links:
root_sitemap = \
sitemap_post_empty%(
langs.site.sitemap_gen,
langs.site.sitemap, target_dir,
langs.site.sitemap, target_dir,
langs.site.sitemap,
nowdate,
langs.site.sitemap_empty
)
else:
root_sitemap = \
sitemap_post%(
langs.site.sitemap_gen,
langs.site.sitemap, target_dir,
langs.site.sitemap, target_dir,
langs.site.sitemap,
nowdate,
langs.site.sitemap, langs.site.directory, langs.logs.pp, target_dir,
list_pages_links,
langs.site.posts_list,
list_posts_links,
)
#print(root_sitemap)
if path != domain.wrk_articles: target_file = "/sitemap.tyto"
else: target_file = "sitemap.tyto"
target_file = target_dir[1:] + target_file
#print(">> target_f", target_file)
file_uri = domain.wrk_articles + target_file
#print(">> file_uri", file_uri)
os.chdir(domain.wrk_articles)
args.targets = "all"
tools.create_file(file_uri, root_sitemap)
wip.is_article(target_file)
#==========================================================#
# Loop from all sub directories from root domain articles/ #
# For each, create_by_dir() sitemaps #
#
def create_by_subdir():
for root, dirs, files in os.walk(domain.wrk_articles):
for d in dirs:
dir_uri = os.path.join(root,d)
create_by_dir(dir_uri)

View File

@ -109,13 +109,13 @@ def dir_exists(dir_path, out):
# Create directories #
#--------------------#
def create_dirs(path):
try:
if not os.path.exists(path):
try:
os.makedirs(path, exist_ok=True)
debug.out(203, "True", path, False, 0, False)
debug.out(203, langs.logs.success, path, True, 0, False)
except:
# Exit if not created
debug.out(6, "False", path, True, 2, True)
debug.out(6, langs.logs.error, path, True, 2, True)
#============================#
@ -128,7 +128,7 @@ def create_file(file_path, contents):
f.write(contents)
except:
# Exit if not created
debug.out(7, "False", file_path, True, 2, True)
debug.out(7, langs.logs.error, file_path, True, 2, True)
# log "update" or "new"
file_name = os.path.basename(file_path)

View File

@ -41,6 +41,8 @@ targets = (
"domains",
"title", "date", "about", "mail", "tags", "lang", "server",
"all",
"metas", "header", "navbar", "sidebar", "footer",
"sitemaps",
)
force_options = ("--force", "-F")
@ -53,7 +55,7 @@ debug_errors = ('--errors', "-E")
#
full_name = "Tyto - Littérateur"
web_url = "https://tyto.echolib.re"
git_url = "https://git.a-lec.org/echolib/tyto-litterateur"
git_url = "https://forge.a-lec.org/echolib/tyto-litterateur"
#=============================================================#

View File

@ -32,7 +32,7 @@
# file program :
#--------------------------
import langs, forms, domain
import langs, forms, domain, wip
#====================================#
@ -51,9 +51,15 @@ def manage(action, target):
"mail" : forms.ask_domain_mail,
"lang" : forms.ask_domain_lang,
"server" : forms.ask_domain_server,
"metas" : wip.create_default_module,
"header" : wip.create_default_module,
"navbar" : wip.create_default_module,
"sidebar" : wip.create_default_module,
"footer" : wip.create_default_module,
}
do[target](True)
try: do[target](target)
except: pass
elif action in ("start", "stop") and target == "domain":
domain.userset_status(action)

View File

@ -92,6 +92,13 @@ def is_article(target):
# Copy article files
create_files()
post.cf_set("WIP", "hash", post.wrk_id)
post.cf_set("WIP", "date", datepub)
post.cf_write()
debug.out(250, langs.logs.success, post.wip_uri, True, 0, False)
#print()
#print(html_post)
@ -144,6 +151,17 @@ def page_html_create():
# Create and copy files for this article #
#----------------------------------------#
def create_files():
# Create source post wip dirs and html file
wip_dirs = \
post.wip_uri.rsplit(os.path.basename(post.wip_uri))[0] or domain.wip
tools.create_dirs(wip_dirs)
tools.create_file(post.wip_uri, page_html)
# Check/Create modules files
# navbar, sidebar, header, footer
if not get_modules("wip"):
return False
# Copy files used by article
for key, src_uri in post.cf.items("SOURCE_FILES"):
dst_uri = src_uri.replace(domain.wrk_articles, domain.wip)
@ -153,12 +171,6 @@ def create_files():
tools.create_dirs(wip_dirs)
tools.copy_files(src_uri, dst_uri)
# Create source post wip dirs and html file
wip_dirs = \
post.wip_uri.rsplit(os.path.basename(post.wip_uri))[0] or domain.wip
tools.create_dirs(wip_dirs)
tools.create_file(post.wip_uri, page_html)
# Copy domain work template directory
shutil.copytree(domain.wrk_tpl,
domain.wip_tpl,
@ -192,19 +204,19 @@ def convert(target):
check.wrk_template_files()
# Check/Create modules files
# navbar, sidebar, header, footer
if not get_modules("wip"):
return False
debug.out(212, target, post.wip_uri, False, 0, False)
# Article has errors or changed : needs check first
if post.has_changed or post.chk_errors:
if post.has_changed: debug.out(106, "'check'", post.uri, True, 1,False)
elif post.chk_errors: debug.out(10, "'check'", post.uri, True, 2, False)
if post.chk_errors: debug.out(10, "'check'", post.uri, True, 2, False)
elif post.not_chk: debug.out(11, "'check'", post.uri, True, 1, False)
elif post.has_changed: debug.out(106, "'check'", post.uri, True, 1, False)
args.force = True
check.is_article(target)
if post.error != 0:
return False
is_article(target)
return
@ -232,6 +244,7 @@ def convert(target):
value_replace("CODES", False, True)
footer_post_create()
return True
@ -252,6 +265,8 @@ def text_replace(src, html):
# tgt_b64 : True to decode base64 target # #
#------------------------------------------#
def value_replace(section, src_b64, tgt_b64):
debug.out(215, "wip. %s"%section.lower(), post.cf_uri, False, 0, False)
for key, val in post.cf.items(section):
if key.startswith("html_"):
continue
@ -333,6 +348,7 @@ def sl_tags():
elif line.lstrip().startswith(post.html_brline[0]):
css = tools.get_css(line, post.html_brline[0][0], "?")
text_replace(html_post.rsplit("\n")[ln], post.html_brline[1]%css)
# <hr>
elif line.lstrip().startswith(post.html_hrline[0]):
css = tools.get_css(line, post.html_hrline[0][0], "?")
@ -704,6 +720,27 @@ def footer_post_create():
#=========#
# Modules #====================================================================
#---------#
#============================#
# With command "set [module] #
# remove if any [module] #
# Create default [module] #
#----------------------------#
def create_default_module(target):
domain.cf_update_values(False)
domain.ready()
files = {
"metas" : domain.wrk_metas,
"header" : domain.wrk_header,
"navbar" : domain.wrk_navbar,
"sidebar" : domain.wrk_sidebar,
"footer" : domain.wrk_footer
}
os.path.exists(files[target]) and os.remove(files[target])
get_modules("wip")
#==================================#
# Create modules ini database file #
# return False if: #
@ -731,7 +768,10 @@ def modules_db():
# - footer #
#--------------------------------------------#
def get_modules(srv):
global modules
global modules, datepub
try: datepub
except: datepub = tools.nowdate()
# Modules settings
fill_footer_raw()
@ -806,6 +846,7 @@ def get_modules(srv):
# Manage modules
# Create raw files, and set html "srv" file
for mod in modules:
debug.out(215, "wip. Module %s"%(mod), modules[mod][srv], False, 0, False)
create_html_module = False
# Create user raw files modules in modules/ directory
@ -825,11 +866,11 @@ def get_modules(srv):
create_html_module = True
# Unused module HTML file or "--force" option
if not os.path.exists(modules[mod][srv]) or args.force:
if not os.path.exists(modules[mod][srv]):
create_html_module = True
# Create HTML module if needed (raw updated, or unused html file)
if create_html_module:
if args.force or create_html_module:
modules[mod]["set"](srv)
if post.error != 0:
@ -965,7 +1006,7 @@ def navbar_html_create(srv):
# Load post configuration file in tmp module
# return if unused or post errors
if not post.tmp_load(wrk_index, wrk_index_uri):
if not post.tmp_load("Navbar", wrk_index, wrk_index_uri):
return False
items = True
@ -1073,7 +1114,7 @@ def sidebar_html_create(srv):
# Load post configuration file in tmp module
# return if unused or post errors
if not post.tmp_load(wrk_post, wrk_post_uri):
if not post.tmp_load("Sidebar", wrk_post, wrk_post_uri):
return False
# Post can be added to list
@ -1122,15 +1163,26 @@ def fill_footer_raw():
if not domain.license_url: domain.license_url = "/"
show_license = "%s%s %s"%(langs.site.license, langs.logs.pp, domain.license)
footer_items = "%s\n%s"%(
footer_items = "%s\n%s\n%s\n%s"%(
footer_items,
item%(
domain.license_url,
langs.site.license_title, domain.title,
show_license
),
item%(
"/%s"%domain.rss,
langs.site.feed_rss, domain.title,
langs.site.feed_rss
),
item%(
"/sitemap.html",
langs.site.sitemap, domain.title,
langs.site.sitemap
)
)
# Loop to [WEBSITE_FOOTER] and make link from key_url
for key, link in domain.cf.items("WEBSITE_FOOTER"):
if link:
@ -1159,6 +1211,19 @@ def fill_footer_raw():
# modules/tyto_footer.raw has default contents #
#------------------------------------------------#
def footer_html_create(srv):
generator = '<div id="Tyto_links">%s '%(
langs.site.generated_by
) + \
'<a class="generator" ' + \
'title="%s" '%langs.site.off_website + \
'href="%s">'%tyto.web_url + \
'%s</a> '%tyto.full_name + \
'[<a class="generator" ' + \
'title="%s%s GPLv3" '%(langs.site.license, langs.logs.pp) + \
'href="%s">'%tyto.git_url + \
'%s</a>]'%langs.site.source_code + \
'</div>'
with open(domain.wrk_footer, "r") as f:
footer_raw = f.read().rsplit("\n")
footer_html = ""
@ -1172,6 +1237,9 @@ def footer_html_create(srv):
if not footer_html: footer_html = line
else: footer_html = "%s\n%s"%(footer_html, line)
# Add generator credentials
footer_html = "%s\n%s"%(footer_html, generator)
tools.create_file(modules["footer"][srv], footer_html)
return True

View File

@ -131,6 +131,17 @@ img.post_logo {}
img.tyto {}
/*
* ----------------
* Sitemaps article
*/
p.sitemap {}
ul.sitemap-items {}
li.sitemap-item {}
/* Also a.tyto */
a.sitemap {}
/* ----------------------------------------------------------------------------
* Sidebar (Website)
*/
@ -161,3 +172,7 @@ li.site_footer_item {}
/* Also a.tyto */
a.site_footer_item_link {}
p#site_footer_copyright {}
/* After footer, TYto, credential */
div#Tyto_links {}
a.generator {}

View File

@ -36,7 +36,10 @@ ok = ("yes", "y")
# Form
q = "?"
pp = ":"
error = "Error"
success = "Success"
configure_domain = "Configure domain"
domain = "Domain"
domain_title = "Domain title"
domain_date = "Creation date"
domain_about = "Domain description"
@ -45,6 +48,8 @@ domain_tags = "Domain tags [1,2,3]"
domain_lang = "Website lang"
domain_srv = "Server URI"
copy = "Copy"
create_sitemaps = "Creating sitemaps"
completed = "Completed"
# Misc
anchor_title = "Anchor title"
@ -73,6 +78,8 @@ err_post_in_tag = "Markers without contents"
err_post_datatag = "Data reserved"
err_post_id_yet = "ID used yet"
err_post_global = "Article Error"
err_post_not_chk = "Article not checked"
err_post_not_www = "Article not published"
# Warnings
warn_no_dom = "Domain not configured"
@ -93,6 +100,10 @@ domain_new = "Domain created"
created_dir = "Directory created"
created_file = "File created"
updated_file = "File Updated"
reading_domain = "Preparing domain"
processing = "Process"
checking_post = "Checking article"
wipping_post = "Converting article"
post_chk_yet = "Article checked yet"
post_chk_ready = "Article checked"
later = "Maybe later..."
@ -104,12 +115,12 @@ help_contents = """
tyto [action] [target] [options]
[action]
new : create new domain (reset with -F)
set : set website lang, domain values (title, server...)
set : [server, date, title, mail, footer, header, ...]
start : activate domain (default "no" when created)
stop : deactivate domain
show : [domains, metas]
check : [domain, wip, www, [name].tyto]
wip :
wip : [name].tyto: create HTML page in "wip/" server
publish :
[target]
@ -120,8 +131,9 @@ tyto [action] [target] [options]
about : [set]: domain description
mail : [set]: domain admin mail
tags : [set]: domain tags (added to all articles)
lang :
lang : [set]: Website language
server : [set]: server local URI
footer : [set]: Create default module (also header...)
wip : [check] Directories and files
www : [check] Directories and files

View File

@ -36,7 +36,10 @@ ok = ("oui", "o")
# Form
q = " ?"
pp = " :"
error = "Erreur"
success = "Succès"
configure_domain = "Configurer le domaine"
domain = "Domaine"
domain_title = "Titre du domaine"
domain_date = "Date de création"
domain_about = "Description du domaine"
@ -45,6 +48,8 @@ domain_tags = "Mots-clés du domaine [1,2,3]"
domain_lang = "Langue du site web"
domain_srv = "URI du serveur"
copy = "Copie"
create_sitemaps = "Création des plans du site"
completed = "Terminé"
# Misc
anchor_title = "Titre de l'ancre"
@ -73,6 +78,8 @@ err_post_in_tag = "Marqueurs sans contenu"
err_post_datatag = "Donnée réservée"
err_post_id_yet = "Identité déjà utilisée"
err_post_global = "Article erronné"
err_post_not_chk = "Article non vérifié"
err_post_not_www = "Article non publié"
# Warnings
warn_no_dom = "Domaine non configuré"
@ -93,6 +100,10 @@ domain_new = "Domaine créé"
created_dir = "Dossier créé"
created_file = "Fichier créé"
updated_file = "Fichier mis à jour"
reading_domain = "Préparation du domaine"
processing = "Process"
checking_post = "Vérification de l'article"
wipping_post = "Convertion de l'article"
post_chk_yet = "Article déjà vérifié"
post_chk_ready = "Article vérifié"
later = "Peut-être plus tard..."
@ -104,12 +115,12 @@ help_contents = """
tyto [action] [target] [options]
[action]
new : créer un nouveau domaine (réinitialisé avec -F)
set : définir la langue du site web, du domaine (titre, serveur...)
set : [server, date, title, mail, footer, header, ...]
start : activer le domaine (défaut "no" à la création)
stop : désactiver le domaine
show : [domains, metas]
check : [domain, wip, www, [name].tyto]
wip :
wip : [name].tyto: crée la page HTML dans le serveur "wip/"
publish :
[target]
@ -120,8 +131,9 @@ tyto [action] [target] [options]
about : [set]: description du domaine
mail : [set]: courriel de l'administrateur
tags : [set]: étiquettes du domaine (ajoutées aux articles)
lang :
lang : [set]
server : [set]: URI du serveur local
footer : [set]: Crée le module par défaut (aussi header...)
wip : [check] dossiers et fichiers
www : [check] dossiers et fichiers

View File

@ -31,7 +31,12 @@
# Note: python file
sidebar_title = "Featured posts"
sitemap = "sitemap"
directory = "Directory"
sitemap = "Sitemap"
sitemap_gen = "Sitemap source article generated by"
sitemap_empty = "Nothing to show yet"
posts_list = "Articles list"
source_code = "Source code"
permalink = "Permalink"
@ -43,3 +48,6 @@ terms = "Terms of Service"
terms_title = "%s of"%terms
bylaws = "Bylaws"
bylaws_title = "%s of"%bylaws
feed_rss = "RSS feed 2.0"
generated_by = "Generated by"
off_website = "Official website"

View File

@ -31,7 +31,12 @@
# Note: Fichier au format python
sidebar_title = "Articles recommandés"
directory = "Dossier"
sitemap = "Plan du site"
sitemap_gen = "Article source du plan du site généré par"
sitemap_empty = "Rien à afficher pour le moment."
posts_list = "Liste des articles"
source_code = "Code source"
permalink = "Permalien"
@ -43,3 +48,6 @@ terms = "C.G.U"
terms_title = "%s de"%terms
bylaws = "Statuts"
bylaws_title = "%s de"%bylaws
feed_rss = "Flux RSS 2.0"
generated_by = "Géneré par"
off_website = "Site web officiel"