Updated for show, check, wip, html, databases

This commit is contained in:
Cyrille L 2023-03-30 17:53:55 +02:00
parent db7c1687a7
commit d08b96cf37
11 changed files with 678 additions and 709 deletions

View File

@ -2,17 +2,26 @@
Pour obtenir de l'aide, taper juste la commande tyto
## Répertoire de code du projet Tyto
TODO
## Comment définir les métas
```
# Obligatoires uniques
# Ces marqueurs se configurent sur UNE ligne
title: Titre
about: Infos de l'article
author: Auteur
tags: mots-clé-1,mots-clé-2
tags: mot-clé-1,mot 2,
date: YYYY-MM-DD (AAAA-MM-JJ)
# L'image doit être configurée avec le même Nom
# dans les marqueurs multiples
# Utilise l'image précisée comme "avatar" dans les réseaux sociaux
snpic: Nom
# Optionnels multiples
# Ces marqueurs se configurent sur 3 lignes
link: Nom du lien
URL
Texte Alternatif
@ -33,10 +42,6 @@ abbr: abbrev
Définition de abbrev
ABBR (forme à afficher dans l'artile (optionnel))
# L'image doit d'abord être configurée
# Utiliser l'image précisée comme défaut dans les réseaux sociaux
snpic: Nom
# Séparateur d'au moins 5 "-" pour définir la fin
# des métadonnées d'entête de l'article
----------
@ -103,13 +108,14 @@ def hello_world():
### Ancres
```
# Source`
# Source de l'ancre cible. "id" est son identité
-> id
# HTML
<a href="id2"></a>
# Source
# Source de l'ancre d'appel
# Définir l'identité cible et le texte du lien
((
>_id:Retourner au point d'ancre id_<
))
@ -120,7 +126,11 @@ def hello_world():
### Retour à la ligne HTML
```
| # <br />
# Source
|
# HTML
<br />
```
### Lien vers URL
@ -136,7 +146,8 @@ Voir ce __Nom du lien+ # ouverture nouvelle fenêtre
```
Note:
Vous pouvez avoir un Nom identique pour file: et link:
Vous pouvez avoir un Nom identique pour les marqueur `file:` et `link:`
### Gras, Strong, italique...
```
@ -159,7 +170,7 @@ Vous pouvez avoir un Nom identique pour file: et link:
### Abréviations
```
# abbrev sera remplacé par "ABBR" dans la page si défini en entête
# sinon, abbrev sera conservé
# sinon, abbrev sera conservé
# - Toujours écrire dans l'article :
# - entre parenthèses ET majuscules les "(ABBREV)"
@ -186,12 +197,12 @@ _image:Nom c=CSS t=https://... w=320px h=240 # 240px
### Code brut depuis un fichier
```
_raw:NOM
_raw:Nom
```
### Citations
Possibilité dans toute citation d'utiliser les marqueurs
optionnels _xxx. Pour la date, utilisez le FORMAT INTERNATIONAL
optionnels `_xxx:`. Pour la date, utilisez le FORMAT INTERNATIONAL
```
# Source: citation complète
[[ CSS_TEST

View File

@ -58,6 +58,7 @@ pass_db = \
'edit-www',
'publish',
'show',
'show-about',
'show-db',
'show-wip',
'show-www',

View File

@ -1,11 +1,28 @@
#!/usr/bin/env python3
# Name: Tyto - Littérateur
# Type: Global functions for check
# Description: Check article contents. Create Stats and Database
# file: check.py
# Folder: /var/lib/tyto/program/
# By echolib (XMPP: im@echolib.re)
# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib@dismail.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the License, or
# 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Manage 'check' argument.
# Check article's validity in Tyto's format
# File: /var/lib/tyto/program/check.py
#----------------------------------------------------------------------
#------------
# funny stats
@ -115,7 +132,7 @@ def check_all(option):
if option == 'all' and not db.old_chk: continue
found = True
print(':> [%s] - %s'%(db.title, db.post_src))
print(' ├ [%s] > %s'%(db.title, db.post_src))
check_process(args.target)
if post_err: logs.out("44", args.target, False)
@ -279,24 +296,19 @@ def count_words(post_bottom):
#---------------------------------------------#
def if_icodes_bcodes_quotes(post_bottom):
global icode, quote, bcode, post_err
global nbr_titles, nbr_quotes, nbr_bcodes, nbr_ancs
global nbr_titles, nbr_quotes, nbr_bcodes, nbr_ancs, nbr_coms
icode = quote = in_quote = bcode = in_bcode = False
nbr_titles = nbr_quotes = nbr_bcodes = nbr_ancs = 0
icode = quote = in_quote = bcode = in_bcode = in_bq = False
nbr_titles = nbr_quotes = nbr_bcodes = nbr_ancs = nbr_coms = 0
for ln, line in enumerate(post_bottom.rsplit('\n'), 1):
# Comments, count titles
# Stat Comments, Titles, Anchors
if not line:
continue
elif line.startswith(tyto.titles_tags):
nbr_titles += 1
continue
elif line.startswith('#'):
continue
# quotes
elif line.startswith(tyto.words_tags[11][0]) and not in_bcode:
quote = in_quote = True
quote = in_quote = in_bq = True
continue
elif line.startswith(tyto.words_tags[11][1]):
in_quote = False
@ -305,18 +317,25 @@ def if_icodes_bcodes_quotes(post_bottom):
# bcode
elif line.startswith(tyto.words_tags[12][0]) and not in_quote:
bcode = in_bcode = True
bcode = in_bcode = in_bq = True
continue
elif line.startswith(tyto.words_tags[12][1]):
in_bcode = False
nbr_bcodes += 1
continue
if in_bcode or in_quote:
if in_bq:
continue
elif line.startswith(tyto.single_tags[1][0]):
elif line.startswith(tyto.titles_tags) and not in_bq:
nbr_titles += 1
continue
elif line.startswith('#') and not in_bq:
nbr_coms += 1
continue
elif line.startswith(tyto.single_tags[1][0]) and not in_bq:
nbr_ancs += 1
continue
# icodes
elif tyto.words_tags[9][0] or tyto.words_tags[9][1] in line:
@ -409,14 +428,14 @@ def check_date(date):
# Multiple settings for each on 3 lines #
#-------------------------------------------#
def check_opt_tags(post_header):
global stat_links, stat_images, stat_files, stat_raws, stat_abbrs
global stat_snpics, snpic_url
global stat_links, stat_images, stat_files, stat_raws
global stat_snpics, snpic_url, stat_abbrs, post_abbrs
global opt_tags_post_name
global files_post
# Statistics
stat_links = stat_images = stat_files = stat_raws = stat_abbrs = 0
stat_snpics = 0
stat_links = stat_images = stat_files = stat_raws = 0
stat_snpics = post_abbrs = stat_abbrs = 0
files_post = (())
# Set default post pic
@ -446,8 +465,9 @@ def check_opt_tags(post_header):
#--------------------------------------------#
def check_3lines(tag, ln, line):
global post_err, db_tag, files_post
global post_abbrs
stat_tag = "stat_%ss"%tag
stat_tag = "stat_%ss"%tag
# Create variable for post DB
globals()[stat_tag] += 1
@ -462,8 +482,7 @@ def check_3lines(tag, ln, line):
name = line.rsplit('%s:'%tag)[1].lstrip()
else:
name = line.rsplit('%s:'%tag)[1].lstrip().rsplit(' ')[0]
if tag == "abbr":
name = name.upper()
if not name:
logs.out("2", 'L=%s. "%s: %s" > %s'%(
@ -471,6 +490,11 @@ def check_3lines(tag, ln, line):
), False)
post_err = True
# abbr:
elif tag == "abbr":
name_abbr = name.upper()
post_abbrs = post_bottom.count('(%s)'%name_abbr)
# snpic only needs a Name
elif tag == "snpic":
check_snpic(name)
@ -482,7 +506,7 @@ def check_3lines(tag, ln, line):
), False)
post_err = True
globals()[db_tag] = ((name),)
globals()[db_tag] = ((opt_tags_post_name[tag]%name),)
# URI/URL and Alt-Text
#---------------------
@ -509,9 +533,13 @@ def check_3lines(tag, ln, line):
# Set data for post DB
if l == 1 and tag in tyto.opt_tags_check_uri:
check_file_uri(tag, data, ln)
if post_err:
return
globals()[db_tag] = globals()[db_tag] + ((web_uri),)
files_post = files_post + (('%s'%web_uri),)
else:
if post_err:
return
globals()[db_tag] = globals()[db_tag] + ((data),)
@ -603,78 +631,6 @@ def check_snpic(name):
def check_content(post_bottom):
global post_err
# Check if anchor has target
# Count anchors target
#---------------------------
for ln, line in enumerate(post_bottom.rsplit('\n'), 1):
# Anchor link
if tyto.words_tags[0][0] and tyto.words_tags[0][1] in line:
anchors = re.findall(r">_(.*?)_<", line)
for anchor in anchors:
css_anchor = anchor.rsplit(':')[0]
tag = '%s %s'%(tyto.single_tags[1][0], css_anchor)
if not tag in post_bottom:
logs.out("12", 'L=%s. anchor "%s" > %s'%(
ln + ln_header, tag, db.uri_file
), False)
post_err = True
# Anchor source "->"
if line.startswith(tyto.single_tags[1][0]):
set_css = tyto.get_css(line)
is_uniq_anchor = "%s %s"%(tyto.single_tags[1][0], set_css)
c_uniq_anchor = post_bottom.count(is_uniq_anchor)
if c_uniq_anchor > 1:
logs.out("15", 'L=%s. %sx "%s" > %s'%(
ln + ln_header, c_uniq_anchor, is_uniq_anchor,
db.uri_file
), False)
post_err = True
break
# Lists: check if contents are valid
#-----------------------------------
inlist = False
markers_lists = '%s, %s, or space'%(
tyto.markers_lists[0],
tyto.markers_lists[1]
)
for ln, line in enumerate(article.rsplit('\n'), 1):
if line.startswith('-('): inlist = True;continue
elif line.startswith('-)'): inlist = False
if not inlist: continue
if inlist and not line or not line[0] in tyto.markers_lists:
logs.out("3", 'line %s must start with %s'%(
ln, markers_lists
), False
)
post_err = True
# Check for all match _TAGS:NAME from content in header
#------------------------------------------------------
set_tags = ()
for ln, line in enumerate(post_bottom):
for htag in tyto.head_tags:
match = False
ptag = '_%s'%htag
if line.startswith(ptag):
ptag_set = line.rsplit(':', 1)[1].lstrip().rsplit(' ')[0]
if ptag_set in set_tags: continue
for hline in post_header:
if re.search(r"^%s\s+%s$"%(htag,ptag_set), hline):
match = True
set_tags = (ptag_set)
if match: continue
else:
logs.out("12", "%s %s"%(htag, ptag_set), False)
post_err = True
# Check tags for words (strongs, italics...)
# Set stats for each one
#-------------------------------------------
@ -702,6 +658,85 @@ def check_content(post_bottom):
globals()['post_%s'%tag[4]] = int(c_opened)
# Check if anchor has target
# Count anchors target
#---------------------------
if post_anchors > 0:
for ln, line in enumerate(post_bottom.rsplit('\n'), 1):
# Anchor link
if tyto.words_tags[0][0] and tyto.words_tags[0][1] in line:
anchors = re.findall(r">_(.*?)_<", line)
for anchor in anchors:
css_anchor = anchor.rsplit(':')[0]
tag = '%s %s'%(tyto.single_tags[1][0], css_anchor)
if not tag in post_bottom:
logs.out("12", 'L=%s. anchor "%s" > %s'%(
ln + ln_header, tag, db.uri_file
), False)
post_err = True
# Anchor "->" id must be uniq
if nbr_ancs > 0:
if line.startswith(tyto.single_tags[1][0]):
set_css = tyto.get_css(line)
is_uniq_anchor = "%s %s"%(tyto.single_tags[1][0], set_css)
c_uniq_anchor = post_bottom.count(is_uniq_anchor)
if c_uniq_anchor > 1:
logs.out("15", 'L=%s. %sx "%s" > %s'%(
ln + ln_header, c_uniq_anchor, is_uniq_anchor,
db.uri_file
), False)
post_err = True
break
# Lists: check if contents are valid
#-----------------------------------
if post_lists > 0:
inlist = False
for ln, line in enumerate(post_bottom.rsplit('\n'), 1):
if line.startswith(tyto.words_tags[13][0]):
inlist = True
continue
elif line.startswith(tyto.words_tags[13][1]):
inlist = False
if not inlist:
continue
if inlist and not line or not line[0] in tyto.markers_lists:
logs.out("3", 'L=%s. %s %s > %s'%(
ln + ln_header,
tyto.words_tags[13][4],
tyto.markers_lists,
db.uri_file
), False
)
post_err = True
# Check for all match _TAGS:NAME from content in header
#------------------------------------------------------
set_tags = ()
for ln, line in enumerate(post_bottom):
for htag in tyto.head_tags:
match = False
ptag = '_%s'%htag
if line.startswith(ptag):
ptag_set = line.rsplit(':', 1)[1].lstrip().rsplit(' ')[0]
if ptag_set in set_tags: continue
for hline in post_header:
if re.search(r"^%s\s+%s$"%(htag, ptag_set), hline):
match = True
set_tags = (ptag_set)
if match: continue
else:
logs.out("12", "%s %s"%(htag, ptag_set), False)
post_err = True
# Template Tags (warning for not paired symbols)
#-----------------------------------------------
for tag in tyto.tpl_tags:
@ -803,24 +838,26 @@ def create_database():
'uniq_files = %d\n'%stat_files + \
'uniq_raws = %d\n'%stat_raws + \
'\n# Statistics from post content\n' + \
'stat_tags = %d\n'%stat_tags + \
'stat_lines = %d\n'%ln_article + \
'stat_words = %d\n'%stat_words + \
'stat_titles = %d\n'%nbr_titles + \
'stat_paragraphs = %d\n'%post_paragraphs + \
'stat_anchors = %d\n'%post_anchors + \
'stat_strongs = %d\n'%post_strongs + \
'stat_bolds = %d\n'%post_bolds + \
'stat_emphasis = %d\n'%post_emphasis + \
'stat_italics = %d\n'%post_italics + \
'stat_dels = %d\n'%post_dels + \
'stat_underlines = %d\n'%post_underlines + \
'stat_cites = %d\n'%post_cites + \
'stat_customs = %d\n'%post_customs + \
'stat_icodes = %d\n'%tyto.nbr_icodes + \
'stat_bcodes = %d\n'%nbr_bcodes + \
'stat_quotes = %d\n'%nbr_quotes + \
'stat_lists = %d\n'%post_lists
'post_coms = %d\n'%nbr_coms + \
'post_tags = %d\n'%stat_tags + \
'post_lines = %d\n'%ln_article + \
'post_words = %d\n'%stat_words + \
'post_titles = %d\n'%nbr_titles + \
'post_paragraphs = %d\n'%post_paragraphs + \
'post_anchors = %d\n'%post_anchors + \
'post_abbrs = %d\n'%post_abbrs + \
'post_strongs = %d\n'%post_strongs + \
'post_bolds = %d\n'%post_bolds + \
'post_emphasis = %d\n'%post_emphasis + \
'post_italics = %d\n'%post_italics + \
'post_dels = %d\n'%post_dels + \
'post_underlines = %d\n'%post_underlines + \
'post_cites = %d\n'%post_cites + \
'post_customs = %d\n'%post_customs + \
'post_icodes = %d\n'%tyto.nbr_icodes + \
'post_bcodes = %d\n'%nbr_bcodes + \
'post_quotes = %d\n'%nbr_quotes + \
'post_lists = %d\n'%post_lists
# Create Post DB
#---------------
@ -828,336 +865,3 @@ def create_database():
tyto.set_file(db.config, 'new', database)
logs.out("21", db.uri_file, False)
#==================================#
# Check tags from article's header #
#----------------------------------#
def check_headers(post_header):
global post_err, err, web_uri, date_check
global date, title, author, tags, about
global stat_links, stat_images, stat_files, stat_raws, stat_abbrs
global post_tags
global snpic_url
global files_post
# Contains all files URIs needed for article
# Used with publish command to copy needed files
files_post = ('')
snshare = False
snpic_name = ''
# Needed Tags
title = author = about = tags = ''
date = ()
# Statistics
stat_links = stat_images = stat_files = stat_raws = stat_abbrs = 0
###
# Second session for optional tags #
# Read articles lines, till separator #
#-------------------------------------#
for ln, line in enumerate(post_header, 1):
if line.startswith('-----'): break
# Set each optional tags
#-----------------------
# ABBR
#-----
tag = tyto.headers[8] # abbr:
if line.startswith(tag):
stat_abbrs += 1
var_tag = 'abbr_%s'%stat_abbrs
abbr_short = post_header[ln - 1].rsplit(tag)[1].lstrip()
if not abbr_short:
logs.out("2", "Line %s (SHORT, %s)"%(ln, tag), False)
post_err = True
if not abbr_short.isupper():
logs.out("3", "Line %s (Upper SHORT, %s)"%(ln, tag), False)
post_err = True
continue
if not isin(r'!\b%s\b'%abbr_short, post_bottom):
logs.out("6", '!%s'%abbr_short, False)
post_err = True
abbr_long = post_header[ln].lstrip()
if abbr_long.startswith(tyto.headers): abbr_long = ''
if not abbr_long:
logs.out("2", "Line %s (Long, %s)"%(ln + 1, tag), False)
post_err = True
abbr_alt = post_header[ln + 1].lstrip()
if abbr_alt.startswith(tyto.headers): abbr_alt = ''
if not abbr_alt: abbr_alt = abbr_short
if not post_err:
web_link = '<abbr class="%s" title="%s">%s</abbr>'%(
'abbr', abbr_long, abbr_alt
)
globals()['abbr_%s'%stat_abbrs] = (
'!%s'%abbr_short, web_link
)
# LINK
#-----
tag = tyto.headers[5] # link:
if line.startswith(tag):
stat_links += 1
var_tag = 'link_%s'%stat_links
# NAME
link_name = post_header[ln - 1].rsplit(tag)[1].lstrip()
if not link_name:
logs.out("2", 'L=%s. "%s %s" > %s'%(
ln, tag, tr.name, db.uri_file
), False)
post_err = True
if not post_err and \
not isin(r'\b_%s\b'%link_name, post_bottom):
logs.out("12", '"_%s%s" > %s'%(
tag, image_name, db.uri_file
), False)
post_err = True
# URL
try:
link_url = post_header[ln].lstrip()
if link_url.startswith(tyto.headers): link_url = ''
except:
link_url = ''
if not link_url:
logs.out("2", 'L=%s. "%s URL" > %s)'%(
ln + 1, tag, db.uri_file
), False)
post_err = True
# ALT
try:
link_alt = post_header[ln + 1].lstrip()
if link_alt.startswith(tyto.headers): link_alt = ''
except:
link_alt = ''
if not link_alt:
logs.out("2", 'L=%s. "%s Alt-Text" > %s'%(
ln + 2, tag, db.uri_file
), False)
post_err = True
if not post_err:
web_link = '<a class="%s" href="%s" '%('link', link_url) + \
'target="%s" title="%s">%s</a>'%(
'%s', link_alt, link_name
)
globals()['link_%s'%stat_links] = (
'_%s'%link_name, web_link
)
# IMAGE
#------
tag = tyto.headers[6] # image:
if line.startswith(tag):
stat_images += 1
var_tag = 'image_%s'%stat_images
# NAME
image_name = post_header[ln - 1]
image_name = image_name.rsplit(tag)[1].lstrip().rsplit(' ')[0]
if not image_name:
logs.out("2", 'L=%s. "%s %s" > %s'%(
ln, tag, tr.name, db.uri_file
), False)
post_err = True
if not post_err and \
not isin(r'\b_%s%s\b'%(tag, image_name), post_bottom):
logs.out("12", '"_%s%s" > %s'%(
tag, image_name, db.uri_file
), False)
post_err = True
# URI
try:
image_uri = post_header[ln].lstrip()
if image_uri.startswith(tyto.headers): image_uri = ''
except:
image_uri = ''
if not image_uri:
logs.out("2", 'L=%s. "%s URI" > %s)'%(
ln + 1, tag, db.uri_file
), False)
post_err = True
else:
check_file_uri('image', image_uri, ln + 1)
if not post_err:
f_uri = web_uri[1:len(web_uri)]
files_post = (files_post + "'%s', "%f_uri)
# ALT
try:
image_alt = post_header[ln + 1].lstrip()
if image_alt.startswith(tyto.headers): image_alt = ''
except:
image_alt = ''
if not image_alt:
logs.out("2", 'L=%s. "%s Alt-Text" > %s'%(
ln + 2, tag, db.uri_file
), False)
post_err = True
if not post_err:
globals()['image_%s'%stat_images] = (
'_%s%s'%(tag, image_name),
web_uri,
image_alt
)
# RAW File
#---------
tag = tyto.headers[9] # raw:
if line.startswith(tag):
stat_raws += 1
var_tag = 'raw_%s'%stat_raws
# NAME
raw_name = post_header[ln - 1]
raw_name = raw_name.rsplit(tag)[1].lstrip().rsplit(' ')[0]
if not raw_name:
logs.out("2", 'L=%s. "%s %s" > %s'%(
ln, tag, tr.name, db.uri_file
), False)
post_err = True
if not post_err and \
not isin(r'\b_%s%s\b'%(tag, raw_name), post_bottom):
logs.out("12", '"_%s%s" > %s'%(
tag, raw_name, db.uri_file
), False)
post_err = True
# URI
try:
raw_uri = post_header[ln].lstrip()
if raw_uri.startswith(tyto.headers): raw_uri = ''
except:
raw_uri = ''
if not raw_uri:
logs.out("2", 'L=%s. "%s URI" > %s)'%(
ln + 1, tag, db.uri_file
), False)
post_err = True
else:
check_file_uri('file', raw_uri, ln + 1)
if not post_err:
f_uri = web_uri[1:len(web_uri)]
files_post = (files_post + "'%s', "%f_uri)
# ALT
try:
raw_alt = post_header[ln + 1].lstrip()
if raw_alt.startswith(tyto.headers): raw_alt = ''
except:
raw_alt = ''
if not raw_alt:
logs.out("2", 'L=%s. "%s Alt-Text" > %s'%(
ln + 2, tag, db.uri_file
), False)
post_err = True
if not post_err:
globals()['raw_%s'%stat_raws] = (
'_%s%s'%(tag, raw_name),
web_uri,
raw_alt
)
# FILE
#-----
tag = 'file:'
if line.startswith(tag):
stat_files += 1
var_tag = 'file_%s'%stat_files
# NAME
file_name = post_header[ln - 1].rsplit(tag)[1].lstrip()
if not file_name:
logs.out("2", "Line %s (Name, %s)"%(ln, tag), False)
post_err = True
if not post_err and \
not isin(r'\b__%s\b'%file_name, post_bottom):
logs.out("6", "__%s"%file_name, False)
post_err = True
# URI
try:
file_uri = post_header[ln].lstrip()
if file_uri.startswith(tyto.headers): file_uri = ''
except:
file_uri = ''
if not file_uri:
logs.out("2", 'L=%s. "%s URI" > %s)'%(
ln + 1, tag, db.uri_file
), False)
post_err = True
else:
check_file_uri('file', file_uri, ln + 1)
if not post_err:
f_uri = web_uri[1:len(web_uri)]
files_post = (files_post + "'%s', "%f_uri)
# ALT
try:
file_alt = post_header[ln + 1].lstrip()
if file_alt.startswith(tyto.headers): file_alt = ''
except:
file_alt = ''
if not file_alt:
logs.out("2", 'L=%s. "%s Alt-Text" > %s'%(
ln + 2, tag, db.uri_file
), False)
post_err = True
if not post_err:
web_link = '<a class="%s" href=".%s" '%('file', web_uri) + \
'target="%s" title="%s">%s</a>'%(
'%s', file_alt, file_name
)
globals()['file_%s'%stat_files] = (
'__%s'%file_name, web_link
)
# snpic (set image to share to social networks)
#----------------------------------------------
if snpic_name: continue
snpic_url = '%s/template/%s'%(dom.www_url, dom.logo)
tag = tyto.headers[11] # snpic:
if line.startswith(tag):
snpic_name = post_header[ln - 1].rsplit(tag)[1].lstrip()
for ln, line in enumerate(post_header, 1):
if re.search(r"^image:\s+%s$"%snpic_name, line):
image_uri = post_header[ln].lstrip()
check_file_uri('image', image_uri, ln + 1)
snshare = True
snpic_url = '%s%s'%(dom.www_url, web_uri)
break
if not snshare:
logs.out("12", '%s %s'%(tyto.headers[6], snpic_name), False)
post_err = True

View File

@ -89,23 +89,25 @@ if args.target \
'uniq_images',
'uniq_files',
'uniq_raws',
'stat_tags',
'stat_words',
'stat_titles',
'stat_paragraphs',
'stat_anchors',
'stat_strongs',
'stat_bolds',
'stat_emphasis',
'stat_italics',
'stat_dels',
'stat_underlines',
'stat_cites',
'stat_customs',
'stat_icodes',
'stat_bcodes',
'stat_quotes',
'stat_lists'
'post_coms',
'post_tags',
'post_words',
'post_titles',
'post_paragraphs',
'post_anchors',
'post_abbrs',
'post_strongs',
'post_bolds',
'post_emphasis',
'post_italics',
'post_dels',
'post_underlines',
'post_cites',
'post_customs',
'post_icodes',
'post_bcodes',
'post_quotes',
'post_lists'
)
for value in values:

View File

@ -659,7 +659,7 @@ def create_domain(target):
except: active = False
print(tr.form_warn)
show.read_lines(dom.config)
show.read_lines(dom.config, False)
# Activate and prepare domain ?
#------------------------------
@ -677,12 +677,10 @@ def create_domain(target):
#----------------
tyto.set_file(dom.config, False, '\nactivated = True')
# RELoad config
#--------------
importlib.reload(dom)
# Create folders from configuration file
#---------------------------------------
folders = \

View File

@ -1,11 +1,26 @@
#!/usr/bin/env python3
# Name: Tyto - Littérateur
# Type: HTML template
# Description: Create raw HTML template
# file: html.py
# Folder: /var/lib/tyto/program/
# By echolib (XMPP: im@echolib.re)
# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib@dismail.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the License, or
# 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Create HTML page
# File: /var/lib/tyto/program/show.py
#----------------------------------------------------------------------
#------------
# funny stats
@ -19,7 +34,7 @@
import os, sys, importlib
import logs, dom, tyto, form
import logs, db, dom, tyto, form
# load locale translation
trans_dir = '/var/lib/tyto/translations'
@ -64,22 +79,22 @@ def create_metas_page():
#-------------------
metas_page = ''
scale = 'width=device-width, initial-scale=1.0'
all_tags = db.domain_tags + ',' + db.tags
all_tags = dom.tags + ',' + db.tags
css_file = 'styles.css'
css_ref = 'href="%stemplate/%s"'%(db.sub_uri, css_file)
rss_ref = 'type="application/rss+xml" ' + \
'href="%s%s" title="RSS 2.0. %s %s %s"'%(
db.sub_uri, db.domain_rss,
db.domain_title, db.domain_sep, db.domain_short
db.sub_uri, dom.rss,
dom.title, dom.sep, dom.shortname
)
icon_file = 'favicon.png'
icon_ref = 'type="image/png" href="%stemplate/%s"'%(
db.sub_uri, icon_file
)
relme = '' # External URL in metas (if exists in config domain)
if db.domain_relme:
if dom.relme:
relme = '\n <link rel="me" type="text/html" href="%s">'%(
db.domain_relme
dom.relme
)
# Create author and date publish section infos
@ -91,10 +106,10 @@ def create_metas_page():
metas = \
'<!--# include virtual="/template/metas.html"-->\n' + \
' <meta name="viewport" content="%s" />\n'%scale + \
' <meta name=”url” content=”%s” />\n'%db.domain_www_url + \
' <meta name="language" content="%s" />\n'%db.domain_lang + \
' <meta name="reply-to" content="%s" />\n'%db.domain_mail + \
' <meta name="copyright" content="%s" />\n'%db.domain_license + \
' <meta name=”url” content=”%s” />\n'%dom.www_url + \
' <meta name="language" content="%s" />\n'%dom.lang_site + \
' <meta name="reply-to" content="%s" />\n'%dom.mail + \
' <meta name="copyright" content="%s" />\n'%dom.license + \
' <meta name="generator" content="%s" />\n'%tyto.Tyto + \
' <meta name="title" content="%s" />\n'%db.title + \
' <meta name="author" content="%s" />\n'%db.author + \
@ -106,14 +121,14 @@ def create_metas_page():
' <link rel="stylesheet" %s />\n'%css_ref + \
' <link rel="shortcut icon" %s />\n'%icon_ref + \
' <!-- Open Graph data -->\n' + \
' <meta property="og:site_name" content="%s" />\n'%db.domain_title + \
' <meta property="og:site_name" content="%s" />\n'%dom.title + \
' <meta property="og:title" content="%s" />\n'%db.title + \
' <meta property="og:type" content="article" />\n' + \
' <meta property="og:url" content="%s" />\n'%db.http_www + \
' <meta property="og:description" content="%s" />\n'%db.about + \
' <meta property="og:image" content="%s" />\n'%db.snpic + \
'%s'%relme + \
' <title>%s</title>'%db.title
' <title>%s %s %s</title>'%(db.title, dom.sep, dom.title)
#=======================================#
@ -122,23 +137,23 @@ def create_metas_page():
def create_main_page(target, article_bottom):
global main_page
if not tyto.exists(db.wip_footer):
logs.out("1", db.wip_footer, True)
if not tyto.exists(dom.wip_footer_f):
logs.out("1", dom.wip_footer_f, True)
if not tyto.exists(db.wip_metas):
logs.out("24", '(HTML metas): %s'%db.wip_metas, False)
if not tyto.exists(dom.wip_metas_f):
logs.out("24", '(HTML metas): %s'%dom.wip_metas_f, False)
# Create link for website's logo
#-------------------------------
logo_html = '<a href="/"\n' + \
'%stitle="%s %s logo: %s"\n'%(11 * " ",
tyto.trans[1][tyto.n], db.domain_sep, db.domain_title
tyto.trans[1][tyto.n], dom.sep, dom.title
) + \
'%sid="site_logo_link">\n'%(11 * " ") + \
'%s<img src="%stemplate/%s"\n'%(
10 * " ", db.sub_uri, db.domain_logo
10 * " ", db.sub_uri, dom.logo
) + \
'%salt="logo: %s"\n'%(15 * " ", db.domain_title) + \
'%salt="logo: %s"\n'%(15 * " ", dom.title) + \
'%sid="site_logo_image" />\n'%(15 * " ") + \
'%s</a>'%(8 * " ")
@ -147,7 +162,7 @@ def create_main_page(target, article_bottom):
#-----------------------#
main_page = \
'<!Doctype html>\n' + \
'<html lang="%s">\n'%db.domain_lang + \
'<html lang="%s">\n'%dom.lang_site + \
' <head>\n' + \
'%s\n'%metas + \
' </head>\n\n' + \
@ -161,9 +176,9 @@ def create_main_page(target, article_bottom):
' <a href="/"\n' + \
' title="%s"\n'%(tyto.trans[1][tyto.n]) + \
' id="site_link">\n' + \
' <h1 id="site_title">%s</h1>\n'%db.domain_title + \
' <h1 id="site_title">%s</h1>\n'%dom.title + \
' </a>\n' + \
' <p id="site_about">%s</p>\n'%db.domain_about + \
' <p id="site_about">%s</p>\n'%dom.about + \
' </div>\n' + \
'<!--# include virtual="/template/navbar.html"-->\n' + \
' </header>\n' + \
@ -187,7 +202,7 @@ def create_main_page(target, article_bottom):
#--------------------------------------------#
def create_html_infos_section(process):
# Need to reload the DB to get last time updated
exec(open(db.post_db).read(), globals())
exec(open(db.config).read(), globals())
global post_pub, meta_pub, date_raw
if process == 'wip':
@ -205,7 +220,7 @@ def create_html_infos_section(process):
# Show source code in article-infos if True in DB
post_code = ''
if db.article_code:
if dom.article_code:
# Set HTML
post_code = \
'<span id="article_code"> ' + \
@ -213,7 +228,7 @@ def create_html_infos_section(process):
os.path.basename(db.short_src),
tyto.trans[21][tyto.n],
tyto.trans[3][tyto.n]
)
) + \
' </span>'
@ -248,26 +263,24 @@ def create_html_infos_section(process):
# Create HTML sidebar from file tyto.sidebar #
#--------------------------------------------#
def create_sidebar(option):
domain.domain_needed
dom.valid()
try:
db.sidebar_load
if not tyto.exists(db.sidebar_load):
logs.out("1", db.sidebar_load, True)
if not tyto.exists(dom.sidebar_f):
logs.out("1", dom.sidebar_f, True)
except:
logs.out("1", 'Sidebar load file', True)
logs.out("1", 'Sidebar ?', True)
try:
db.sidebar_items
if int(db.sidebar_items) > 16: db.sidebar_items = 6
if int(dom.sidebar_items) > 16: db.sidebar_items = 6
except:
db.sidebar_items = 6
pub_opts = ('www', 'pub')
if option == 'wip': target = db.wip_sidebar
elif option == 'www': target = db.www_sidebar
elif option == 'pub': target = db.www_sidebar
if option == 'wip': target = dom.wip_sidebar_f
elif option == 'www': target = dom.www_sidebar_f
elif option == 'pub': target = dom.www_sidebar_f
# If content in sidebar, go True
sidebar_new = False
@ -285,8 +298,8 @@ def create_sidebar(option):
counter = 0
nolines = ('#', '/')
sidebar_title = db.sidebar_title
sidebar_lines = open(db.sidebar_load, 'r').read()
sidebar_title = dom.sidebar_title
sidebar_lines = open(dom.sidebar_f, 'r').read()
for line in sidebar_lines.rsplit('\n'):
if not line or line.startswith(nolines): continue
@ -296,14 +309,14 @@ def create_sidebar(option):
# Get full article URI and check if exists
sidebar_has = True
f_uri = '%s%s'%(db.domain_articles, line)
f_uri = '%s%s'%(dom.articles_d, line)
if not tyto.exists(f_uri):
logs.out("24", f_uri, False)
continue
# Get Hash from uri to get db file
hash_uri = tyto.get_filesum(f_uri, False)
db_uri = '%s%s.conf'%(db.articles_db, hash_uri)
db_uri = '%s%s.config'%(dom.articles_db_d, hash_uri)
if not tyto.exists(db_uri):
logs.out('25', line, False)
continue
@ -332,9 +345,9 @@ def create_sidebar(option):
# Count: no more than max configured items
counter += 1
if counter > db.sidebar_items:
if counter > dom.sidebar_items:
logs.out("31", '(%s): %s "%s"'%(
db.sidebar_items, line, title),
dom.sidebar_items, line, title),
False
)
continue

View File

@ -1,11 +1,28 @@
#!/usr/bin/env python3
# Name: Tyto - Littérateur
# Type: Command arguments 'show', 'showdb' manager
# Description: manage 'show' and 'showdb' from command action argument
# file: show.py
# Folder: /var/lib/tyto/program/
# By echolib (XMPP: im@echolib.re)
# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib@dismail.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the License, or
# 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Manage show*/edit* arguments.
# Read or edit file from [target] argument
# File: /var/lib/tyto/program/show.py
#----------------------------------------------------------------------
#------------
# funny stats
@ -17,9 +34,64 @@
#**********************************************************************
import os, sys, importlib
import os, sys, locale, importlib
import args, lang, logs, dom, db, form, tyto, check, stats
# load locale translation
trans_dir = '/var/lib/tyto/translations'
sys.path.insert(0, trans_dir)
# System language
try: lang_sys = locale.getdefaultlocale()[0].split('_')[0]
except: lang_sys = 'en'
# Get default system language
# or set "en" (english) if no translation file
try:
lang_site = lang_sys
os.path.exists('%s/site_%s.py'%(trans_dir, lang_site))
except:
lang_site = 'en'
# Set language site/form from configuration domain
# or set default english if not known
try:
dom.exists
lang_site = dom.lang_site
os.path.exists('%s/site_%s.py'%(trans_dir, lang_site))
tr = importlib.import_module('site_%s'%lang_site, package=None)
except:
tr = importlib.import_module('site_%s'%lang_site, package=None)
#========================#
# Read lines from a file #
# alone: True/False #
#------------------------#
def read_lines(f, alone):
if not f: return
if not tyto.exists(f): logs.out("1", f, True)
datas = open(f).read()
# Align content line, after line number
ln_datas = len(datas.splitlines()) + 1
sp_max = len(str(ln_datas))
print('', f)
print(' ├─%s─┐'%(sp_max * ''))
for ln, line in enumerate(datas.rsplit('\n'), 1):
sp = sp_max - len(str(ln))
print('%s %s%s'%(ln, int(sp) * " ", line))
# Ends for show. False should be for form
if alone: decor = ''
else: decor = ''
print(' %s%s─┘'%(decor, sp_max * ''))
dom.valid()
#======================#
# From command line: #
# - 'showdb' / 'show' #
@ -28,130 +100,126 @@ import args, lang, logs, dom, db, form, tyto, check, stats
# final html, db, load #
#----------------------#
def manage(target):
# Domain must be valid
if not dom.exists: logs.out("10", '', True)
if not target == "domain": dom.valid()
dom.valid()
do = False
actions_read = ('show', 'show-about', 'show-db', 'show-wip', 'show-www')
actions_edit = ('edit', 'edit-about', 'edit-db', 'edit-wip', 'edit-www')
post_src = post_db = post_wip = post_www = False
actions_about= ('show-about', 'edit-about')
actions_wip = ('show-wip', 'edit-wip')
actions_www = ('show-www', 'edit-www')
# Set file from post DB when target is an article
#------------------------------------------------
try: post_src = db.uri_file
except: pass
actions_post = ('show', 'edit')
actions_db = ('show-db', 'edit-db')
if post_src:
target = "post"
try: post_db = db.config
except: pass
# Target is not a post uri (sidebar, navbar, metas, footer)
#----------------------------------------------------------
if target in args.pass_targets:
if args.action in actions_post:
do = {
"domain" : dom.config,
"footer" : dom.footer_f,
"metas" : dom.metas_f,
"navbar" : dom.navbar_f,
"sidebar" : dom.sidebar_f
}
try: post_wip = db.post_wip
except: pass
elif args.action in actions_about:
do = {
"footer" : dom.footer_about_f
}
try: post_www = db.post_www
except: pass
elif args.action in actions_wip:
if target == 'stats':
stats.manage_stats('wip')
return
# Except for show-about > Show post DB
if args.action == "show-about":
target = 'post'
do = {
"domain" : dom.config,
"footer" : dom.wip_footer_f,
"metas" : dom.wip_metas_f,
"navbar" : dom.wip_navbar_f,
"sidebar" : dom.wip_sidebar_f
}
elif args.action in actions_www:
if target == 'stats':
stats.manage_stats('www')
return
do = {
"domain" : dom.config,
"footer" : dom.www_footer_f,
"metas" : dom.www_metas_f,
"navbar" : dom.www_navbar_f,
"sidebar" : dom.www_sidebar_f
}
# Target is a post uri
#---------------------
elif db.uri_file:
# Get hash when edit, and ask if file changed
# When edit article, get src hash
if args.action == "edit":
curr_hash = tyto.get_filesum(db.uri_file, True)
if args.action in actions_post:
target = "post"
do = {"post" : db.uri_file}
# Post has database
elif db.exists:
do = {
"db" : db.config,
"wip" : db.post_wip,
"www" : db.post_www
}
if args.action in actions_wip: target = "wip"
elif args.action in actions_www: target = "www"
elif args.action in actions_db: target = "db"
# Convert command action to do[]
# as edit* &nd show* [action] have same target file
actions = \
{
'show' : 'src',
'edit' : 'src',
'post' : 'src',
'show-db' : 'db',
'edit-db' : 'db',
'show-about' : 'about',
'edit-about' : 'about',
'show-wip' : 'wip',
'edit-wip' : 'wip',
'show-www' : 'www',
'edit-www' : 'www'
}
action = actions[args.action]
#print('> show: target', target)
# Set target file from "new" [action]
do = \
{
'src' : {
'domain' : dom.config,
'footer' : dom.footer_f,
'metas' : dom.metas_f,
'navbar' : dom.navbar_f,
'sidebar' : dom.sidebar_f,
'post' : post_src
},
'db' : {
'domain' : dom.config,
'footer' : dom.footer_f,
'metas' : dom.metas_f,
'navbar' : dom.navbar_f,
'sidebar' : dom.sidebar_f,
'post' : post_db
},
'about' : {
'domain' : dom.config,
'footer' : dom.footer_about_f,
'metas' : dom.metas_f,
'navbar' : dom.navbar_f,
'sidebar' : dom.sidebar_f,
'post' : post_db
},
'wip' : {
'domain' : dom.config,
'footer' : dom.wip_footer_f,
'metas' : dom.wip_metas_f,
'navbar' : dom.wip_navbar_f,
'sidebar' : dom.wip_sidebar_f,
'post' : post_wip
},
'www' : {
'domain' : dom.config,
'footer' : dom.www_footer_f,
'metas' : dom.www_metas_f,
'navbar' : dom.www_navbar_f,
'sidebar' : dom.www_sidebar_f,
'post' : post_www
},
}
if not do:
if not db.post: sys.exit(1)
# Read or edit file, according to legacy args.action
try:
file = do[action][target]
if args.action in actions_read:
read_lines(file, True)
elif args.action in actions_edit:
tyto.edit_file(file)
except:
logs.out("28", '%s + %s'%(action, target), True)
# Read lines of, or edit file
if args.action in actions_read: read_lines(do[target])
elif args.action in actions_edit: tyto.edit_file(do[target])
# After editing article, if change, ask to check again
if args.action == "edit" and not args.pass_targets:
new_hash = tyto.get_filesum(db.uri_file, True)
# If edit article and hash changed, ask to check
if args.action == "edit" and post_src:
new_hash = tyto.get_filesum(post_src, True)
if curr_hash != new_hash:
ask = ''
try: ask = input('-> Check your changes ? ')
try: ask = input('%s%s '%(tr.post_chg, tr.q))
except KeyboardInterrupt:
print('')
logs.out("255", '', True)
if not ask in ['y', 'Y']:
if not ask in form.answer_yes:
logs.out("255", '', True)
# Reload post DB (if edited article, and check it if ask "y")
importlib.reload(db)
check.manage_check(db.uri_file)
check.manage(post_src)
#============================================#
# Generic function to read lines from a file #
#--------------------------------------------#
def read_lines(f):
if not f: return # Maybe
if not tyto.exists(f): logs.out("1", f, True)
datas = open(f).read()
# Align content line, after line number
ln_datas = len(datas.splitlines()) + 1
sp_max = len(str(ln_datas))
for ln, line in enumerate(datas.rsplit('\n'), 1):
sp = sp_max - len(str(ln))
print('%s %s%s'%(ln, int(sp) * " ", line))
dom.valid()

View File

@ -135,14 +135,22 @@ words_tags = [
('-(', '-)', '-(', '-)', 'lists', 't')
]
# Tags that do not need to be paired
#-----------------------------------
single_tags = [
('|', '<br />'), # New Line
('->', '<a class="anchor_target" id="%s"></a>') # Anchors
]
# When counting words, do no count line starting with:
nolinewords = \
(
'((', '))',
'{{', ']]',
'{{', '}}',
'->', '|',
'_image:', '_taw:'
words_tags[10][0], words_tags[10][1], # paragraphs
words_tags[11][0], words_tags[11][1], # quotes
words_tags[12][0], words_tags[12][1], # bcodes
words_tags[13][0], words_tags[13][1], # lists
single_tags[0][0], single_tags[1][0], # New line, anchor
'_%s:'%opt_header_tags[1], '_%s:'%opt_header_tags[4] # _image:, _raw:
)
# warning symbols (Check if paired)
@ -156,16 +164,9 @@ tpl_tags = [
]
# Tags that do not need to be paired
#-----------------------------------
single_tags = [
('|', '<br />'), # New Line
('->', '<a class="anchor_target" id="%s"></a>') # Anchors
]
# Markers for lists, to check in list content
#--------------------------------------------
markers_lists = ('+', '=', ' ')
markers_lists = ('+', '=', ' ', '#')
# Tags used for titles
#---------------------
@ -335,23 +336,34 @@ def protect_bcodes_quotes(process, post_bottom):
b64_quote = b64('Encode', quote, 'Q64.', '.Q64')
line = b64_quote
'''
# Remove coemments and empty lines for wip
if not in_quote and not in_bcode:
if not line: continue
if not line:
continue
if line.startswith('#') and not line.startswith(titles_tags):
continue
'''
# Counters and keep tags for check process
#-----------------------------------------
if process == "check":
if in_bcode and not start_bcode \
or in_quote and not start_quote :
continue
line = '#-Protectedline-'
# Set new article content for wip process
#----------------------------------------
elif process == "wip":
# Remove empty line and comments
if not in_quote and not in_bcode:
if not line:
continue
elif line.startswith('#') \
and not line.startswith(titles_tags):
continue
# bcode convertion to base64
if in_bcode:
# Convert lines to b64
@ -369,7 +381,6 @@ def protect_bcodes_quotes(process, post_bottom):
#----------------
# check: remove quote/bcode, keep tags
# wip: replace close tag with quote/bcode (keep in open tag)
if not line: continue
if not protect_article: protect_article = line
else: protect_article = '%s\n%s'%(protect_article, line)
@ -498,34 +509,43 @@ def replace_in_db(post_db, process, hash_post):
# Copy files used by article to srv #
#-----------------------------------#
def files_to_srv(server):
import db
for uri in db.uris:
# Extract Directories from uri file
d_in = uri.split("/")[-1]
d_in = uri.rsplit(d_in)[0]
# Destination file to server
f_src = '%s%s'%(db.domain_articles, uri)
if server == 'wip': f_dst = '%s%s'%(db.srv_wip, uri)
elif server == 'www': f_dst = '%s%s'%(db.srv_www, uri)
f_src = '%s%s'%(dom.articles_d[:-1], uri)
if server == 'wip':
f_dst = '%s%s'%(dom.srv_wip[:-1], uri)
d_dst = '%s%s'%(dom.srv_wip[:-1], d_in)
elif server == 'www':
f_dst = '%s%s'%(dom.srv_www[:-1], uri)
d_dst = '%s%s'%(dom.srv_www[:-1], d_in)
# Create folder and subfolders
f_uri = uri.split("/")[-1]
f_uri = uri.rsplit(f_uri)[0]
try:
os.makedirs('%s%s'%(f_dst, f_uri), exist_ok=True)
os.makedirs(d_dst, exist_ok=True)
logs.out("33", d_dst, False)
except:
logs.out('4', '%s%s'%(f_dst, f_uri), True)
logs.out('4', d_dst, True)
try:
shutil.copy2(f_src, f_dst)
logs.out("33", f_dst, False)
logs.out("32", f_dst, False)
except:
logs.out('4', f_dst, True)
if db.article_code:
if server == "wip": base_srv = db.srv_wip
elif server == "www": base_srv = db.srv_www
if dom.article_code:
if server == "wip": base_srv = dom.srv_wip
elif server == "www": base_srv = dom.srv_www
f_dst = "%s%s"%(base_srv, db.short_src)
try:
shutil.copy2(db.post_src, f_dst)
logs.out("33", f_dst, False)
logs.out("32", f_dst, False)
except:
logs.out('4', f_dst, True)

View File

@ -1,11 +1,30 @@
#!/usr/bin/env python3
# Name: Tyto - Littérateur
# Type: Convert article to HTML
# Description: Converters from Source to HTML
# file: wip.py
# Folder: /var/lib/tyto/program/
# By echolib (XMPP: im@echolib.re)
# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib@dismail.de>
# Copyright (C) 2023 Adrien Bourmault <neox@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the License, or
# 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
# XMPP: neox (neox@a-lec.org)
#
# Description: Manage 'wip' argument
# Convert article to HTML from Tyto's format markers
# File: /var/lib/tyto/program/wip.py
#----------------------------------------------------------------------
#------------
# funny stats
@ -17,10 +36,36 @@
#**********************************************************************
import os, re, sys, shutil, importlib
import os, re, sys, locale, shutil, importlib, time
from pathlib import Path
import args, logs, dom, db, tyto, html, form, stats
import args, logs, lang, dom, db, tyto, html, form, stats
# load locale translation
trans_dir = '/var/lib/tyto/translations'
sys.path.insert(0, trans_dir)
# System language
try: lang_sys = locale.getdefaultlocale()[0].split('_')[0]
except: lang_sys = 'en'
# Get default system language
# or set "en" (english) if no translation file
try:
lang_site = lang_sys
os.path.exists('%s/site_%s.py'%(trans_dir, lang_site))
except:
lang_site = 'en'
# Set language site/form from configuration domain
# or set default english if not known
try:
dom.exists
lang_site = dom.lang_site
os.path.exists('%s/site_%s.py'%(trans_dir, lang_site))
tr = importlib.import_module('site_%s'%lang_site, package=None)
except:
tr = importlib.import_module('site_%s'%lang_site, package=None)
#=========================================#
@ -55,10 +100,10 @@ def manage_wip(target):
# Per article with target
#------------------------
# Exit with these conditions
if not target: logs.out("5", '', True)
if not db.post_exists: sys.exit(1)
if not db.db_exists: logs.out("25", db.uri_file, True)
if db.old_chk: logs.out("9", db.uri_file, True)
if not target: logs.out("5", '', True)
if not db.exists: sys.exit(1)
if not db.config: logs.out("25", db.uri_file, True)
if db.old_chk: logs.out("9", db.uri_file, True)
# Article has changed or wip file missing
if db.old_wip or not db.file_wip:
@ -68,12 +113,14 @@ def manage_wip(target):
else:
logs.out("19", db.date_wip, False)
try:
res = input('Create new wip page ? ')
res = input('[%s] %s%s '%(db.title, tr.wip_new, tr.q))
except KeyboardInterrupt:
print('')
logs.out("255", '', True)
if not res in ['y', 'Y']: return
if not res in form.answer_yes:
logs.out("255", '', True)
wip_article(db.uri_file)
@ -85,7 +132,7 @@ def wip_all(process):
tyto.process_all('Wip')
# Sort by newer articles (created by last check)
db_articles = sorted(Path(db.articles_db).iterdir(),
db_articles = sorted(Path(db.articles_db_d).iterdir(),
key=os.path.getmtime
)
@ -93,7 +140,7 @@ def wip_all(process):
option = args.target
found = False
for post_db in db_articles:
if not str(post_db).endswith('.conf'): continue
if not str(post_db).endswith('.config'): continue
# Load DB
exec(open(post_db).read(),globals())
@ -104,7 +151,7 @@ def wip_all(process):
if option == "again" and db.old_wip: continue
if option == "newer" and not db.old_wip: continue
print(':> [%s] - %s'%(db.title, db.post_src))
print(' ├ [%s] > %s'%(db.title, db.post_src))
if db.old_chk:
logs.out("9", '', False)
continue
@ -127,14 +174,14 @@ def wip_article(target):
global post_bottom
# Protect block-codes and quotes
if db.stat_bcodes or db.stat_quotes > 0:
if db.post_bcodes or db.post_quotes > 0:
tyto.protect_bcodes_quotes('wip', post_bottom)
post_bottom = tyto.protect_article
# Protect inline-codes
if db.stat_icodes > 0:
if db.post_icodes > 0:
tyto.protect_icodes(post_bottom)
post_bottom = tyto.protect_article
post_bottom = tyto.protect_article
# Convert contents from modules
@ -151,16 +198,17 @@ def wip_article(target):
wip_tabs() # make HTML tabulations
# Replace in DB hash_wip and date_wip
tyto.replace_in_db(db.post_db, 'wip', db.hash_post)
tyto.replace_in_db(db.config, 'wip', db.hash_post)
# Get article DB in html.py
html.set_page(db.uri_file, post_bottom)
#print(html.main_page)
# Create wip file
os.makedirs('%s%s'%(db.srv_wip, db.direc_src), exist_ok=True)
os.makedirs('%s%s'%(dom.srv_wip, db.direc_src), exist_ok=True)
logs.out("33", '%s%s'%(dom.srv_wip, db.direc_src), False)
tyto.set_file(db.post_wip, 'New', html.main_page)
logs.out("33", db.post_wip, False)
logs.out("32", db.post_wip, False)
# Copy needed files (Also create sub-folders)
tyto.files_to_srv('wip')
@ -182,8 +230,9 @@ def file_to_string(post_file):
continue
if sep:
if not post_bottom: post_bottom = line
else: post_bottom = '%s\n%s'%(post_bottom, line)
if not line: continue
elif not post_bottom: post_bottom = line
else: post_bottom = '%s\n%s'%(post_bottom, line)
else:
if not post_header: post_header = line
else: post_header = '%s\n%s'%(post_header, line)
@ -237,7 +286,7 @@ def wip_words_tags():
for ln, line in enumerate(post_bottom.rsplit('\n')):
# Paragraphs
# Open tag
if db.stat_paragraphs > 0:
if db.post_paragraphs > 0:
if line.startswith(tyto.words_tags[10][0]):
set_css = tyto.get_css(line)
post_bottom = post_bottom.replace(post_bottom.rsplit('\n')[ln],
@ -249,7 +298,8 @@ def wip_words_tags():
tyto.words_tags[10][3]
)
# Open anchors
if db.stat_anchors == 0: continue
if db.post_anchors == 0: continue
anchor_links = re.findall(r'>_(.+?):', line)
for item in anchor_links:
anchor_id = '%s%s:'%(tyto.words_tags[0][0], item)
@ -333,7 +383,7 @@ def wip_images():
for i in range(1, db.uniq_images + 1):
image = 'db.image_%s'%i
target = width = height = False
set_css = db.domain_css + '_image'
set_css = dom.css + '_image'
imag_html = ''
if eval(image)[0] == values[0]:
@ -401,7 +451,7 @@ def quote_params(qline):
# Convert quote in article #
#--------------------------#
def wip_quotes() :
if db.stat_quotes == 0: return
if db.post_quotes == 0: return
global post_bottom
global author, link, lang, book, date
@ -545,7 +595,7 @@ def wip_quotes() :
# Content is HTML ready #
#--------------------------#
def wip_icodes():
if db.stat_icodes == 0: return
if db.post_icodes == 0: return
global post_bottom
@ -561,7 +611,7 @@ def wip_icodes():
# Content is raw, and have to be converted in HTML #
#--------------------------------------------------#
def wip_bcodes():
if db.stat_bcodes == 0: return
if db.post_bcodes == 0: return
global post_bottom
@ -595,7 +645,7 @@ def wip_bcodes():
# Check between titles to set div or not #
#----------------------------------------#
def wip_titles():
if db.stat_titles == 0: return
if db.post_titles == 0: return
global post_bottom
article_temp = post_bottom
@ -740,3 +790,94 @@ def wip_tabs():
post_bottom = article_temp
#=================================#
# Convert list in markers to HTML #
# Def from neox <- Thx a lot #
#---------------------------------#
def convert_list(markdown_str):
# First step : reshape lines
items = []
inside_item = 0
index = -1
# Cut string with \n's
strlist = markdown_str.split("\n")
# Find items
for i in range(len(strlist)):
if "-(" in strlist[i] or "-)" in strlist[i]:
continue
if strlist[i][0] != "=" and strlist[i][0] != "+":
if inside_item != 1:
inside_item = 1
else:
inside_item = 0
if inside_item == 0:
items.append(strlist[i])
index += 1
if inside_item == 1:
items[index] += strlist[i].lstrip()
#print("[{}] index {}, inside_item {}, curstr {}\n".format(i, index, inside_item, strlist[i]))
# Second step : parsing
UL = 1
OL = 2
CLOSING = ["ERROR", "</ul>\n", "</ol>\n"]
OPENING = ["ERROR", "<ul>\n", "<ol>\n"]
rank_stack = []
rank = 0
cur_rank = 0
state = 0
old_state = 0
work_str = ""
for i in range(len(items)):
if "-(" in items[i] or "-)" in items[i]:
continue
rank = cur_rank
descriptor = items[i].split(" ")[0]
text = items[i][items[i].find(" "):]
cur_rank = len(descriptor)
if "=" in descriptor:
state = UL
elif "+" in descriptor:
state = OL
else:
raise(Exception)
# rank up
if cur_rank > rank:
for i in range(cur_rank - rank - 1):
work_str += " "*(rank+i) + OPENING[rank_stack.append(UL)]
rank_stack.append(state)
work_str += " "*rank + OPENING[state]
# rank down
elif cur_rank < rank:
for i in range(rank - cur_rank - 1):
work_str += " "*(rank-i-1) + CLOSING[rank_stack.pop()]
work_str += " "*cur_rank + CLOSING[rank_stack.pop()]
work_str += " "*cur_rank + "<li>" + text + "</li>\n"
print("[{}] rank_stack {}, state {}, old_state {}, rank {}, cur_rank {}, text {}\n".format(
i, rank_stack, state, old_state, rank, cur_rank, text))
work_str += " "*(cur_rank-1) + CLOSING[rank_stack.pop()]
return(work_str)
#print(convert_list(str_exemple))

View File

@ -59,10 +59,15 @@ mail_to = "Contact by %s the admin of"%mail.lower()
feed = "Feed"
generator = "Generator"
# Check
post_chg = "Article was edited. Check it"
# Wip
wip_new = "Create new HTML page in wip"
# Form
#----------------------------------------------------------------------
form_edit = "Edit the domain with the form"
form_start = ' ├──────────────────────────────────────────────┐\n' + \
' │ Configure a new domain for current directory │\n' + \
' │ Answer Y/y = yes. Enter to keep {default}\n' + \

View File

@ -59,6 +59,12 @@ mail_to = "Contacter par %s l'administrateur de"%mail.lower()
feed = "Flux"
generator = "Generateur"
# Check
post_chg = "Article édité. Le vérifier"
# Wip
wip_new = "Créer une nouvelle page HTML dans wip"
# Formulaire
#----------------------------------------------------------------------
form_edit = "Éditer le domaine avec le formulaire"