diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8b247ba..2686b6a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,213 +10,5 @@ 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
-- Fill Article HTML metas datas
-- Working on files copies to wip server with "wip" command
-- - some changes in post DB and check process
-
-## [1.9.37]
-- Preparing full HTML Page
-- Some fixes
-- Added web target (without index.html) in section "FILE" in post DB
-- Added article footer contents
-
-## [1.9.36]
-- fix translations modules
-- added metas module
-- added command "show metas" to see those already set in page with post
-
-## [1.9.35]
-- Working on creating modules
-- - Todo last: metas
-- check
-- - target: domain, wip, www to check directories and files
-- - - domain: create .raw modules and wip modules (.html)
-- wip
-- - html values are now in wip.py
-- fixes and more...
-
-## [1.9.34]
-- Working on creating modules
-- - fixes typos codes
-- - header, navbar, sidebar = ok
-- - toto footer contents and testing things
-- - Manage modules with an ini db file to avoid creating HTML updated modules
-
-## [1.9.33]
-- Working on creating modules (header, navbar, sidebar, header)
-- - Added working header module
-- - Finishing navbar module...
-- - Todo Next: sidebar and footer modules
-
-## [1.9.32]
-- Working on creating modules (header, navbar, sidebar, header)
-
-## [1.9.31]
-- Fix replacing markers starting LINE with HTML
-- Added tpl_files directory
-- - addes styles.css (empty with classes used)
-
-## [1.9.30]
-- 'wip' process
-- - About all markers done !
-
-## [1.9.29]
-- Translations
-- - added for logs (english)
-- - updated french logs
-- wip (working on...)
-- - added modules conversions (source to HTML)
-- check
-- - some fixes and updated code
-- tools
-- - check css content
-- readme : updated article example with comments
-
-## [1.9.28]
-- readme
-- - updated tyto article, with comments to show how to
-- multiple targets
-- - fix CSS classe name error
-- - reset stats, post.error, HEADERS datas
-- check process:
-- - Added hr and br tags (CSS class name check)
-- - fix blockquote title HTML
-- - New method to split separator in article
-- - fix icode, bcode contents HTML signs (converted)
-
-## [1.9.27]
-- fix when target article .tyto is missing
-- Nearly all stats are added in DB from modules
-- Only used tags and stats (or nearly) are added to DB
-- cleaner code
-- check:
-- - added words_tags (strong, italics...)
-- - "all" target now ready
-
-## [1.9.26]
-- user can indent titles in text
-- prepared words markers (strong, bolds) (some to add soon)
-
-## [1.9.25]
-- fix typo when creating HTML list
-- new anchors process (HTML prepared at 'check')
-
-## [1.9.24]
-- new list process (HTML prepared at 'check')
-
-## [1.9.23]
-- new quote process (HTML prepared at 'check')
-
-## [1.9.22]
-- new bcode process (html prepared for wip)
-- new post database management values
-- new icode process (html prepared for wip)
-- bcodes and icodes are FIRST processed in text article
-- generic check fonction for bcodes, quotes, lists, paragraphs
-- lots more
-
-## [1.9.21]
-- new indentation (3 spaces)
-- added 'raw:' marker
-- (for wip process):
-- - added html titles to post database
-- - added html comments to post database (default: ';; a comment')
-- - added val3 tag as html comment to content, and convert content to base64
-- - - added values to post database
-- cleaner code
-
-## [1.9.20]
-- working on 'check' process
-- - updated 'logo:' process
-- - added 'abbr:' process
-
-## [1.9.19]
-- working on 'check' process
-- - Added post 'logo: URI' (for social network share + opt show on page)
-
-## [1.9.18]
-- working on 'check' process
-- - added image: tag
-- - added value 2 (tag line 2) uri check (generic, root, post)
-- - some corrections for domain config file
-- - prepared html values for wip
-
-## [1.9.17]
-- working on 'check' process
-- - dev on checking file used in some post header tags
-
-## [1.9.16]
-- working on 'check' process
-- - dev: post database values (lots are missing)
-- - added links, files supports
-- - testing some new markers
-
-## [1.9.15]
-- Added 'check' process for bcodes, quotes and paragraphs + stats
-- - Their contents must be indented
-- - replace with empty lines for bcodes and quotes
-
-## [1.9.14]
-- added 'check' process for block-codes
-
-## [1.9.13]
-- Check: One-Line needed tags, titles
-- Added first stats
-- move ini template from tyto to domain for domain config file
-- Check valid date in article and form domain date
-
-## [1.9.12]
-- preparing check process : head tags in article
-
-## [1.9.11]
-- Preparing for multi-targets with "all"
-- check if article is a .tyto format
-- preparing values for articles
-
-## [1.9.10]
-- cleaner code
-- start/stop domain by user
-- User directories check/create when domain activated
-- Check install configuration
-
-## [1.9.9]
-- cleaner code with new check/update domain process
-
-## [1.9.8]
-- Check/create/update a domain is ready
-
-## [1.9.7]
-- new process to check and update configuration file (bug at write some values)
-
-## [1.9.6]
-- Better management to create/update domain
-
-## [1.9.5]
-- Preparing post database
-
-## [1.9.4]
-- Added start/strop action to activate (or deactivate) domain
-- Directories creation for user working domain
-- better log management for user
-
-
-
+## [1.9.50]
+- Complete new code
diff --git a/LICENSE b/LICENSE
index 2a1caa8..b83cd68 100644
--- a/LICENSE
+++ b/LICENSE
@@ -629,7 +629,7 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
- GSL Statique Littérateur
+ Tyto - Littérateur
Copyright (C) 2022 Libre en Communs / Commissions / Infrastructure
This program is free software: you can redistribute it and/or modify
diff --git a/README.md b/README.md
index 1d83be2..e481b67 100644
--- a/README.md
+++ b/README.md
@@ -1,372 +1,195 @@
# Very early IN dev code
-This program can ve tested but not at all usable. Lots of work to do...
+This program can ve tested and should mainly work. Please report any problems
+
+Tyto - Littérateur is translated in french and english.
# Commands
```
-# Get commands list help
+# Get commands help
tyto
+
+# Get all documentation
+tyto help all
+
+# How to write words tags (strong...) and anchors
+tyto help words anchor
```
+
# Create new domain
- create a domain directory, like www.domain.tld
- Go to this directory
- type `tyto new domain`
- type `tyto check domain`
-- create in new directory domain ".../articles/", an article (see tuto below)
-- type `check myfile.tyto` (or use "wip" instead of check)
+- create in new directory domain ".../articles/", an article (see help)
+- type `wip myfile.tyto`
-## Working on
-- 'wip' action processes
-- Create HTML full page from article
-- Create/Manage modules (metas, header, navbar, sidebar, footer)
-
-## ToDo
-- thinking about creating an auto top article menu from titles
-- create full HTML page
-- sitemaps
-- RSS
-- 'publish' process
-
## Exemple d'article .tyto commenté
```
-#================================================#
-# Entete de l'article #
-# Fin de l'entête avec au moins 5 tirets "-----" #
-# Toute ligne de commentaire "# ..." est ignorée #
-# ! Recommandé de ne pas utiliser le signe "_" #
-#================================================#
+title: Tests
+about: Tests divers
+date: 2023-02-28
+tags: tests
+authors: echolib
-# Pour ne pas inclure cet article dans les sitemaps :
-! NoSitemap
+abbr: CSS
+ Cascading SteelSheet
+ en
-# Données uniques sur UNE ligne
-title: tests d'un article
-about: À propos de cet article de test
-tags: Tyto, tuto,
-author: echolib
-date: 2023-10-27
-
-# Données unique sur UNE ligne optionnelle
-# Si non définit, le logo du domaine est utilisé
-# Ne sera affiché qu'avec _image:logo
-logo: logo.png
-
-# Données multiples sur 3 lignes
-# [TAG]: Nom
-# LIEN
-# Text alternatif
-
-# Reprendre dans l'article : __cliquer sur ce lien
-link: cliquer sur ce Lien
- https://
- Text alternatif
-
-link: Réservez ici
- https://
- Billets
-
-# Reprendre dans l'article : --télécharger ce fichier
-file: télécharger ce fichier
- @/PDFs/hello.pdf
- Un PDF !
-
-# Reprendre dans l'article : _code:codetest
-code: codetest
- @RAWS/test.py
- Exemple d'un code Python
-
-# Reprendre dans l'article : _image:mypic
-image: mypic
- @hello.png
- Text Alt
-
-# Les abréviations :
-# 2eme ligne: Texte alternatif
-# 3ème ligne: valeur affichée dans l'article à la place du Nom
-abbr: HTML
- HuperText Markup Langage
- HTML
-
-# Reprendre dans l'article : ;;css
-abbr: css
- Cascading Stylesheet
- CSS
+link: le site est prêt
+ https://forge.a-lec.org
+ La forge libre
-----
-#=====================================================================#
-# Contenu de l'article #
-# Les classe optionnelles non renseignées deviennent celle du domaine #
-# /!\ Tout code HTML sera interprêté par le navigateur sauf si placé #
-# entre les marqueurs de block-code ou icode #
-#=====================================================================#
-
-# La ligne suivante est un commentaire HTML ""
-# ----------------------------------------------------------------
-;; Commentaire
-
-# Ceci est une ancre avec l'ID uniq1 (ID unique)
-# ----------------------------------------------
--> uniq1
--> top
-
-# Créer un lien vers l'ancre "uniq1"
-# ----------------------------------
->_uniq1: Go to uniq1 anchor_<
-
-# Ceci est une ligne
ayant pour classe hrcss
-# -----------------------------------------------
--- hrcss
-
-# Les Titres de l'article de #1 à #5 ( à )
-# ------------------------------------------------
-#1 Titre en h2
-
-# Contenu dans un paragraphe entre (( ... )) ayant pour classe "mypar"
-# --------------------------------------------------------------------
-(( mypar
- Un long paragraphe...
-
- # Retour à la ligne avec un de classe brcss
- # (les retours à la ligne vides ne sont pas pris en compte)
- # ---------------------------------------------------------
- | brcss
-
- # Reprise du Nom pour les liens de link: et file:
- # Reprise des abréviations
- Il faut __cliquer sur ce Lien, __Réservez ici et --télécharger ce fichier
- ou encore faire une ::css pour du beau rendu ::HTML
-
- # Un paragraphe dans le paragraphe ayant pour classe, celle du domaine
- # --------------------------------------------------------------------
- ((
- Un /_court_/ paragraphe de :_1984_: pour de ~_vrai_~ +_faux en gras_+
- Il faut le ._souligner_. et *_Très Gras_*
+#1 Titre 1
+((
+ Un peu de ::CSS et ::le site est prêt
+ (( note
+ Cet article est un test
))
-
- # Créer un icode (utilise la balise HTML)
- # /!\ ! Doit être sur une même ligne
- # ----------------------------------------------
- {_, _}
- {_{_Afficher un icode brut_}_}
))
-# Un exemple de block code ayant pour classe python
-# Tout contenu entre les marqueurs "{{" et "}}" est conservé
-# ----------------------------------------------------------
-#2 Block Code
-{{ python
- # Un commentaire et du code
- def hello(world):
- world and print(world) or print("NoMore")
+#2 Citation
+("
+ cite: Auteur
+ date: AAAA-MM-JJ
+ book: Nom du livre
+ lang: fr
+ link: https://...
+
+ ((
+ Citation complète dans un paragraphe
+ ))
+)"
+
+#2 Code (bloc)
+{{
+ # Écrire les marqueurs de mots
+ # Chaque marqueur à la classe CSS de la configuration
+ # Astuce : ** + ← + `` + ← + très gras
+
+ *`très gras`* =>
+ +`gras`+ =>
+ /`italique`/ =>
+ ;`italique`; =>
+ _`souligné`_ =>
+ ~`effacé`~ =>
+ [`cité`] => # Contenu
+ :`cité`: => # auteur, nom
+ |`perso`| =>
+
+ # Code dans un texte
+ # ! Les marqueurs d'ouverture et de fermeture de code sont sur la MEME LIGNE
+
+ {` Une entée de liste `} =>
+
+ # ! Dans certains cas, il faut ajouter un espace après le 1er marqueur
+ # et/ou avant le second. Ils seront automatiquement supprimés
+
+ *`DOMAIN/articles/ `* # évite /` : marqueur italique ouvert
}}
+#2 Une liste
+# Liste. Classe CSS possible (défaut : celle dans la configuration)
+# Une entrée de liste peut être ordonnée avec le signe "+" ou non avec "="
+# Une liste peut contenir des entrées mixées ("+" et "=")
+# mais au changement de signe, ajouter un signe !
+# Possible d'écrire une entrée sur plusieurs lignes
-# Écrire en gras, italique...
-# ---------------------------
-#2 Marqueurs de mots
-((
- Même si, il est possible d'écrire directement des balises (HTML), Tyto
- propose de les simplifier, en entourant les mots avec des marqueurs. La
- classe CSS du domaine est utilisée pour chaque marqueur.
-
- {{
- *_Très Gras_* >
- +_En Gras_+ >
- [_Citer un texte_] >
- :_Citer une référence_: >
- ~_Texte barré_~ >
- ._Text souligné_. >
- /_En italique_/ >
- ;_En italique_; >
-
- # Marques multiples, ajouter "&"
- *_&._Très gras et souligné_.&_*
- }}
-))
-
-
-# Dans un block div [[ ... ]] (classe CSS mydiv),
-# La citation entre [" ... "] (classe CSS mycite)
-# est placée dans un paragraphe (classe CSS mycite)
-# ! Tout commentaire "# ..." dans la citation sera affiché...
-# -----------------------------------------------------------
-#2 Citation
-[[ mydiv
- [" mycite
- ;; A great quote here !
- cite: Someone
- date: 2023-10-13
- book: A History
- lang: en
- link: https://...
-
- (( mycite
- Here, i am
- ))
- "]
-]]
-
-
-# Créer une liste ol/ul entre <: ... :> (classe mylist)
-# dans un paragraphe (classe du domaine)
-# "+" pour ol, "=" pour ul
-# Ajouter toujours un signe pour un sous-item ou /!\ au changement de signe
-# -------------------------------------------------------------------------
-#2 Une liste mixée {_, _}
-((
- <: mylist
- + numeric ol item 1
- ++ numeric ol sub-Item 1
- +++ numeric ol sub-sub-item 1
- ==== ul item >_top: Go to Top_<
- ==== ul item >_top: Another anchor_<
- :>
-))
-
-# Afficher un block code avec le contenu d'un fichier
-# Il doit avoir été configuré dans l'entête
-# -----------------------------------------
-#2 Un block code depuis un fichier
-_code:codetest
-
-# Afficher une image (1 tag par ligne)
-# ------------------------------------
-#2 Les images
-# Placer le logo de l'article
-_image:logo
-
-# les options du marqueur:
-# - c=CLASS < Sinon la classe est celle du domaine
-# - w=WIDTH < longueur (si pas d'unité : défaut "px")
-# - h=HEIGHT < Comme w=
-# - f=Ma légende sous l'image (ajoute )
-# - - Recommandé d'utiliser cette option en dernier
-
-# ! Les images dans cet exemple sont affichées horizontalement
-# Placer "|", ou mettez chaque image dans un paragraphe "((...))"
-# ou définir un style css de type display:block pour les afficher verticalement
-((
- _image:mypic
- _image:mypic c=MYCSS
-))
-
-# Une image avec légende () (jamais dans un paragraphe)
-_image:mypic c=PIC w=60em h=30% f=echolib sur une chaise
-
+(=
+ = Première entrée non ordonnée (ul)
+ == Sous entrée non ordonnée
+ +++ Première sous-sous entrée ordonnée (ol)
+ +++ Seconde sous-sous entrée ordonnée
+ = Seconde entrée non ordonnée
+ = Troisième entrée ...
+ ... non ordonnée
+)=
```
## Output HTML
```
-
-
-
-
-Go to uniq1 anchor
-
-Titre en h2
-
- Un long paragraphe...
-
-
-
- Il faut cliquer sur ce Lien , Réservez ici et télécharger ce fichier
- ou encore faire une CSS pour du beau rendu HTML
-
-
- Un court paragraphe de 1984 pour de vrai faux en gras
- Il faut le souligner et Très Gras
-
- <ol>, <ul>
- {_Afficher un icode brut_}
-
-Block Code
-
-1 # Un commentaire et du code
-2 def hello(world):
-3 world and print(world) or print("NoMore")
-
-Marqueurs de mots
-
- Même si, il est possible d'écrire directement des balises (HTML), Tyto
- propose de les simplifier, en entourant les mots avec des marqueurs. La
- classe CSS du domaine est utilisée pour chaque marqueur.
-
-
-1 *_Très Gras_* > <strong>
-2 +_En Gras_+ > <b>
-3 [_Citer un texte_] > <q>
-4 :_Citer une référence_: > <cite>
-5 ~_Texte barré_~ > <del>
-6 ._Text souligné_. > <u>
-7 /_En italique_/ > <em>
-8 ;_En italique_; > <i>
-9
-10 # Marques multiples, ajouter "&"
-11 *_&._Très gras et souligné_.&_*
-
-
-Citation
-
-
-
-
-
+
+
-
-Here, i am
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+echolib, 28/02/2023 [
Code source ]
-Une liste mixée <ol>, <ul>
+
+Titre 1
-
- numeric ol item 1
-
- numeric ol sub-Item 1
-
- numeric ol sub-sub-item 1
-
-
-
+Un peu de CSS et le site est prêt
+
+Cet article est un test
+
+
+Citation
+
+
+Citation complète dans un paragraphe
+
+
+Code (bloc)
+
+1 # Écrire les marqueurs de mots
+2 # Chaque marqueur à la classe CSS de la configuration
+3 # Astuce : ** + ← + `` + ← + très gras
+4
+5 *`très gras`* => <strong>
+6 +`gras`+ => <b>
+7 /`italique`/ => <em>
+8 ;`italique`; => <i>
+9 _`souligné`_ => <u>
+10 ~`effacé`~ => <del>
+11 [`cité`] => <q> # Contenu
+12 :`cité`: => <cite> # auteur, nom
+13 |`perso`| => <span>
+14
+15 # Code dans un texte
+16 # ! Les marqueurs d'ouverture et de fermeture de code sont sur la MEME LIGNE
+17
+18 {` <li>Une entée de liste</li> `} => <code>
+19
+20 # ! Dans certains cas, il faut ajouter un espace après le 1er marqueur
+21 # et/ou avant le second. Ils seront automatiquement supprimés
+22
+23 *`DOMAIN/articles/ `* # évite /` : marqueur italique ouvert
+
+Une liste
+
+Première entrée non ordonnée (ul)
+
+Sous entrée non ordonnée
+
+Première sous-sous entrée ordonnée (ol)
+Seconde sous-sous entrée ordonnée
+
+Seconde entrée non ordonnée
+Troisième entrée ... ... non ordonnée
+
+
+
-
-Un block code depuis un fichier
-
-
-1 #================================#
-2 # Searching options in arguments #
-3 #--------------------------------#
-4 def get_options():
-5 global dlogs, force, erron
-6
-7 dlogs = force = erron = False
-8 for arg in range(1, len(sys.argv)):
-9 dlogs = sys.argv[arg] in tyto.debug_options
-10 force = sys.argv[arg] in tyto.force_options
-11 erron = sys.argv[arg] in tyto.debug_errors
-12
-13 print("<li>my 'cafe !</li>")
-14
-
-
-Les images
-
-
-
-
-
-echolib sur une chaise
+
+
+
+
+
+
+
+
+
```
diff --git a/debian/control b/debian/control
index ab58014..040bb33 100644
--- a/debian/control
+++ b/debian/control
@@ -1,5 +1,5 @@
Package: tyto
-Version: 1.9.39
+Version: 1.9.50
Section: custom
Priority: optional
Architecture: all
diff --git a/src/usr/bin/tyto b/src/usr/bin/tyto
index 583cb87..23e58bb 100755
--- a/src/usr/bin/tyto
+++ b/src/usr/bin/tyto
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
-# Version: 1.9.39
-# Updated: 2023-11-11 1699742831
+# version: 1.9.50
# Tyto - Littérateur
# Copyright (C) 2023 Cyrille Louarn
@@ -16,102 +15,136 @@
# 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 .
+# along with this program. If not, see ..
#----------------------------------------------------------------------
-# XMPP: echolib > im@echolib.re
+# XMPP: echolib (im@echolib.re)
#
-# Description: Main binary to execute.
-# Import modules and start checking/using arguments
+# Description: Main executable
# File: /usr/bin/tyto
#----------------------------------------------------------------------
-#-------------------------
-# Funny Stats Project
-#-------------------------
-# Project files :
-# Project lines :
-# Project comments :
-# Project functions:
-# Project program :
-#
-# file lines :
-# file comments :
-# file functions:
-# file program :
-#--------------------------
-
import os, sys
-#===============#
-# Error message #
-#---------------#
-def error_message(path):
- print("! Installation error, unused:", path)
- sys.exit(1)
-
-
-#======================================================#
-# A little checker to be sure, all files are installed #
-#------------------------------------------------------#
+#===================================#
+# Check Tyto directoryies and files #
+# Insert directories #
+#-----------------------------------#
def check_install():
- os.path.exists(libs) or error_message(libs)
- os.path.exists(trfs) or error_message(trfs)
+ # Settings
+ error = False
+ lib_tyto = "/var/lib/tyto/%s"
- for f in prog_files:
- f = os.path.join(libs, f + ".py")
- if not os.path.exists(f):
- error_message(f)
+ log_m = "! Tyto installation. Unused"
- # Only default lang files
- for f in lang_files:
- f = os.path.join(trfs, f + ".py")
- if not os.path.exists(f):
- error_message(f)
-
+ # Files trees
+ files = {
+ "program" : (
+ "args",
+ "check",
+ "debug",
+ "domain",
+ "feed",
+ "form",
+ "help",
+ "langs",
+ "modules",
+ "new",
+ "page",
+ "post",
+ "publish",
+ "sitemap",
+ "tools",
+ "wip",
+ ),
+ "translations" : (
+ "logs_fr",
+ "logs_en",
+ "site_fr",
+ "site_en",
+ ),
+ }
+
+ for d in files:
+ tyto_dir = lib_tyto%d
+ if not os.path.exists(tyto_dir):
+ print("%s directory:"%log_m, tyto_dir)
+ error = True
+ continue
+
+ # Insert path
+ sys.path.insert(0, tyto_dir)
+
+ for f in files[d]:
+ tyto_file = os.path.join(tyto_dir, f + ".py")
+ if not os.path.exists(tyto_file):
+ print("%s file:"%llog_m, tyto_file)
+ error = True
+
+ error and sys.exit(1)
-#======#=======================================================================
-# MAIN #
+#=============================================================================#
+# Main #
#======#
if not __name__ == "__main__":
- print("! Error: '%s' not '%s'"%(__name__, "__main__"))
+ print("! Process error: '%s' not '%s'"%(__name__, "__main__"))
sys.exit(1)
-# files list in /program/
-prog_files = {
- "args",
- "check",
- "debug",
- "domain",
- "forms",
- "help",
- "langs",
- "new",
- "post",
- "show",
- "tools",
- "tyto",
- "userset",
- "wip"
- }
-lang_files = {
- "logs_en",
- "logs_fr",
- "website_en",
- "website_fr"
- }
-
-# Set librairies to import app files
-libs = "/var/lib/tyto/program"
-trfs = "/var/lib/tyto/translations"
-
+# Check installed files
check_install()
-sys.path.insert(0, libs)
-sys.path.insert(0, trfs)
-# Manage arguments from command line, start process
-import args
-args.start_process()
+# Load some Tyto libs
+import langs, debug, args, domain
+
+#==========#
+# Language #
+#==========#
+langs.load_logs() # Load logs language
+
+
+#========#
+# Domain #
+#========#
+domain.check_home() # Mainly check current directory
+
+
+#===========#
+# Arguments #
+#===========#
+args.get_arguments() # Get arguments from command line
+
+# First starting logs
+debug.out(200, os.getlogin(), domain.user_dir, False, 0, False)
+debug.out(201, langs.logs_lang, langs.logs_uri, False, 0, False)
+if domain.in_hole:
+ debug.out(4, "$PWD ?", domain.user_dir, True, 2, True)
+
+if args.err_action: # [action] error (only)
+ debug.out(2, "[action]", args.err_action, False, 2, False)
+
+
+#===============#
+# Start process #
+#===============#
+import check, help, new, wip, publish
+
+# From command line [ACTION], do
+do = {
+ "check" : check.manage,
+ "help" : help.manage,
+ "new" : new.manage,
+ "publish" : publish.manage,
+ "wip" : wip.manage,
+ "start" : domain.manage,
+ "stop" : domain.manage,
+
+ }
+
+do[args.action]()
+"""
+try: do[args.action]()
+except KeyError: debug.out(90, args.action, "", True, 2, True)
+"""
diff --git a/src/var/lib/tyto/program/__pycache__/args.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/args.cpython-311.pyc
deleted file mode 100644
index db3b35c..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/args.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/check.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/check.cpython-311.pyc
deleted file mode 100644
index 631844e..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/check.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/debug.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/debug.cpython-311.pyc
deleted file mode 100644
index 3bfa598..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/debug.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/domain.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/domain.cpython-311.pyc
deleted file mode 100644
index d58e1d1..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/domain.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/forms.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/forms.cpython-311.pyc
deleted file mode 100644
index a581213..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/forms.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/help.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/help.cpython-311.pyc
deleted file mode 100644
index ff52e8a..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/help.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/langs.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/langs.cpython-311.pyc
deleted file mode 100644
index ee7fa5b..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/langs.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/logs.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/logs.cpython-311.pyc
deleted file mode 100644
index 4e4dd43..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/logs.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/new.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/new.cpython-311.pyc
deleted file mode 100644
index f94cad6..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/new.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/post.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/post.cpython-311.pyc
deleted file mode 100644
index 4ce594f..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/post.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/show.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/show.cpython-311.pyc
deleted file mode 100644
index 86983c1..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/show.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/sitemaps.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/sitemaps.cpython-311.pyc
deleted file mode 100644
index 6ea26d4..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/sitemaps.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/tools.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/tools.cpython-311.pyc
deleted file mode 100644
index cd6f46a..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/tools.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/tyto.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/tyto.cpython-311.pyc
deleted file mode 100644
index dec9a6c..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/tyto.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/userset.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/userset.cpython-311.pyc
deleted file mode 100644
index 3bba342..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/userset.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/__pycache__/wip.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/wip.cpython-311.pyc
deleted file mode 100644
index 8020c89..0000000
Binary files a/src/var/lib/tyto/program/__pycache__/wip.cpython-311.pyc and /dev/null differ
diff --git a/src/var/lib/tyto/program/args.py b/src/var/lib/tyto/program/args.py
index 01f331b..6d2d6cb 100644
--- a/src/var/lib/tyto/program/args.py
+++ b/src/var/lib/tyto/program/args.py
@@ -14,101 +14,177 @@
# 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 .
+# along with this program. If not, see ..
#----------------------------------------------------------------------
-# XMPP: echolib > im@echolib.re
+# XMPP: echolib (im@echolib.re)
#
# Description: Manage arguments from command line
# File: /var/lib/tyto/program/args.py
#----------------------------------------------------------------------
-
-#-------------------------
-# Funny Stats Project
-#-------------------------
-# file lines :
-# file comments :
-# file functions:
-# file program :
-#--------------------------
-
import sys
-import langs, tyto, debug, help, new, check, userset, show, wip
-#==================#
-# Action Arguments #
-#------------------#
-def get_action():
- global action
+#======================================================#
+# Get action at first position #
+# Set options for other arguments (no position matter) #
+#------------------------------------------------------#
+def get_arguments():
+ global commands, action, err_action, set_module
+
+ commands = {
+ "actions" : {
+ "check" : False,
+ "wip" : False,
+ "publish" : False,
+ "new" : False,
+ "start" : False,
+ "stop" : False,
+ "help" : False,
+ },
+ "targets" : {
+ "*.tyto" : (),
+ "all" : False,
+ "domain" : False,
+ "sitemap" : False,
+ },
+ "modules" : {
+ "modules" : False,
+ "metas" : False,
+ "header" : False,
+ "navbar" : False,
+ "sidebar" : False,
+ "footer" : False,
+ },
+ "options" : {
+ "-v" : False,
+ "-E" : False,
+ },
+ }
+
+ # Arguments from command line
+ # ---------------------------
+ set_module = False
+ for user_arg in range(2, len(sys.argv)):
+ # Register articles
+ if sys.argv[user_arg].endswith(".tyto"):
+ commands["targets"]["*.tyto"] = \
+ commands["targets"]["*.tyto"] + (sys.argv[user_arg],)
+
+ # Register targets
+ for arg in commands["targets"]:
+ if not commands["targets"][arg] \
+ and sys.argv[user_arg] == arg:
+ commands["targets"][arg] = True
+ continue
+
+ # Register modules
+ for arg in commands["modules"]:
+ if not commands["modules"][arg] \
+ and sys.argv[user_arg] == arg:
+ commands["modules"][arg] = True
+ set_module = True
+ continue
+
+ # Register options
+ for arg in commands["options"]:
+ if sys.argv[user_arg] == arg:
+ commands["options"][sys.argv[user_arg]] = True
+ continue
+
+ # Action, the first argument
+ # --------------------------
+ err_action = True
+ try: action = sys.argv[1]
+ except: action = "help" ; err_action = False ; return
+ for arg in commands["actions"]:
+ if action == arg:
+ commands["actions"][arg] = True
+ err_action = False
+ break
+
+ if err_action:
+ err_action = action
+ action = "help"
+ return
+
+
+ """
+ global err_act, action, actions, article, targets, logall, erron, force
+
+ hlp_actions = ("help", "-h", "--help")
+
+ actions = (
+ "check", "wip", "publish",
+ "start", "stop",
+ "new", hlp_actions,
+ )
+ debug_opts = ("--verbose", "-v")
+ erron_opts = ("--errors", "-E")
+ force_opts = ("--force", "-F")
+
+ # Options
+ err_act = article = targets = logall = erron = force = False
+
+ # First argument must be an action
+ # --------------------------------
try: action = sys.argv[1]
except: action = ""
-
-
-#==================#
-# Target arguments #
-#------------------#
-def get_target():
- global target, targets
- try: target = sys.argv[2]
- except: target = ""
-
- targets = False
- if target == "all": targets = True
-
-
-#================================#
-# Searching options in arguments #
-# Done only once #
-#--------------------------------#
-def get_options():
- global dlogs, force, erron, set_options
-
- try: set_options ; return
- except: pass
-
- dlogs = force = erron = False
- for arg in range(1, len(sys.argv)):
- 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
-
-
-#===========#
-# Show logs #
-#-----------#
-def valid_action():
- global action
-
- if not action in tyto.actions:
- debug.out(1, "[action]", action, False, 2, False)
+ if not action in actions or action in hlp_actions:
+ err_act = action
action = "help"
+ return
+
+ # Set other arguments passed
+ # --------------------------
+ global domain, modules, metas, header, navbar, sidebar, footer, set_modules
+ global sitemap
+
+ sitemap = False
+ domain = modules = metas = header = navbar = sidebar = footer = False
+ set_modules = {
+ "modules" : "",
+ "metas" : "",
+ "header" : "",
+ "navbar" : "",
+ "sidebar" : "",
+ "footer" : "",
+ }
+
+ for arg in range(2, len(sys.argv)):
+ # ------
+ # Target
+ # ------
+ # Argument is a .tyto article
+ if not article and sys.argv[arg].endswith(".tyto"):
+ article = sys.argv[arg]
+ continue
+
+ # Other targets
+ # domain
+ if not domain: domain = bool(sys.argv[arg] == "domain")
+ if not sitemap: sitemap = bool(sys.argv[arg] == "sitemap")
+
+ # Modules
+ if not modules:
+ modules = set_modules["modules"] = bool(sys.argv[arg] == "modules")
+ if not metas:
+ metas = set_modules["metas"] = bool(sys.argv[arg] == "metas")
+ if not header:
+ header = set_modules["header"] = bool(sys.argv[arg] == "header")
+ if not navbar:
+ navbar = set_modules["navbar"] = bool(sys.argv[arg] == "navbar")
+ if not sidebar:
+ sidebar = set_modules["sidebar"] = bool(sys.argv[arg] == "sidebar")
+ if not footer:
+ footer = set_modules["footer"] = bool(sys.argv[arg] == "footer")
-#==============#
-# Start action #
-#--------------#
-def start_process():
- # Set Lang logs
- langs.load_logs_lang()
-
- get_options()
- get_action()
- get_target()
- valid_action()
-
- do = {
- "help" : help.show,
- "check" : check.manage,
- "new" : new.manage,
- "set" : userset.manage,
- "start" : userset.manage,
- "stop" : userset.manage,
- "show" : show.manage,
- "wip" : wip.manage,
- }
-
- do[action](action, target)
-
+ # -------
+ # Options
+ # -------
+ if not targets: targets = bool(sys.argv[arg] == "all")
+ if not logall: logall = bool(sys.argv[arg] in debug_opts)
+ if not erron: erron = bool(sys.argv[arg] in erron_opts)
+ if not force: force = bool(sys.argv[arg] in force_opts)
+ """
diff --git a/src/var/lib/tyto/program/check.py b/src/var/lib/tyto/program/check.py
index e8c2740..9ca75f0 100644
--- a/src/var/lib/tyto/program/check.py
+++ b/src/var/lib/tyto/program/check.py
@@ -14,1192 +14,652 @@
# 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 .
+# along with this program. If not, see ..
#----------------------------------------------------------------------
-# XMPP: echolib > im@echolib.re
+# XMPP: echolib (im@echolib.re)
#
-# Description: Mainly to check article, but also domain and more
+# Description: Check article content. Check domain
# File: /var/lib/tyto/program/check.py
#----------------------------------------------------------------------
-#-------------------------
-# Funny Stats Project
-#-------------------------
-# file lines :
-# file comments :
-# file functions:
-# file program :
-#--------------------------
-
-import sys, os, re
-from dateutil.parser import parse
-
-import args, domain, langs, debug, post, tools, tyto, wip
-
-
-#=====================================#
-# Check domain #
-# Load domain configuration file #
-# Update it if needed, and set values #
-# Load website lang #
-# Domain must be activated #
-#-------------------------------------#
-def ready():
- domain.cf_update_values(False)
- domain.ready()
+import os, re, datetime
+import args, post, debug, domain, tools
#===========================================#
-# Manage argument from command line "check" #
-# Domain must be valid to proceed #
-# Create user work domain directories #
+# action "check" #
+# not to check article, but domain, or more #
#-------------------------------------------#
-def manage(action, target):
- # target is "all"
- if args.targets:
- multiple_targets()
- return
-
- # target is not "all"
- ready()
- target.endswith(".tyto") and is_article(target)
- target == "domain" and wrk_domain()
- target in ("wip", "www") and srv_domain(target)
+def manage():
+ if args.commands["targets"]["domain"]:
+ domain.is_ready()
+ with open(domain.cf_uri) as f:
+ print(f.read())
+ debug.out(250, domain.conf["title"], domain.cf_uri, True, 0, False)
-#==========================================#
-# Check some things used by current domain #
-#------------------------------------------#
-def wrk_domain():
- wrk_template_files()
- wip.get_modules("wip")
+#===============================#
+# File is a Tyto format #
+# 1st process, checking #
+# Create strings from separator #
+# Check article header contents #
+#-------------------------------#
+def tyto_format():
+ global out, article, article_header, article_writer, stats
- if post.error != 0:
- sys.exit(post.error)
+ debug.out(210, post.uid, post.uri, False, 0, False)
+
+ post.set_default_vars()
+ post.cf_load()
+ post.cf_read()
+
+ # Multiple targets ("all"): out is False
+ # (out to exit on error at single target)
+ out = not(args.commands["targets"]["all"])
+
+ article_header = article_writer = ""
+ separator = False
+
+ with open(post.uri, "r") as article:
+ article = article.read().rsplit("\n")
+ for lines, line in enumerate(article, 1):
+ # Find separator between header and contents writer
+ if not separator and line.lstrip().startswith(post.separator):
+ separator = True
+
+ if separator:
+ if article_writer: article_writer = "%s\n%s"%(article_writer, line)
+ else: article_writer = line
+ else:
+ if article_header: article_header = "%s\n%s"%(article_header, line)
+ else: article_header = line
+
+ # Separator must be set
+ if not separator:
+ debug.out(30, '"%s"'%post.separator, post.uri, True, 2, out)
+ return False
+
+ # Contents in headers
+ if not article_header:
+ debug.out(31, "!?", post.uri, True, 2, out)
+ return False
+
+ # Contents in article writer
+ if len(article_writer.rsplit("\n")) == 1:
+ debug.out(32, "!?", post.uri, True, 2, out)
+ return False
+
+
+ # Remove useless separator at first line
+ article_writer = \
+ article_writer.replace(article_writer.rsplit("\n")[0], "").rsplit("\n")
+
+ article_header = article_header.rsplit("\n")
+
+ # Set statistics
+ stats = {
+ "file" : {
+ "lines" : lines,
+ "header_lines" : len(article_header),
+ "writer_lines" : len(article_writer),
+ },
+ # format: "..." : {TagName : int}
+ "header" : {},
+ "writer" : {},
+ }
+
+ # Check and set needed header contents (single line tags)
+ if not header_sl_tags(): return False
+
+ # Check for block codes
+ global ln_w
+ ln_w = len(article_header) + 1 # Count article header lines for error logs
+
+ # Check article contents
+ if not block_tags("bcodes"): return False # Protect bcodes contents
+ if not words_tags(): return False # Count/check paired words tags
+ if not icodes(): return False # Protect icodes contents
+ if not header_ml_tags(): return False # Set values for 3 lines tags
+ if not sl_ptags(): return False # Count/Chech paragraphs, divs
+ if not block_tags("bquotes"): return False
+ if not titles(): return False
+ if not block_tags("lists"): return False
+ indep_tags() # Count independant tags
+ if not anchors(): return False # Anchors source
+ if not anchors_links(): return False # Anchors links
+
+ return True
+
+
+#=============================================================================#
+# ARTICLE HEADER #
+#=============================================================================#
+#==============================#
+# Set from article header #
+# - optional marks #
+# - needed tags #
+# Check if all needed tags set #
+#------------------------------#
+def header_sl_tags():
+ global stats
+
+ # Set needed tags
+ for ln, line in enumerate(article_header, 1):
+ # Options_marks (! NOMAP, ! NOTSS, ! TOC, ...)
+ for mark in post.options_marks:
+ if not post.options_marks[mark] \
+ and line.lstrip().startswith(mark):
+ post.options_marks[mark] = True
+ # Needed tags
+ for tag in post.needed_tags:
+ if not post.needed_tags[tag] and \
+ line.lstrip().startswith("%s:"%tag):
+ tag_set = line.rsplit("%s:"%tag)[1].lstrip()
+ if not tag_set:
+ debug.out(33, "%s. '%s: ?'"%(ln, tag), post.uri, True, 2, out)
+ return False
+ # For logo and date, get ln
+ if tag == "logo":
+ logo_ln = ln
+ elif tag == "date":
+ date_ln = ln
+
+ post.needed_tags[tag] = tag_set
+
+ # Article logo (Auto set if not set by user)
+ if not post.needed_tags["logo"]:
+ post.needed_tags["logo"] = \
+ "%stemplate/%s"%(
+ domain.web["www"], domain.cf.get("TEMPLATE_FILENAMES", "logo")
+ )
+ else:
+ global tag_set_l2
+ tag_set_l2 = post.needed_tags["logo"]
+ tag_uri_file("logo", logo_ln)
+ post.needed_tags["logo"] = domain.web["www"][:-1] + tag_set_l2
-#==========================================================#
-# 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
+ # Check if all needed tags are set
+ for tag in post.needed_tags:
+ if not post.needed_tags[tag]:
+ debug.out(33, '"%s: ?"'%tag, post.uri, True, 2, out)
+ return False
+
+ # Date format must be YYY-MM-DD
+ try:
+ datetime.date.fromisoformat(post.needed_tags["date"])
+ except ValueError:
+ debug.out(34, "%s. date: %s ? (YYYY-MM-DD)"%(date_ln, post.needed_tags["date"]), post.uri, True, 2, out)
+ return False
+
+ # Count authors
+ stats["header"]["authors"] = len(post.needed_tags["authors"].rsplit(","))
+
+ return True
+
+
+#==============================================#
+# loop article header and set multi-lines tags #
+#----------------------------------------------#
+def header_ml_tags():
+ global tags_l1
- try: check_tpl_files ; return
- except: pass
+ tags_l1 = ()
+ tag_found = False
+ pass_line = 2 # 3 lines to pass if a tag is found
- for key, uri in domain.cf.items("USER_TEMPLATE_FILES"):
- if not os.path.exists(uri):
- debug.out(5, key, uri, True, 1, False)
+ for ln, line in enumerate(article_header, 1):
+ # When a tag was found, pass 2 configuration lines
+ if pass_line == 0:
+ tag_found = False
+ pass_line = 2
+ elif tag_found:
+ pass_line -= 1
+ continue
+
+ for tag in post.option_tags:
+ if line.lstrip().startswith("%s:"%tag):
+ if not get_ml_tag_l1(tag, ln, line): return False
+ if not get_ml_tag_l2(tag, ln, line): return False
+ if not get_ml_tag_l3(tag, ln, line): return False
+ dict_ml_tag(tag)
+ tag_found = True
+
+ return True
+
+
+#=======================================#
+# Check set line 1 from multi-lines tag #
+#---------------------------------------#
+def get_ml_tag_l1(tag, ln, line):
+ global tag_set_l1, tags_l1, tag_mark
- check_tpl_files = True
+ tag_set_l1 = line.rsplit("%s:"%tag)[1].lstrip()
+ # tag not set or contains tag marker
+ if not tag_set_l1:
+ debug.out(33, '%s. %s: ?'%(ln, tag), post.uri, True, 2, out)
+ return False
+ elif post.marker_tags%"" in tag_set_l1:
+ debug.out(34, "%s. %s: '%s' > '%s'"%(
+ ln, tag, tag_set_l1, post.marker_tags%""
+ ), post.uri, True, 2, out)
+ return False
+
+ # Check if tag_set_l1 is uniq
+ if tags_l1.count(tag_set_l1):
+ debug.out(35, "%s. '%s'"%(ln, tag_set_l1), post.uri, True, 2, out)
+ return False
+ # Is new : add tag_set_l1 to others in tuple
+ tags_l1 = tags_l1 + (tag_set_l1,)
+
+ # Set writer mark from tag_set_l1 (default "::tag_set_l1")
+ tag_mark = post.marker_tags%tag_set_l1
+ # Count if tag mar is found in article writer
+ has_mark = sum(tag_mark in s for s in article_writer)
+ if has_mark == 0:
+ debug.out(36, '%s: "%s"'%(tag, tag_mark), post.uri, True, 2, out)
+ return False
+
+ # Add stat
+ try: stats["writer"]["%ss"%tag] += has_mark
+ except: stats["writer"]["%ss"%tag] = has_mark
+
+ return True
+
+
+#=======================================#
+# Check set line 2 from multi-lines tag #
+#---------------------------------------#
+def get_ml_tag_l2(tag, ln, line):
+ global tag_set_l2
+
+ tag_set_l2 = article_header[ln].lstrip()
+
+ # Tag not set
+ if not tag_set_l2:
+ debug.out(33, '%s. %s: ? (L2)'%(ln + 1, tag), post.uri, True, 2, out)
+ return False
+
+ # Line starts with a tag name
+ for item in post.option_tags:
+ if tag_set_l2.startswith("%s:"%item):
+ debug.out(34, "%s. %s: '%s'"%(
+ ln + 1, tag, tag_set_l2
+ ), post.uri, True, 2, out)
+ return False
+
+ # Check uri file
+ if tag in post.nofile_tags:
+ return True
+
+ # Check uri file set
+ if not tag_uri_file(tag, ln + 1):
+ return False
+
+ return True
+
+
+#=============================================#
+# Get full file uri #
+# check if file exists #
+# Set srv_uri and web_uri file #
+# Put in dicts (post.option_tags, post.datas) #
+#---------------------------------------------#
+def tag_uri_file(tag, ln):
+ global tag_set_l2 # will replace current value with web_uri
+
+ mark_uri = tag_set_l2[:1]
+
+ # URI file targets generic directories
+ if mark_uri == "@":
+ real_uri = tag_set_l2[1:]
+ srv_uri = "files/" + real_uri
+ web_uri = "/" + srv_uri
+ src_dir = domain.wrk_dirs["files"]
+ if tag in ("image", "logo"):
+ src_dir = domain.wrk_dirs["images"]
+ srv_uri = "images/" + real_uri
+ web_uri = "/" + srv_uri
+
+ # URI file targets root articles/ directory
+ elif mark_uri == "/":
+ real_uri = tag_set_l2[1:]
+ srv_uri = real_uri
+ web_uri = tag_set_l2
+ src_dir = domain.wrk_dirs["articles"]
+
+ # URI file targets from current article directory
+ else:
+ real_uri = tag_set_l2
+ src_dir = domain.wrk_dirs["articles"] + post.datas["dir_target"]
+ srv_uri = post.datas["dir_target"] + real_uri
+ web_uri = "/" + srv_uri
+
+ # CHeck if file set for this tag exists
+ src_file = src_dir + real_uri
+ if not os.path.exists(src_file):
+ debug.out(11, "%s. %s: '%s'"%(
+ ln, tag, tag_set_l2
+ ), src_file, True, 2, out)
+ return False
+
+ global f_nbr
+ try: f_nbr += 1
+ except: f_nbr = 1
+ post.datas["files"][f_nbr] = (src_file, srv_uri)
+ tag_set_l2 = web_uri
+
+ return True
+
+
+#=======================================#
+# Check set line 3 from multi-lines tag #
+#---------------------------------------#
+def get_ml_tag_l3(tag, ln, line):
+ global tag_set_l3
+
+ tag_set_l3 = article_header[ln + 1].lstrip()
+ if not tag_set_l3:
+ debug.out(33, '%s. %s: ? (L3)'%(ln + 2, tag), post.uri, True, 2, out)
+ return False
+
+ for item in post.option_tags:
+ if tag_set_l3.startswith("%s:"%item):
+ debug.out(34, "%s. %s: '%s'"%(
+ ln + 1, tag, tag_set_l2
+ ), post.uri, True, 2, out)
+ return False
+
+ return True
+
#====================================#
-# Check wip and www dirs and files #
-# Done only once #
-# - in case of "all" or direct "wip" #
+# Add multi-lines tag values to dict #
#------------------------------------#
-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) #
-# Also used with multiple (loop) #
-#--------------------------------#
-def is_article(target):
- if not valid(target) or post.error != 0:
- if targets: return
- else: sys.exit(post.error)
-
- # When all is OK
- # Will create post database, but now, show some values
- """
- print("> check: Final texts string...")
- print('\n'.join(texts))
- """
-
- # Write to post database
- cf_update_values("after")
-
-
-#===========================================#
-# Check full article contents (head + text) #
-# In error case, exit or return if targetS #
-#-------------------------------------------#
-def valid(target):
- global targets
- targets = args.targets
-
- # Target is a tyto article format
- if not post.is_article(target):
- return False
-
- if not post.do_chk:
- post.error = debug.out(210, post.chk_date, post.uri, True, 0, False)
- return False
-
- # Reset: must be done only when multiple targets
- if targets:
- post.title = ("title:", False)
- post.about = ("about:", False)
- post.date = ("date:", False)
- post.tags = ("tags:", False)
- post.author = ("author:", False)
- post.logo = ("logo:", False) # optional
-
- post.stats_bcodes = 0
- post.stats_quotes = 0
- post.stats_parags = 0
- post.stats_lists = 0
- post.stats_divs = 0
-
- post.stats_links = 0
- post.stats_images = 0
- post.stats_files = 0
- post.stats_raws = 0
- post.stats_codes = 0
- post.stats_abbrs = 0
-
- post.stats_text_links = 0
- post.stats_text_files = 0
- post.stats_text_images = 0
- post.stats_text_abbrs = 0
- post.stats_text_codes = 0
- post.stats_text_raws = 0
- post.error = 0
-
- # Reset post database (Old values are prepared)
- tools.create_file(post.cf_uri, post.ini_template)
- post.cf_load()
-
- # Add statistics to post database
- cf_update_values("before")
-
- global css
- css = domain.css
-
- global headers, texts
- headers = post.head_contents.rsplit("\n")
- texts = post.text_contents.rsplit("\n")
-
- # ============
- # Text article
- # ============
- # Process bcodes and icodes first to protect their contents
- post.error == 0 and sl_ptags(post.ptags[0]) \
- or tools.exit(targets, post.error)
- post.error == 0 and icodes() \
- or tools.exit(targets, post.error)
-
- # =============
- # 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
- post.error == 0 and ml_tags() \
- or tools.exit(targets, post.error)
-
- # ============
- # Text article
- # ============
- # Single tags
- post.error == 0 and sl_stags() \
- or tools.exit(targets, post.error)
-
- # Anchors links
- post.error == 0 and anchors_links() \
- or tools.exit(targets, post.error)
-
- # Words Tags (Strong, bold...)
- post.error == 0 and words_tags() \
- or tools.exit(targets, post.error)
-
- # Quotes
- post.error == 0 and sl_ptags(post.ptags[1]) \
- or tools.exit(targets, post.error)
-
- # Lists
- post.error == 0 and sl_ptags(post.ptags[3]) \
- or tools.exit(targets, post.error)
-
- # Paragraphs
- post.error == 0 and sl_ptags(post.ptags[2]) \
- or tools.exit(targets, post.error)
-
- # divs
- post.error == 0 and sl_ptags(post.ptags[4]) \
- or tools.exit(targets, post.error)
-
- post.error > 0 and tools.exit(targets, post.error)
-
- return True
-
-
-#===========================================#
-# Create a loop to get all .tyto articles #
-#-------------------------------------------#
-def multiple_targets():
- ready()
- post.find_tyto_article()
-
-
-#=====================#
-# check head contents #========================================================
-#=====================#
-#======================#
-# One Line needed tags #
-#----------------------#
-def ol_tags():
- global sitemap, src_uri, stats_tyto_head_coms
- global stats_total_files
-
- stats_total_files = 0
- post.cf_set("HEADERS", "sitemap", "True")
- stats_tyto_head_coms = 0
-
- for ln, line in enumerate(headers, 1):
-
- # Optional one line markers
- if line.startswith("#"):
- stats_tyto_head_coms += 1
- post.cf_set("STATS_HEADERS", "tyto_coms", str(stats_tyto_head_coms))
-
- elif line.startswith(post.nositemap):
- post.cf_set("HEADERS", "sitemap", "False")
-
- elif line.startswith(post.logo[0]):
- if not post.logo[1]:
- post.logo = (post.logo[0], ol_tag_value(line, False))
- logo_ln = ln
- if is_value2_file_exists(logo_ln, "logo:", post.logo[1]):
- src_uri = "%s%s"%(domain.www_url, src_uri)
- else:
- return False
-
- # One Line tags (Must be set)
- # ===========================
- elif not post.title[1] and line.startswith(post.title[0]):
- post.title = (post.title[0], ol_tag_value(line, False))
- if not is_ol_tag(post.title[0], post.title[1]):
- return False
- post.cf_set("HEADERS", "title", post.title[1])
-
- elif not post.about[1] and line.startswith(post.about[0]):
- post.about = (post.about[0], ol_tag_value(line, False))
- if not is_ol_tag(post.about[0], post.about[1]):
- return False
- post.cf_set("HEADERS", "about", post.about[1])
-
- elif not post.date[1] and line.startswith(post.date[0]):
- post.date = (post.date[0], ol_tag_value(line, False))
- if not is_ol_tag(post.date[0], post.date[1]):
- return False
- elif not is_valid_date(post.date[1]):
- return False
- post.date = ("date:", tools.local_date(post.date[1]))
- post.cf_set("HEADERS", "date", post.date[1])
-
- elif not post.author[1] and line.startswith(post.author[0]):
- post.author = (post.author[0], ol_tag_value(line, True))
- if not is_ol_tag(post.author[0], post.author[1]):
- return False
- post.cf_set("HEADERS", "authors", post.author[1])
-
- elif not post.tags[1] and line.startswith(post.tags[0]):
- post.tags = (post.tags[0], ol_tag_value(line, True))
- if not is_ol_tag(post.tags[0], post.tags[1]):
- return False
- post.cf_set("HEADERS", "tags", post.tags[1])
-
- # Default domain logo for this post
- if not post.logo[1]:
- src_uri = "%stemplate/%s"%(domain.www_url, domain.logo)
- post.logo = (post.logo[0], src_uri)
-
- post.cf_set("HEADERS", "logo", src_uri)
-
- return True
-
-
-#===========================================#
-# Return value from one line after "[tag]:" #
-# tags, author are comma separated #
-# set new value, removing spaces (strip) #
-#-------------------------------------------#
-def ol_tag_value(line, commas):
- value = line.rsplit(":")[1].lstrip()
-
- # reformat comma separated items, removing first spaces
- if commas:
- tuple_values = value.rsplit(",")
- value = ""
- for i, item in enumerate(tuple_values):
- value = value + item.strip()
- if i != len(tuple_values) - 1:
- value = value + ","
-
- return value
-
-
-#===========================#
-# Check if tag value is set #
-# Return True/False #
-#---------------------------#
-def is_ol_tag(tag, value):
- if not value:
- post.error = debug.out(51, "%s ?"%tag, post.uri, True, 2, False)
- return False
-
- return True
-
-
-#======================================#
-# Check if date id valid #
-# Set date of check (YYYY-MM-DD H:M:S) #
-# Return True/False #
-#--------------------------------------#
-def is_valid_date(date):
- global chk_date
-
+def dict_ml_tag(tag):
try:
- parse(date)
- chk_date = tools.nowdate()
- post.cf_set("CHECK", "date", chk_date)
- return True
+ stats["header"]["%ss"%tag] += 1
+ nbr = stats["header"]["%ss"%tag]
except:
- post.error = debug.out(50, "%s"%date, post.uri, True, 2, False)
+ nbr = stats["header"]["%ss"%tag] = 1
+
+
+ post.option_tags[tag][nbr] = \
+ (len(tag_set_l1), tag_mark, tag_set_l1, tag_set_l2, tag_set_l3)
+
+
+#=============================================================================#
+# ARTICLE WRITER #
+#=============================================================================#
+#======================================================#
+# Check indented first marks for bcode, quotes, lists #
+# Put block contents in post.block_tags[tag]["source"] #
+# Replace bcodes in article writer to protect contents #
+#------------------------------------------------------#
+def block_tags(tag):
+ global article_writer
+
+ mark_o = post.block_tags[tag]["marks"][0]
+ mark_c = post.block_tags[tag]["marks"][1]
+ tag_i = -1
+ tag_c = False
+ block_source = ""
+
+ for ln, line in enumerate(article_writer, ln_w):
+ # bcode not yet opened, but begin here
+ if tag_i == -1 and \
+ line.lstrip().startswith(mark_o):
+ tag_i = line.index(mark_o[0])
+ mark_ln = ln
+
+ # bcode was opened and mark closed here
+ elif tag_i != -1 and \
+ line.lstrip().startswith(mark_c) and \
+ line.index(mark_c[0]) == tag_i:
+ tag_c = True
+
+ # tag is open
+ if tag_i != -1:
+ # replace line in article for bcodes only
+ if tag == "bcodes":
+ article_writer[ln - stats["file"]["header_lines"] - 1] = " "
+
+ if not block_source: block_source = line
+ else: block_source = "%s\n%s"%(block_source, line)
+
+ # bcode is closed here
+ if tag_c:
+ # Create or add to stats
+ try: stats["writer"][tag] += 1
+ except: stats["writer"][tag] = 1
+ nbr = stats["writer"][tag]
+
+ # convert html signe, and convert bcode to base64
+ bcode_H = tools.get_HID(block_source, False)
+
+ # Put bcode in dict with nbr bcode
+ post.block_tags[tag]["sources"][nbr] = (block_source, bcode_H)
+
+ # Replace last line with close mark
+ if tag == "bcodes":
+ article_writer[ln - stats["file"]["header_lines"] - 1] = bcode_H
+
+ # Reset all for next block
+ tag_i = -1
+ tag_c = False
+ block_source = ""
+
+ # bcode wan NOT closed
+ if tag_i != -1 and not tag_c:
+ debug.out(37, "%s. %s: '%s' ?"%(
+ mark_ln, tag, mark_c
+ ), post.uri, True, 2, out)
return False
+ return True
+
#============================#
-# multiple and optional Tags #
-# Written using 3 lines #
-# Tags are stric start line #
+# Check and count words tags #
+# incliding icodes #
#----------------------------#
-def ml_tags():
- c = 0 # Continue for next x lines, as tags are 3 lines values
-
- for ln, line in enumerate(headers):
- if c != 0:
- c -= 1
- continue
+def words_tags():
+ for tag in post.words_tags:
+ opened = closed = 0
+ for line in article_writer:
+ if post.words_tags[tag][0] in line:
+ tag_o = line.count(post.words_tags[tag][0])
+ try: stats["writer"][tag] += tag_o
+ except: stats["writer"][tag] = tag_o
+ opened = stats["writer"][tag]
+ if post.words_tags[tag][1] in line:
+ closed += line.count(post.words_tags[tag][1])
- if line.startswith(post.ml_tags):
- tag_name = line.rsplit(":")[0]
- tag = tag_name + ":"
-
- post.ml_tags_stats[tag] = post.ml_tags_stats[tag] + 1
-
- if not ml_tag_values(ln, tag, post.ml_tags_stats[tag]):
- return False
-
- c = 2
- post.cf_set("STATS_HEADERS",
- "%ss"%tag_name,
- str(post.ml_tags_stats[tag])
- )
- continue
+ if opened != closed:
+ debug.out(33, "%s. %s '%s', %s '%s'"%(
+ tag,
+ opened, post.words_tags[tag][0],
+ closed, post.words_tags[tag][1]
+ ), post.uri, True, 2, out)
+ return False
return True
-#========================================#
-# Get tag 3 lines values #
-# Check if 2nd, 3rd lines starts with: #
-# - tag, comment or are empty #
-# Create var and val for post database #
-# Return True/False (if no value) #
-#----------------------------------------#
-def ml_tag_values(ln, tag, stats):
- global value1, value2
+#===========================================================#
+# ICODES (Secure raw contents) #
+# Replace in article writer each inline-code with their HID #
+# Put stats and datas in dicts #
+#-----------------------------------------------------------#
+def icodes():
+ global article_writer
+
+ try: stats["writer"]["icodes"]
+ except: return True
- # Get 3 lines values
- value1 = headers[ln].rsplit(":")[1].lstrip()
- value2 = headers[ln+1].lstrip()
- value3 = headers[ln+2].lstrip()
+ total = 0
+ for ln, line in enumerate(article_writer, ln_w):
+ if post.words_tags["icodes"][0] in str(line) and \
+ post.words_tags["icodes"][1] in str(line):
+ icodes = re.findall(r'%s(.*?)%s'%(
+ post.words_tags["icodes"][0],
+ post.words_tags["icodes"][1]
+ ), line)
+
+ for nbr, icode in enumerate(icodes, 1):
+ total += 1
+ # Put in dict
+ icode_H = tools.get_HID(icode, False)
+ post.icodes["sources"][total] = (icode, icode_H)
+
+ # Replace line in wrticle_writer
+ line = line.replace(icode, icode_H)
+ article_writer[ln - stats["file"]["header_lines"] - 1] = line
- # Check values (not empty or begins with a tag)
- # value1
- # ------
- if not value1:
- post.error = \
- debug.out(51, "%s) %s 1/3"%(ln+1, tag), post.uri, True, 2, False)
- return False
-
- # value1 must not starts or contains:o
- elif "_" in value1:
- post.error = \
- debug.out(56, '%s) "_" : "%s"'%(ln+1, value1), post.uri, True, 2, False)
- return False
-
- # Specific for image: logo name is reserved
- elif tag == post.ml_tags[1] and value1 == "logo":
- post.error = debug.out(56, "%s) 'logo'"%(ln+1), post.uri, True, 2, False)
- return False
-
- # value2
- # ------
- if not value2 or value2.startswith(post.ml_tags):
- post.error = \
- debug.out(51, "%s) %s 2/3"%(ln+2, tag), post.uri, True, 2, False)
- return False
-
- # value3
- # ------
- if not value3 or value3.startswith(post.ml_tags):
- post.error = \
- debug.out(51, "%s) %s 3/3"%(ln+3, tag), post.uri, True, 2, False)
- return False
-
- # No error with values
- # Convert value1 in header with tyto_value1 in text
- tyto_value = post.ml_tags_marks[tag] + value1
-
- # CHeck if value is in text and to stats or return error
- if post.text_contents.find(tyto_value) == -1:
- post_error = debug.out(51, tyto_value, post.uri, True, 2, False)
- return False
-
- # Check value2 link for some tags (file, image...)
- if tag in post.value2s_uri \
- and not value2.startswith(post.value2s_ext_uris) \
- and not is_value2_file_exists(ln+2, tag, value2):
- return False
+ return True
- #-----------------------------------------------#
- # Convert values to HTML (put in post database) #
- #-----------------------------------------------#
- # link:
- if tag == post.ml_tags[0]:
- section = "LINKS"
- post.stats_text_links += post.text_contents.count(tyto_value)
- post.cf_set("STATS_TEXTS", "links", str(post.stats_text_links))
- html_value = tyto.a_link%(
- value2, "%s link"%css, value3, value1
- )
-
- # file:
- elif tag == post.ml_tags[2]:
- section = "FILES"
- post.stats_text_files += post.text_contents.count(tyto_value)
- post.cf_set("STATS_TEXTS", "files", str(post.stats_text_files))
- html_value = tyto.a_link%(
- value2, "%s file"%css, value3, value1
- )
-
- # image:
- elif tag == post.ml_tags[1]:
- section = "IMAGES"
- post.stats_text_images += post.text_contents.count(tyto_value)
- post.cf_set("STATS_TEXTS", "images", str(post.stats_text_images))
- html_value = tyto.image_link%(
- value2, "%%s image", value3,
- "%%s", value2, "%%s", value3, value3, "%%s", "%%s"
- )
-
- # raw: (content file converted to base64)
- elif tag == post.ml_tags[3]:
- section = "RAWS"
- post.stats_text_raws += post.text_contents.count(tyto_value)
- post.cf_set("STATS_TEXTS", "raws", str(post.stats_text_raws))
- html_value = ""%value3
- with open(value2_uri, "r") as f:
- html_value = "%s\n%s"%(html_value, f.read())
-
- html_value = tools.b64_convert("encode", html_value)
-
- # code: (content file converted to HTML + base64)
- elif tag == post.ml_tags[4]:
- section = "CODES"
- post.stats_text_codes += post.text_contents.count(tyto_value)
- post.cf_set("STATS_TEXTS", "codes", str(post.stats_text_codes))
- htmlbcode = ""%value3
- with open(value2_uri, "r") as f:
- for ln, line in enumerate(f.read().rsplit("\n"), 1):
- line = tools.convert_html_signs(line)
- line = tyto.code_line%(ln, line)
- htmlbcode = "%s\n%s"%(htmlbcode, line)
+#===============================#
+# Check start-lines paired tags #
+#-------------------------------#
+def sl_ptags():
+ # Do divs, paragraphs... tags count
+ for tag in post.sl_ptags:
+ tot_o = tot_c = 0
+ for ln, line in enumerate(article_writer, ln_w):
+ # Simple count of opened and closed tags
+ if line.lstrip().startswith(post.sl_ptags[tag][0]): tot_o += 1
+ elif line.lstrip().startswith(post.sl_ptags[tag][1]): tot_c += 1
+
+ if tot_o != tot_c:
+ debug.out(38, '%s: "%s"=%s, "%s"=%s'%(
+ tag,
+ post.sl_ptags[tag][0], tot_o,
+ post.sl_ptags[tag][1], tot_c,
+ ), post.uri, True, 2, out)
+ return False
+
+ stats["writer"][tag] = tot_o
- footer_code = '\n'
- html_value = tyto.code_bcode%(css, htmlbcode, footer_code)
- html_value = tools.b64_convert("encode", html_value)
-
- # abbr:
- elif tag == post.ml_tags[5]:
- section = "ABBRS"
- post.stats_text_abbrs += post.text_contents.count(tyto_value)
- post.cf_set("STATS_TEXTS", "abbrs", str(post.stats_text_abbrs))
- html_value = '%s '%(
- css, value2, value3
- )
-
- # Set in post database, source and HTML content
- post.cf_set(section, "%s_%s"%(tag.replace(":", ""), stats), tyto_value)
- post.cf_set(section, "html_%s"%stats, html_value)
-
return True
-
-
-#================================#
-# Check value2 uri for some tags #
-# uri starts with: #
-# - @... for generic articles/ #
-# - /... for root work directory #
-# - ... for post directory #
-#--------------------------------#
-def is_value2_file_exists(ln, tag, val2):
- global value2, src_uri, value2_uri, stats_total_files
-
- # uri "@..." means generic folders
- if val2[0].startswith("@"):
- if val2[1] == "/": val2 = val2[2:]
- else: val2 = val2[1:]
-
- #Set directory for files
- value2_uri = os.path.join(domain.wrk_files + val2)
- value2 = src_uri = os.path.join("/files", val2)
-
- # Set directory for images in /images
- if tag == post.ml_tags[1] or tag == post.logo[0]: # image:
- value2_uri = os.path.join(domain.wrk_images, val2)
- value2 = src_uri = os.path.join("/images", val2)
-
- # uri "/..." means from wrk root folder
- elif val2[0].startswith("/"):
- val2 = val2[1:]
- value2_uri = os.path.join(domain.wrk_articles, val2)
- src_uri = val2
-
- # uri "..." means from legacy post folder
- else:
- value2_uri = os.path.dirname(post.uri) + "/" + val2
- value2 = "./" + val2
- src_uri = value2_uri.rsplit("articles/")[1]
-
- # Check if file exists
- if not os.path.exists(value2_uri):
- post.error = \
- debug.out(5, "%s) %s"%(ln, tag), value2_uri, True, 2, False)
- return False
-
- # Add file to [SOURCE_FILES] post database
- stats_total_files += 1
- post.cf_set("SOURCE_FILES", "file_%s"%stats_total_files, value2_uri)
- post.cf_set("STATS_FILE", "files", str(stats_total_files))
-
- return True
-
-
-#=====================#
-# check text contents #========================================================
-#=====================#
-#=========================================#
-# start line paired tags #
-# Generic check for all paired markers #
-# Check if opened and closed tags match #
-# Count markers for stats #
-# bcodes: remove lines from texts #
-# Convert content between markers to html #
-# (except for paragraphs) #
-# convert html content to base64 #
-# create sections, keys values to post DB #
-# Return True/False #
-#-----------------------------------------#
-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,
- "lists" : wip.list,
- }
-
- index0 = index1 = -1
-
- for ln, line in enumerate(texts, post.head_lines + 1):
- # Marker is opened
- if index0 >= 0 :
- content = "%s\n%s"%(content, line)
- if markers[2] == "bcodes":
- if index1 != index0:
- texts[ln - 1 - post.head_lines] = ""
-
- # Opened mark
- if line.lstrip().startswith(markers[0]):
- # Mark was opened yet
- if index0 >= 0:
- # at the same position
- if line.index(markers[0][0]) == index0:
- post.error = \
- debug.out(53, '%s: %s...%s) %s'%(
- markers[2], tag_ln, ln, markers[1]
- ), post.uri, True, 2, False)
- return False
- continue
- csstest = tools.get_css(line, markers[0], ln)
- if post.error > 0:
- return
-
- index0 = line.index(markers[0][0])
- tag_ln = ln
- content = line
- if markers[2] == "bcodes":
- texts[ln - 1 - post.head_lines] = ""
-
- # Closed mark
- if line.lstrip().startswith(markers[1]):
- # But not opened
- if index0 < 0:
- post.error = \
- debug.out(53, '%s) %s: %s...'%(
- ln, markers[2], markers[0]
- ), post.uri, True, 2, False)
- return False
-
- index1 = line.index(markers[1][0])
- # at same position as opened
- if index1 == index0:
- index0 = index1 = -1
- tag_ln = ""
- post.ptags_stats[markers[2]] += 1
- post.cf_set("STATS_TEXTS",
- markers[2],
- str(post.ptags_stats[markers[2]])
- )
-
- # paragraphs don't need html wip yet
- if markers[2] in ("parags", "divs"):
- continue
-
- elif markers[2] == "bcodes":
- texts[ln - 1 - post.head_lines] = \
- "%s_%s"%(markers[2][:-1], post.ptags_stats[markers[2]])
-
- # Set keys, values to post database
- post.cf_set(
- markers[2].upper(),
- "%s_%s"%(markers[2][:-1], post.ptags_stats[markers[2]]),
- tools.b64_convert("encode", content)
- )
- post.cf_set(
- markers[2].upper(),
- "html_%s"%post.ptags_stats[markers[2]],
- tools.b64_convert("encode",
- convert[markers[2]](content, ln)
- )
- )
-
- # bcode not opened, but closed tag found
- elif index0 < 0:
- tag_ln = ln
-
- # Check if markers match
- # ----------------------
- if index1 >= 0 and index0 < 0:
- post.error = \
- debug.out(53, '%s) %s: %s...'%(
- tag_ln, markers[2], markers[0]
- ), post.uri, True,2, False)
- return False
-
- if index0 >= 0 and index1 < 0:
- post.error = \
- debug.out(53, '%s) %s: ...%s'%(
- tag_ln, markers[2], markers[1]
- ), post.uri, True,2, False)
- return False
-
- if index0 != index1:
- post.error = \
- debug.out(53, '%s) %s: %s...%s'%(
- tag_ln, markers[2], markers[0], markers[1]
- ), post.uri, True,2, False)
- return False
-
- return True
-
#==========================================#
-# icodes (SAME LINE) #
-# Check if opened and closed markers match #
-# Convert double marks, then single markes #
-# replace icodes with "" in texts article #
-# Add source text and html converted to DB #
+# For stats: count hr, br, anchors (sourc) #
#------------------------------------------#
-def icodes():
- global texts
-
- debug.out(215, "check. icodes", post.cf_uri, False, 0, False)
-
- stats_text_icodes = 0
- markers = post.words_markers
-
- for ln, line in enumerate(texts, post.head_lines + 1):
- # Search for opened, closed markers
- # markers cannot be at same position on line
- m0 = line.find(markers[1][0])
- m1 = line.find(markers[1][1])
- if m0 == m1:
- continue
-
- # Simple 3 cases errors
- # ---------------------
- # First marker is a closed one
- if m1 < m0:
- post.error = \
- debug.out(53, '%s) %s..."%s"'%(
- ln, markers[1][1], markers[1][0]
- ), post.uri, True,2, False)
- return False
-
- # First marker but unused closed one
- if m0 >= 0 and m1 == -1:
- post.error = \
- debug.out(53, '%s) ...%s'%(
- ln, markers[1][1]
- ), post.uri, True,2, False)
- return False
-
- # Last marker but unused opened one
- elif m1 >= 0 and m0 == -1:
- post.error = \
- debug.out(53, '%s) %s...'%(
- ln, markers[1][0]
- ), post.uri, True,2, False)
- return False
-
- if markers[0][0] in line:
- # Double mark first
- line = line.replace(markers[0][0], markers[0][4])
- line = line.replace(markers[0][1], markers[0][5])
- icodes = re.findall('%s(.*?)%s'%(markers[0][4], markers[0][5]), line)
-
- for icode in icodes:
- stats_text_icodes += 1
- icleg = markers[0][0] + icode + markers[0][1]
- icnew = markers[0][4] + \
- tools.convert_html_signs(icode) + \
- markers[0][5]
- icrep = markers[0][4] + \
- icode + \
- markers[0][5]
- line = line.replace(icrep, "icode_%s"%stats_text_icodes)
-
- # Set HTML [ICODES] to post database
- html_val = icnew.replace(markers[0][4], markers[0][2]%css)
- html_val = html_val.replace(markers[0][5], markers[0][3])
- html_val = tools.b64_convert("encode", html_val)
- post.cf_set(
- "ICODES",
- "icode_%s"%stats_text_icodes,
- icleg
- )
- post.cf_set(
- "ICODES",
- "html_%s"%stats_text_icodes,
- html_val
- )
-
- # Single mark
- line = line.replace(markers[1][0], markers[1][4])
- line = line.replace(markers[1][1], markers[1][5])
- icodes = re.findall('%s(.*?)%s'%(markers[1][4], markers[1][5]), line)
-
- for icode in icodes:
- stats_text_icodes += 1
- icleg = markers[1][0] + icode + markers[1][1]
- icnew = markers[1][4] + \
- tools.convert_html_signs(icode) + \
- markers[1][5]
- icrep = markers[1][4] + \
- icode + \
- markers[1][5]
- line = line.replace(icrep, "icode_%s"%stats_text_icodes)
-
- # Set HTML [ICODES] to post database
- html_val = icnew.replace(markers[1][4], markers[1][2]%css)
- html_val = html_val.replace(markers[1][5], markers[1][3])
- html_val = tools.b64_convert("encode", html_val)
- post.cf_set(
- "ICODES",
- "icode_%s"%stats_text_icodes,
- icleg
- )
- post.cf_set(
- "ICODES",
- "html_%s"%stats_text_icodes,
- html_val
- )
-
- texts[ln - 1 - post.head_lines] = line
-
- post.cf_set("STATS_TEXTS", "icodes", str(stats_text_icodes))
-
- return True
+def indep_tags():
+ for tag in post.indep_tags:
+ for ln, line in enumerate(article_writer, ln_w):
+ if line.lstrip().startswith(post.indep_tags[tag]):
+ try: stats["writer"][tag] += 1
+ except: stats["writer"][tag] = 1
-#============================#
-# start line single tags #
-# Check optional title tags #
-# Count tyto + html comments #
-# Add stat for _image:logo #
-# Return True/False #
-#----------------------------#
-def sl_stags():
- global anchors_ids, stats_tyto_text_coms
-
- debug.out(215, "check. Contents", post.cf_uri, False, 0, False)
+
+#=================================#
+# Check titles #
+# - put them in tuple post.titles #
+# - Count them #
+#---------------------------------#
+def titles():
+ global article_writer, anchors_ids
anchors_ids = () # Uniq anchors IDs
- stats_tyto_text_coms = stats_html_coms = 0
- stats_text_anc_ids = 0
- stats_titles = 0
- for ln, line in enumerate(texts, post.head_lines + 1):
- linels = line.lstrip()
+ for ln, line in enumerate(article_writer, ln_w):
+ line = line.lstrip()
+
+ # User needs Table of content
+ if not post.options_marks["! TOC"] \
+ and line.startswith("! TOC"):
+ post.options_marks["! TOC"] = True
- # Tyto Titles
- if linels.startswith(post.tyto_titles):
- if not linels[3:]:
- post.error = \
- debug.out(52, "%s) %s ?"%(ln, line), post.uri, True, 2, False)
+ # Add title
+ elif line.startswith(post.title_marks):
+ mark = str(line[0] + line[1])
+ if line.rsplit(mark)[1]:
+ post.titles = post.titles + (line,)
+ try: stats["writer"]["titles"] += 1
+ except: stats["writer"]["titles"] = 1
+ anchors_ids = anchors_ids + ("toc_%s"%stats["writer"]["titles"],)
+ continue
+ else:
+ debug.out(33, "%s. '%s ?'"%(ln, mark), post.uri, True, 2, out)
return False
-
- # 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)
- return False
-
- stats_titles += 1
- post.cf_set("STATS_TEXTS", "titles", str(stats_titles))
-
- # Create html value for this title in database
- post.cf_set(
- "TITLES",
- "title_%s"%stats_titles,
- line
- )
- post.cf_set(
- "TITLES",
- "html_%s"%stats_titles,
- post.html_titles[linels[0:2]]%(css, line[3:])
- )
-
- # Count Tyto Comments
- elif line.lstrip().startswith("#"):
- stats_tyto_text_coms += 1
- post.cf_set("STATS_TEXTS", "tyto_coms", str(stats_tyto_text_coms))
-
-
- # Count HTML comments
- elif line.lstrip().startswith(post.text_comments):
- stats_html_coms += 1
- post.cf_set("STATS_TEXTS", "html_coms", str(stats_html_coms))
-
- # Convert tyto commented marker to HTML
- if line.lstrip().startswith(post.text_comments[0]):
- real_com = line.lstrip()[3:]
- post.cf_set(
- "COMMENTS",
- "comment_%s"%stats_html_coms,
- line.lstrip()
- )
- post.cf_set(
- "COMMENTS",
- "html_%s"%stats_html_coms,
- ''%real_com
- )
-
-
- # Add stat + html for [IMAGES] when user wants to show logo in post
- elif line.lstrip().startswith("_image:logo"):
- post.stats_text_images += 1
- post.cf_set(
- "IMAGES",
- "image_%s"%(post.ml_tags_stats["image:"] + 1),
- "_image:logo"
- )
- post.cf_set(
- "IMAGES",
- "html_%s"%(post.ml_tags_stats["image:"] + 1),
- tyto.image_link%(
- post.logo[1], "%%s image", post.title[1],
- "%%s", post.logo[1], "%%s", post.title[1], post.title[1],
- "%%s", "%%s"
- )
- )
- # BR line
- elif line.lstrip().startswith(post.html_brline[0]):
- brcss = tools.get_css(line, post.html_brline[0], ln)
-
- # HR line
- elif line.lstrip().startswith(post.html_hrline[0]):
- hrcss = tools.get_css(line, post.html_hrline[0], ln)
-
-
- # Anchor source
- elif line.lstrip().startswith(post.anchor_target[0]):
- anchor_id = tools.get_css(line, post.anchor_target[0], ln)
- if anchor_id in anchors_ids:
- post_error = \
- debug.out(54, '%s) "%s"'%(ln, anchor_id), post.uri, True, 2, False)
- return False
- anchors_ids = (*anchors_ids, anchor_id)
-
- stats_text_anc_ids += 1
- post.cf_set("STATS_TEXTS", "anc_targets", str(stats_text_anc_ids))
+ elif line.startswith(("#0", "#6")):
+ debug.out(34, "%s. %s..."%(ln, line[:3]), post.uri, True, 1, out)
+ return False
+
+ # Not valid Tyto title
+ elif line.startswith("#"):
+ try: stats["writer"]["tyto_comments"] += 1
+ except: stats["writer"]["tyto_comments"] = 1
return True
-#===========================#
-# Find and anchors links #
-# Check if anchor_id exists #
-#---------------------------#
-def anchors_links():
- markers = post.anchor_link
- stats_text_anc_links = 0
+#=======================================#
+# Check if anchors have uniq identities #
+#---------------------------------------#
+def anchors():
+ try: stats["writer"]["anchors"]
+ except: return True
- for ln, line in enumerate(texts, post.head_lines + 1):
- anc_links = re.findall('%s(.*?)%s'%(markers[0], markers[1]), line)
- if not anc_links:
- continue
-
- for anc_link in anc_links:
- if not ":" in anc_link:
- debug.out(51, '%s) ">_id:%s_<"'%(
- ln, langs.logs.anchor_title,
- ), post.uri, True, 1, False)
- continue
-
- anc_id = anc_link.rsplit(":")[0]
+ global anchors_ids
+
+ for ln, line in enumerate(article_writer, ln_w):
+ if line.lstrip().startswith(post.indep_tags["anchors"]):
+ anc_id = tools.get_css(line, post.indep_tags["anchors"])
if anc_id in anchors_ids:
- anc_title = anc_link.rsplit(":")[1].lstrip()
- if not anc_title:
- post.error = \
- debug.out(51, '%s) ">_%s:?_<"'%(
- ln, anc_id
- ), post.uri, True, 2, False)
+ debug.out(35, "%s. Anchor ID '%s'"%(
+ ln, anc_id
+ ), post.uri, True, 2, out)
+ return False
+ anchors_ids = anchors_ids + (anc_id,)
+
+ return True
+
+
+#==============================================#
+# Check Anchors links ID #
+# Create HTML for anchors #
+# Put in dict post.anchors for wip #
+#----------------------------------------------#
+def anchors_links():
+ try: stat = stats["writer"]["anc_links"]
+ except: return True
+
+ total = 0
+ for ln, line in enumerate(article_writer, ln_w):
+ if post.words_tags["anc_links"][0] in str(line) and \
+ post.words_tags["anc_links"][1] in str(line):
+ anchors = re.findall(r'%s(.*?)%s'%(
+ post.words_tags["anc_links"][0],
+ post.words_tags["anc_links"][1]
+ ), line)
+
+ for nbr, anchor in enumerate(anchors, 1):
+ # CHeck ID in anchors_ids
+ anc_id = anchor.rsplit(":")[0]
+ if not anc_id in anchors_ids:
+ debug.out(33, "%s. Anchor '-> %s'"%(
+ ln, anc_id
+ ), post.uri, True, 2, out)
return False
- # Set to post Database
- stats_text_anc_links += 1
- post.cf_set("ANCHORS",
- "anchor_%s"%stats_text_anc_links,
- post.anchor_set[0]%anc_link
- )
- post.cf_set("ANCHORS",
- "html_%s"%stats_text_anc_links,
- post.anchor_set[1]%(css, anc_id, anc_title)
- )
- else:
- post.error = \
- debug.out(51, '%s) "-> %s"'%(ln, anc_id), post.uri, True, 2, False)
- return False
-
- post.cf_set("STATS_TEXTS", "anc_links", str(stats_text_anc_links))
- return True
-
-
-#======================================#
-# Count and return sub indices in text #
-#--------------------------------------#
-def find_sub_indices(full, sub):
- return [index for index in range(len(full)) if full.startswith(sub, index)]
-
-#================================================#
-# From position of sub tag: return article line #
-# When error, to let user know real line article #
-# char is indice tag position #
-#------------------------------------------------#
-def find_line_sub(char):
- for fc, lc, ln in lines_chars:
- if fc <= char and char <= lc:
- return ln
-
-#=======================================
-# CHeck paired words tagss #
-# Count for tags stats + words #
-# ! No neeed to create HTML in post db #
-#--------------------------------------#
-def words_tags():
- global lines_chars
-
- # Create List lines number and number of characters in line
- # (In error case, show line number)
- old_len = 0 # len(line)
- lines_chars = (())
- stats_text_chars = 0
- for ln, line in enumerate(texts, post.head_lines + 1):
- stats_text_chars = stats_text_chars + len(line)
- lines_chars = lines_chars + ((old_len, stats_text_chars, ln),)
- old_len = stats_text_chars
-
- post.cf_set("STATS_TEXTS", "chars", str(stats_text_chars))
-
- # Create article in block text format
- # Also count words written
- block_texts = ''
- for line in texts:
- block_texts = block_texts + line
-
- post.cf_set("STATS_TEXTS",
- "words",
- str(sum(1 for w in block_texts.split()))
- )
-
- # For each word tag, get position indicies
- for i, tags in enumerate(post.words_tags):
- indices_o = find_sub_indices(block_texts, tags[0])
- indices_c = find_sub_indices(block_texts, tags[1])
- if not indices_o and not indices_c:
- continue
-
- # Count and compare opened and closes tags numbers
- len_o = len(indices_o)
- len_c = len(indices_c)
-
- # Not paired tags
- if len_o != len_c:
- post.error = \
- debug.out(53, "%s %s, %s %s"%(
- len_o, tags[0],
- len_c, tags[1]
- ), post.uri, True, 2, False)
- return False
-
- # Test if tags are opened > closed
- for n in range(len_o):
- # Current opened must be smaller than current closed
- if indices_o[n] > indices_c[n]:
- post.error = \
- debug.out(53, '%s) "%s...%s"'%(
- find_line_sub(indices_o[n]), tags[1], tags[0]
- ), post.uri, True, 2, False)
- return False
+ total += 1
+ anc_H = '%s '%(
+ domain.web["css"],
+ anchor.rsplit(":")[0],
+ anchor.rsplit(":")[1].lstrip()
+ )
+ post.anchors[total] = ("%s%s%s"%(
+ post.words_tags["anc_links"][0],
+ anchor,
+ post.words_tags["anc_links"][1]
+ ), anc_H)
- # Other mismatches opens/closed tags
- else:
- # Current closed must be higher than opened + 1
- try:
- if indices_c[n] > indices_o[n+1]:
- post.error = \
- debug.out(53, '%s) "%s...%s"'%(
- find_line_sub(indices_c[n]), tags[0], tags[0]
- ), post.uri, True, 2, False)
- return False
- except:
- continue
-
- # Add tag statistic to post database
- post.cf_set("STATS_TEXTS", tags[2], str(len_o))
-
return True
-
-
-#==================================#
-# Update post configuration file #
-# part: #
-# before > first generic datas #
-# after > after all check modules #
-#----------------------------------#
-def cf_update_values(part):
- # Generic known first datas, before check modules
- if part == "before":
- post.cf_set("DOMAIN", "name", domain.name)
- post.cf_set("CHECK", "static", str(domain.static))
- post.cf_set("CHECK", "hash", post.wrk_id)
-
- # [FILE]
- web_target = post.wrk_target[:-4] + "html"
- if web_target.endswith("index.html"):
- web_target = web_target[:-10]
- if not web_target.startswith("/"):
- web_target = "/" + web_target
-
- # Create HTML local sub uri
- post.cf_set("FILE", "id", post.uri_id)
- post.cf_set("FILE", "uri", post.uri)
- post.cf_set("FILE", "db", post.cf_uri)
- post.cf_set("FILE", "target", post.wrk_target)
- post.cf_set("FILE", "web", web_target)
- post.cf.set("FILE", "sub_uri", post.wrk_target.count('/') * "../" or "./")
-
- # [WIP]
- # -----
- post.cf_set("WIP", "hash", post.wip_hash)
- post.cf_set("WIP", "date", post.wip_date)
- post.cf_set("WIP", "web", "%s%s"%(domain.wip_url, post.web_target))
- post.cf_set("WIP", "uri", "%s%s"%(domain.wip, post.web_target))
-
- # [WWW]
- # -----
- post.cf_set("WWW", "hash", post.www_hash)
- post.cf_set("WWW", "date", post.www_date)
- post.cf_set("WWW", "web", "%s%s"%(domain.www_url, post.web_target))
- post.cf_set("WWW", "uri", "%s%s"%(domain.www, post.web_target))
-
- # Stats (these, cause i want them first)
- post.cf_set("STATS_FILE", "lines", str(post.lines))
- post.cf_set("STATS_HEADERS", "lines", str(post.head_lines))
- post.cf_set("STATS_TEXTS", "lines", str(post.text_lines))
-
- return
-
- # Datas after check modules
- # -------------------------
- # [CHECK]
- # -------
- post.cf_set("CHECK", "errors", "False")
-
- # [STATS_FILE]
- # ------------
- stats_tyto_all_coms = stats_tyto_text_coms + stats_tyto_head_coms
- stats_tyto_all_coms > 0 and \
- post.cf_set("STATS_FILE", "tyto_coms", str(stats_tyto_all_coms))
-
- # Add base64 new article TEXTS
- post.cf_set("TEXTS", "post", tools.b64_convert("encode", '\n'.join(texts)))
-
- # ============================
- # Write new values in database
- # ============================
- post.cf_write()
-
- # Show done message
- debug.out(254, "[%s]"%post.title[1], post.uri, True, 0, False)
diff --git a/src/var/lib/tyto/program/debug.py b/src/var/lib/tyto/program/debug.py
index 2bd8f2c..4160488 100644
--- a/src/var/lib/tyto/program/debug.py
+++ b/src/var/lib/tyto/program/debug.py
@@ -14,95 +14,75 @@
# 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 .
+# along with this program. If not, see ..
#----------------------------------------------------------------------
-# XMPP: echolib > im@echolib.re
+# XMPP: echolib (im@echolib.re)
#
-# Description: Add more logs when debug is set in command line
+# Description: Show logs in console. Manage verbose mode (-v)
# File: /var/lib/tyto/program/debug.py
#----------------------------------------------------------------------
-#-------------------------
-# Funny Stats Project
-#-------------------------
-# file lines :
-# file comments :
-# file functions:
-# file program :
-#--------------------------
-
import sys
-import langs, args, logs
-
+import args, langs, domain
#===================#
# Messages for logs #
#-------------------#
def set_messages():
- global messages, got_messages
-
- try: got_messages ; return
+ global messages, loaded_messages
+
+ try: loaded_messages ; return
except: pass
messages = \
{
# ERRORS (1-100)
- 1 : langs.logs.err_arg,
- 2 : langs.logs.err_hole,
- 3 : langs.logs.err_dir,
- 4 : langs.logs.err_cd,
- 5 : langs.logs.err_no_file,
- 6 : langs.logs.err_no_dir,
- 7 : langs.logs.err_cr_file,
- 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,
- 23 : langs.logs.err_post_empty,
- 50 : langs.logs.err_date,
- 51 : langs.logs.err_post_data,
- 52 : langs.logs.err_post_title,
- 53 : langs.logs.err_post_paired,
- 54 : langs.logs.err_post_id_yet,
- 55 : langs.logs.err_post_in_tag,
- 56 : langs.logs.err_post_datatag,
- # WARNINGS (100-200)
- 100 : langs.logs.warn_no_dom,
- 101 : langs.logs.domain_created,
- 102 : langs.logs.reset_dom,
- 103 : langs.logs.website_lang,
- 104 : langs.logs.domains_no,
- 105 : langs.logs.domain_off,
- 106 : langs.logs.warn_post_chk,
- # Great (200-255)
- 200 : langs.logs.load_file,
- 201 : langs.logs.lang_logs_sys,
- 202 : langs.logs.domain_found,
- 203 : langs.logs.created_dir,
- 204 : langs.logs.domain_updated,
- 205 : langs.logs.domain_new,
- 206 : langs.logs.created_file,
- 207 : langs.logs.updated_file,
- 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,
+ 2 : langs.logs.err_argument,
+ 3 : langs.logs.err_domain_name,
+ 4 : langs.logs.err_in_hole,
+ 5 : langs.logs.err_file_create,
+ 6 : langs.logs.err_dir_unused,
+ 7 : langs.logs.err_dir_create,
+ 8 : langs.logs.err_lang_no,
+ 9 : langs.logs.err_domain_dir,
+ 10 : langs.logs.err_dir_in,
+ 11 : langs.logs.err_file_no,
+ 12 : langs.logs.err_post_db,
+ 13 : langs.logs.err_post_srv_no,
+ 30 : langs.logs.err_post_sep,
+ 31 : langs.logs.err_post_header_no,
+ 32 : langs.logs.err_post_writer_no,
+ 33 : langs.logs.err_post_tag_set,
+ 34 : langs.logs.err_post_tag_val,
+ 35 : langs.logs.err_post_tag_id,
+ 36 : langs.logs.err_post_mark_no,
+ 37 : langs.logs.err_post_mark_stop,
+ 38 : langs.logs.err_post_mark_miss,
+ 39 : langs.logs.warn_post_tupic,
+ 90 : langs.logs.err_process,
+ 99 : langs.logs.err_kbd_stop,
+ # WARNINGS
+ 100 : langs.logs.warn_domain_no,
+ 101 : langs.logs.warn_date_format,
+ 102 : langs.logs.warn_domain_conf,
+ 199 : langs.logs.warn_maybe_later,
+ # INFOS (200-255)
+ 200 : langs.logs.inf_dir_user,
+ 201 : langs.logs.inf_lang_logs,
+ 202 : langs.logs.inf_domain_load,
+ 203 : langs.logs.inf_domain_conf,
+ 205 : langs.logs.inf_file_create,
+ 206 : langs.logs.inf_file_upd,
+ 207 : langs.logs.inf_dir_create,
+ 210 : langs.logs.inf_check_post,
+ 211 : langs.logs.inf_wip_process,
+ 212 : langs.logs.inf_mod_process,
+ 250 : langs.logs.inf_end_process,
}
- got_messages = True
+ loaded_messages = True
#===================================#
@@ -118,18 +98,13 @@ def set_messages():
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
+ # File log printing
+ # -----------------
+ #logit(nbr, var, val)
+
+ # Front User Console
+ # ------------------
# COlors
CS = '\033[0;0m' # Unset
CL = '\033[0;2m' # Gray
@@ -144,18 +119,23 @@ def out(nbr, var, val, show, color, stop):
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"%(
- SC, CS,
- CL, messages[nbr], CS,
- CB, var, CS,
- CC, val, CS
- )
- )
+ elif color == 2: SC = CR
+
+ if not show:
+ if args.commands["options"]["-v"]: show = True
+ force_show = bool(color > 0 and args.commands["options"]["-E"])
+ if show or force_show:
+ # Print, acoording to parameters
+ print("%s*%s %s%s%s > %s%s%s < %s%s%s"%(
+ SC, CS,
+ CL, messages[nbr], CS,
+ CB, var, CS,
+ CC, val, CS
+ )
+ )
+
# Exit if stop = True
if stop:
if nbr >= 200: nbr = 0
@@ -163,3 +143,11 @@ def out(nbr, var, val, show, color, stop):
return nbr
+
+#============#
+# Files logs #================================================================
+#------------#
+def logit(nbr, var, val):
+ try: domain.name
+ except: domain.name = ""
+ print(": debug. domain name", domain.name)
diff --git a/src/var/lib/tyto/program/domain.py b/src/var/lib/tyto/program/domain.py
index 4fe74f7..da1b7cb 100644
--- a/src/var/lib/tyto/program/domain.py
+++ b/src/var/lib/tyto/program/domain.py
@@ -14,704 +14,586 @@
# 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 .
+# along with this program. If not, see ..
#----------------------------------------------------------------------
-# XMPP: echolib > im@echolib.re
+# XMPP: echolib (im@echolib.re)
#
-# Description: Manage configuration domain(s)
+# Description: Manage domain (config files).
# File: /var/lib/tyto/program/domain.py
#----------------------------------------------------------------------
-#-------------------------
-# Funny Stats Project
-#-------------------------
-# file lines :
-# file comments :
-# file functions:
-# file program :
-#--------------------------
-
import os, sys, configparser
-import debug, tyto, tools, forms, langs
+import debug, tools, form, langs
-#=========================================================#
-# Exit if directory name is compatible with a domain name #
-#---------------------------------------------------------#
-def compatible_name():
- if len(name.rsplit(".")) <= 1:
- debug.out(3, "abc.tld", name, True, 2, True)
+#
+# Manage domain
+# Mainly start and stop action
+#
+def manage():
+ import args
+ is_ready()
-#================================#
-# Load Domain Configuration file #
-# As needed, exit if not exists #
-#--------------------------------#
-def cf_load():
- global cf
+ if args.commands["actions"]["start"]:
+ if not conf["activated"]:
+ cf.set("DOMAIN", "activated", "True")
+ with open(cf_uri, "w") as f:
+ cf.write(f)
+
+ debug.out(250, "%s [%s]"%(
+ conf["title"], "True"
+ ), cf_uri, True, 0, True)
- cf_exists() or sys.exit(100)
-
- cf = False
- cf = configparser.ConfigParser()
- cf.read(cf_uri)
- debug.out(200, langs.logs.domain, cf_uri, False, 0, False)
+ elif args.commands["actions"]["stop"]:
+ if conf["activated"]:
+ cf.set("DOMAIN", "activated", "False")
+ with open(cf_uri, "w") as f:
+ cf.write(f)
+
+ debug.out(250, "%s [%s]"%(
+ conf["title"], "False"
+ ), cf_uri, True, 0, True)
-#=====================================#
-# Load User Domain Configuration file #
-# As needed, exit if not exists #
-#-------------------------------------#
-def ult_cf_load():
- global ult_cf
-
- ult_cf = False
- if not os.path.exists(ult_cf_uri):
- tools.create_file(ult_cf_uri, tyto.ini_domain_user)
-
- ult_cf = configparser.ConfigParser()
- ult_cf.read(ult_cf_uri)
+#=======================#
+# Set current directory #
+#-----------------------#
+def check_home():
+ global user_dir, home_dir, in_hole
+
+ try:
+ in_hole = False
+ user_dir = os.getcwd() + "/"
+ home_dir = os.path.expanduser('~')
+ if ".local/share/Trash/" in user_dir:
+ in_hole = True
+ except:
+ user_dir = ""
+ in_hole = True
-#===================================#
-# Load User local Domains List File #
-#-----------------------------------#
-def ult_dlf_load():
- global ult_dlf
+#===================================================#
+# Set domain name #
+# check if name is valid (compatible with a domain) #
+#---------------------------------------------------#
+def set_name():
+ global wrk_root, name, cf_uri, cf_id, ult_dir, ult_cf_uri, ult_domains_uri
- # User Domains list file
- ult_dlf = False
- if not os.path.exists(ult_dlf_uri):
- tools.create_file(ult_dlf_uri, tyto.ini_domains_list)
-
- ult_dlf = configparser.ConfigParser()
- ult_dlf.read(ult_dlf_uri)
+ # Set current working root directory before articles/ folder (if exists)
+ wrk_root = user_dir.rsplit("articles/")[0]
-
-#===========================================#
-# Check if Domain COnfiguration file exists #
-# Show status message only once #
-# return True or False
-#-------------------------------------------#
-def cf_exists():
- global shown_ok, shown_no
+ # Set current directory name
+ name = os.path.basename(os.path.dirname(wrk_root))
- if os.path.exists(cf_uri):
- try: shown_ok
- except: debug.out(202, name, cf_uri, False, 0, False)
- shown_ok = True
- return True
- else:
- try: shown_no
- except: debug.out(104, "False", cf_uri, True, 1, False)
- shown_no = True
- compatible_name()
- return False
+ # valid name is "a.b" format
+ if not len(name.rsplit(".")) > 1:
+ debug.out(3, name, user_dir, True, 2, True)
+
+ # Set Configuration file uri, and ID
+ cf_uri = wrk_root + "tyto_domain.ini"
+ cf_id = tools.get_HID(cf_uri, False)
+
+ # Set .loacl/Tyto/ configuration files uri
+ ult_dir = "%s/.local/Tyto/"%home_dir
+ ult_cf_uri = "%s%s.ini"%(ult_dir, cf_id)
+ ult_domains_uri = "%sdomains.ini"%ult_dir
#=========================================#
# Guess and return wip_url from name #
#-----------------------------------------#
def create_wip_url():
- www_url = "https://www-wip.%s/"
+ wip_url = "https://www-wip.%s/"
len_cn = name.count(".")
# Domain name Format: a.b
if len_cn == 1:
- return www_url%name
+ return wip_url%name
# Domain name format: (at least) a.b.c
len_cn = len(name.rsplit(".")[0]) + 1
tld = name[len_cn:]
- return www_url%tld
+ return wip_url%tld
-#==========================================#
-# Ask User to create new domain #
-# Create NEW #:
-# - default Domain Configuration file #
-# - default User domain configuration file #
-# If not User domains list file, create it #
-#------------------------------------------#
-def cf_create():
- compatible_name()
+
+#============================#
+# Set all needed directories #
+#----------------------------#
+def set_values():
+ global conf
+ conf = {
+ "activated" : cf.getboolean("DOMAIN", "activated"),
+ "post_code" : cf.getboolean("WEBSITE", "article_code"),
+ "sitemaps" : cf.getboolean("WEBSITE_MODULES", "sitemaps"),
+ "title" : cf.get("DOMAIN", "title"),
+ "about" : cf.get("DOMAIN", "about"),
+ "date" : cf.get("DOMAIN", "date"),
+ "tags" : cf.get("DOMAIN", "tags"),
+ "mail" : cf.get("DOMAIN", "mail"),
+ }
- # This fonction is only called with "new domain" argument
- # If a conf already exists, show important RESET log
- if cf_exists():
- debug.out(102, "!?", cf_uri, True, 1, False)
-
- # Ask User to create new domain. Will exit if not ok.
- forms.ask_domain_shortname(name)
+ global wrk_dirs
+ wrk_dirs = {
+ "articles" : wrk_root + "articles/",
+ "images" : wrk_root + "articles/images/",
+ "files" : wrk_root + "articles/files/",
+ "template" : wrk_root + "template/",
+ "modules" : wrk_root + "modules/",
+ "db" : wrk_root + ".db/",
+ }
+
+ global srv_root, srv_domain
+ srv_root = cf.get("SERVER", "srv_root")
+ srv_domain = "%s%s/"%(srv_root, name)
+
+ global wip, www, wip_dirs, www_dirs
+ wip = "%swip/"%srv_domain
+ www = "%swww/"%srv_domain
+ wip_dirs = {
+ "images" : "%simages/"%wip,
+ "files" : "%sfiles/"%wip,
+ "template" : "%stemplate/"%wip,
+ }
+ www_dirs = {
+ "images" : "%simages/"%www,
+ "files" : "%sfiles/"%www,
+ "template" : "%stemplate/"%www,
+ }
+
+ global srv_wip_files
+ srv_wip_files = \
+ {
+ "styles" : wip_dirs["template"] + cf.get("TEMPLATE_FILENAMES", "styles"),
+ }
+
+ global web
+ web = {
+ "wip" : cf.get("WEBSITE", "wip_url"),
+ "www" : cf.get("WEBSITE", "www_url"),
+ "css" : cf.get("WEBSITE", "css"),
+ "lang" : cf.get("WEBSITE", "lang"),
+ "license" : cf.get("WEBSITE", "license"),
+ "license_url" : cf.get("WEBSITE", "license_url"),
+ }
+
+ global lang
+ lang = cf.get("WEBSITE", "lang")
+
+ create_srv_dirs("wrk")
+
+ debug.out(202, name, cf_uri, False, 0, False)
+
+
+#=======================================================#
+# Create domain directorie for wrk or srv (wip or wwws) #
+#-------------------------------------------------------#
+def create_srv_dirs(process):
+ dirs = {
+ "wrk" : wrk_dirs,
+ "wip" : wip_dirs,
+ "www" : www_dirs,
+ }
- # Create default files
- tools.create_file(cf_uri, ini_template%name)
+ for d in dirs[process]:
+ tools.create_dirs(dirs[process][d])
+
+
+#===========================#
+# Main domain check #
+# Used for most processes #
+# when domain must be ready #
+# Exit if something wrong #
+#---------------------------#
+def is_ready():
+ # Exit 3 if domain name not at leat "a.b" format
+ set_name()
+ cf_exists() or sys.exit(100)
+ cf_load()
+ cf_legacy() # Exit in error case
+ cf_update()
+ set_values()
+
+
+#====================================#
+# Domain Configuration file sections #
+#------------------------------------#-----------------------------------------
+#============================================================#
+# Create NZW ID.ini config file in user local Tyto directory #
+#------------------------------------------------------------#
+def ult_cf_create():
tools.create_dirs(ult_dir)
- tools.create_file(ult_cf_uri, tyto.ini_domain_user)
+ if os.path.exists(ult_cf_uri):
+ os.remove(ult_cf_uri)
+ with open(ult_cf_uri, "w") as f:
+ f.write(ini_ult_tpl)
+ else:
+ tools.create_file(ult_cf_uri, ini_ult_tpl)
- # User Domains list file
- if not os.path.exists(ult_dlf_uri):
- tools.create_file(ult_dlf_uri, tyto.ini_domains_list)
+ ult_cf_load()
+
+ # Also create domains lists in domains.ini
+ if not os.path.exists(ult_domains_uri):
+ tools.create_file(ult_domains_uri, ini_domains)
+
+ ult_domains_load()
+
+
+#
+# Domain configuration file in .loacl/Tyto/
+#
+def ult_cf_load():
+ global ult_cf
+
+ ult_cf = False
+ ult_cf = configparser.ConfigParser()
+ ult_cf.read(ult_cf_uri)
+
+
+#====================================#
+# Load list of all registred domains #
+#------------------------------------#
+def ult_domains_load():
+ global ult_domains
+
+ ult_domains = False
+ ult_domains = configparser.ConfigParser()
+ ult_domains.read(ult_domains_uri)
+
+
+#==========================#
+# Check configuration file #
+#--------------------------#
+def cf_exists():
+ global found
+
+ found = bool(os.path.exists(cf_uri))
+
+ # Show info
+ found or debug.out(100, name, cf_uri, True, 1, False)
+
+ return found
+
+
+#================================#
+# Create default ini config file #
+#--------------------------------#
+def cf_create():
+ if not found:
+ tools.create_file(cf_uri, ini_cf_tpl)
+ cf_exists() or debug.out(100, name, cf_uri, True, 2, True)
- # Ask user for domain settings
cf_load()
- forms.ask_domain_title(True)
- forms.ask_domain_date(True)
- forms.ask_domain_about(True)
- forms.ask_domain_mail(True)
- forms.ask_domain_tags(True)
-
- # Set default lang, from config file or system lang
- forms.ask_domain_lang(True)
-
- # Set server directory
- forms.ask_domain_server(True)
-
- # Update Domain Configuration file
- cf_update_values(True)
-
-#===================================================#
-# Generic set section and values for ini file #
-# File must exists (checked before) #
-# Create section, set key if not exists #
-# Ask yser when default is a key form and not value #
-#---------------------------------------------------#
-def cf_set(section, key, default):
- global new_val
- try: new_val
- except: new_val = False
+#=============================#
+# Load ini configuration file #
+#-----------------------------#
+def cf_load():
+ global cf
+ cf = False
+ cf = configparser.ConfigParser()
+ cf.read(cf_uri)
+
+
+#=============================================#
+# Check if current directory is domain legacy #
+#---------------------------------------------#
+def cf_legacy():
+ cf_legacy_id()
+ cf_ult_file()
+ cf_legacy_domains()
+
+
+#====================================================================#
+# Config file was loaded yet #
+# Check domain hash ID from current directory and domain config file #
+#--------------------------------------------------------------------#
+def cf_legacy_id():
try:
- val = cf.get(section, key)
+ domain_id = cf.get("TYTO", "id")
+ domain_dir = cf.get("DOMAIN", "work")
except:
- try: cf.add_section(section) ; new_val = True
- except: pass
- val = ""
+ domain_id =domain_dir = ""
+
+ legacy_id = tools.same_values(domain_id, cf_id)
+ legacy_id or debug.out(9, wrk_root, domain_dir, True, 2, True)
+
+
+#=============================#
+# Check if ult_cf file exists #
+#-----------------------------#
+def cf_ult_file():
+ ult_config = bool(os.path.exists(ult_cf_uri))
+ if ult_config:
+ try:
+ ult_cf_load()
+ domain_dir = ult_cf.get("DOMAIN", "directory")
+ except:
+ domain_dir = ""
- # Values has a form
- if default in tyto.keys_4q:
- if val: return val
- else: default = tyto.keys_questions[default](False) ; new_val = True
-
- # Optional key
- elif not default:
- if not val:
- cf.set(section, key, default)
- return default
- else:
- default = val
-
- # Force set default value
- if val != default:
- new_val = True
-
- cf.set(section, key, default)
- debug.out(204, "[%s] %s"%(section, key), default, False, 0, False)
-
- return default
+ legacy_dir = tools.same_values(domain_dir, wrk_root)
+ legacy_dir or debug.out(9, wrk_root, domain_dir, True, 2, True)
+ else:
+ debug.out(100, "!?", ult_cf_uri, True, 2, True)
-#===========================================#
-# Set or Update domain configuration values #
-# Ask for some values if empty #
-# Ensure to set correct values #
-#-------------------------------------------#
-def cf_update_values(write):
- # Load Domain Configuration file
- cf_load()
- debug.out(214, "...", cf_uri, False, 0, False)
+#====================================================#
+# Check current wrk_root dir with dir in domains.ini #
+#----------------------------------------------------#
+def cf_legacy_domains():
+ try:
+ ult_domains_load()
+ domain_dir = ult_domains.get("DOMAINS", name)
+ except:
+ domain_dir = ""
+ legacy_dir = tools.same_values(domain_dir, wrk_root)
+ legacy_dir or debug.out(9, wrk_root, domain_dir, True, 2, True)
+
+
+#============================================#
+# from cf_load() #
+# update all values and set some global ones #
+#--------------------------------------------#
+def cf_update():
+ global cf_write
+
+ # Check if domain configuration file has changed
+ # and update configuration file if so.
+ # (Based on last content ID, saved in ult domain config file)
+ try:
+ ult_cf_load()
+ if not args.action == "check":
+ if tools.same_values(
+ ult_cf.get("DOMAIN", "id"),
+ tools.get_HID(cf_uri, True)
+ ):
+ return
+ except:
+ debug.out(203, name, cf_uri, False, 0, False)
+
+ try: cf_write
+ except: cf_write = False
+
# [DOMAIN]
- # ========
- global activated, title, date, about, mail, tags, license, license_url
- try: activated = cf.getboolean("DOMAIN", "activated")
- except: activated = cf_set("DOMAIN", "activated", "no")
-
- cf_set("DOMAIN", "name", name)
-
- title = cf_set("DOMAIN", "title", "title")
- date = cf_set("DOMAIN", "date", "date")
- about = cf_set("DOMAIN", "about", "about")
- mail = cf_set("DOMAIN", "mail", "mail")
- tags = cf_set("DOMAIN", "tags", "tags")
- license = cf_set("DOMAIN", "lincese", "")
- if not license:
- license = cf_set("DOMAIN", "license", "gfdl-1.3")
- license_url = cf_set("DOMAIN", "license_url",
- "https://www.gnu.org/licenses/fdl-1.3.txt")
- elif not license == "gfdl-1.3" and \
- license_url == "https://www.gnu.org/licenses/fdl-1.3.txt":
- license_url = cf_set("DOMAIN", "license_url", "")
-
- # [WEBSITE_FOOTER]
- global legals_url, terms_url, bylaws_url
- legals_url = cf_set("WEBSITE_FOOTER", "legals_url", "")
- terms_url = cf_set("WEBSITE_FOOTER", "terms_url", "")
- bylaws_url = cf_set("WEBSITE_FOOTER", "bylaws_url", "")
-
-
- # [SERVER]
- # ========
- global srv, srv_name, wip, www
- srv = cf_set("SERVER", "root", "server")
- if not tools.dir_exists(srv, False):
- srv = cf_set("SERVER", "root", "server")
-
- srv_name = os.path.join(srv, name + "/")
- wip = os.path.join(srv_name, "wip/")
- www = os.path.join(srv_name, "www/")
-
- cf_set("SERVER", "domain", srv_name)
- cf_set("SERVER", "wip", wip)
- cf_set("SERVER", "www", www)
-
-
- # [WIP_DIRS]
- # ==========
- global wip_tpl, wip_images, wip_files
- wip_tpl = os.path.join(wip, "template/")
- wip_images = os.path.join(wip, "images/")
- wip_files = os.path.join(wip, "files/")
-
- cf_set("WIP_DIRS", "template", wip_tpl)
- cf_set("WIP_DIRS", "images", wip_images)
- cf_set("WIP_DIRS", "files", wip_files)
-
-
- # [WWW_DIRS]
- # ==========
- global www_tpl, www_images, www_files
- www_tpl = os.path.join(www, "template/")
- www_images = os.path.join(www, "images/")
- www_files = os.path.join(www, "files/")
-
- cf_set("WWW_DIRS", "template", www_tpl)
- cf_set("WWW_DIRS", "images", www_images)
- cf_set("WWW_DIRS", "files", www_files)
-
+ cf_set("DOMAIN", "name", name, False)
+ cf_set("DOMAIN", "work", wrk_root, False)
+ cf_set("DOMAIN", "activated", False, True)
+ title = \
+ cf_set("DOMAIN", "title", "", False)
+ cf_set("DOMAIN", "date", "", False)
+ cf_set("DOMAIN", "about", "", False)
+ cf_set("DOMAIN", "tags", "", False)
+ cf_set("DOMAIN", "mail", "", False)
# [WEBSITE]
- # =========
- global wip_url, www_url, lang, css, sep, article_code, static
- wip_url = cf_set("WEBSITE", "wip_url", "") or \
- cf_set("WEBSITE", "wip_url", create_wip_url())
-
- www_url = cf_set("WEBSITE", "www_url", "") or \
- cf_set("WEBSITE", "www_url", "https://%s/"%name)
-
- lang = cf_set("WEBSITE", "lang", "")
- if not lang:
- lang = cf_set("WEBSITE", "lang", langs.load_website_lang())
- elif not langs.translation_exists("website", lang, False):
- lang = langs.get_sys_lang()
- langs.load_website_lang()
-
- css = cf_set("WEBSITE", "css", "") or \
- cf_set("WEBSITE", "css", "tyto")
-
- sep = cf_set("WEBSITE", "separator", "")
- if not sep or len(sep) > 2:
- sep = cf_set("WEBSITE", "separator", "|")
-
- try: article_code = cf.getboolean("WEBSITE", "article_code")
- except: article_code = cf_set("WEBSITE", "article_code", "yes")
- try: static = cf.getboolean("WEBSITE", "static")
- except: static = cf_set("WEBSITE", "static", "no")
-
-
+ cf_set("WEBSITE", "wip_url", create_wip_url(), False)
+ cf_set("WEBSITE", "www_url", "https://%s/"%name, False)
+ cf_set("WEBSITE", "css", "tyto", False)
+ cf_set("WEBSITE", "separator", "-", False)
+ cf_set("WEBSITE", "article_code", False, True)
+ license = \
+ cf_set("WEBSITE", "license", "gfdl-1.3", False)
+ license_url = \
+ cf_set("WEBSITE", "license_url",
+ "https://www.gnu.org/licenses/fdl-1.3.txt", False)
+ global lang
+ lang = \
+ cf_set("WEBSITE", "lang", "", False)
+
# [WEBSITE_MODULES]
- # =================
- global navbar, sidebar_title, sidebar_items, rss_items, sitemaps
- try: navbar = cf.getboolean("WEBSITE_MODULES", "navbar")
- except: navbar = cf_set("WEBSITE_MODULES", "navbar", "yes")
-
- sidebar_title = cf_set("WEBSITE_MODULES", "sidebar_title", "") or \
- cf_set("WEBSITE_MODULES", "sidebar_title", langs.site.sidebar_title)
-
- sidebar_items = cf_set("WEBSITE_MODULES", "sidebar_items", "")
- if not sidebar_items or not sidebar_items.isdigit():
- sidebar_items = cf_set("WEBSITE_MODULES", "sidebar_items", "0")
-
- rss_items = cf_set("WEBSITE_MODULES", "rss_items", "")
- if not rss_items or not rss_items.isdigit():
- rss_items = cf_set("WEBSITE_MODULES", "rss_items", "0")
-
- try: sitemaps = cf.getboolean("WEBSITE_MODULES", "sitemaps")
- except: sitemaps = cf_set("WEBSITE_MODULES", "sitemaps", "yes")
-
-
- # TEMPLATE_FILENAMES
- # ==================
- global favicon, logo, styles, rss, stats
- favicon = cf_set("TEMPLATE_FILENAMES", "favicon", "") or \
- cf_set("TEMPLATE_FILENAMES", "favicon", "favicon.png")
-
- logo = cf_set("TEMPLATE_FILENAMES", "logo", "") or \
- cf_set("TEMPLATE_FILENAMES", "logo", "logo.png")
-
- styles = cf_set("TEMPLATE_FILENAMES", "styles", "") or \
- cf_set("TEMPLATE_FILENAMES", "styles", "styles.css")
-
- rss = cf_set("TEMPLATE_FILENAMES", "rss", "") or \
- cf_set("TEMPLATE_FILENAMES", "rss", "rss.xml")
-
- stats = cf_set("TEMPLATE_FILENAMES", "stats", "") or \
- cf_set("TEMPLATE_FILENAMES", "stats", "tyto_stats.ini")
-
-
- # [USER_DIRS]
- # ===========
- cf_set("USER_DIRS", "root", wrk_dir)
- cf_set("USER_DIRS", "articles", wrk_articles)
- cf_set("USER_DIRS", "images", wrk_images)
- cf_set("USER_DIRS", "files", wrk_files)
- cf_set("USER_DIRS", "template", wrk_tpl)
- cf_set("USER_DIRS", "modules", wrk_mods)
- cf_set("USER_DIRS", "database", wrk_db)
-
-
- # [USER_TEMPLATE_FILES]
- # =====================
- global wrk_favicon, wrk_logo, wri_styles
- wrk_favicon = os.path.join(wrk_tpl, favicon)
- wrk_logo = os.path.join(wrk_tpl, logo)
- wrk_styles = os.path.join(wrk_tpl, styles)
-
- cf_set("USER_TEMPLATE_FILES", "favicon", wrk_favicon)
- cf_set("USER_TEMPLATE_FILES", "logo", wrk_logo)
- cf_set("USER_TEMPLATE_FILES", "styles", wrk_styles)
-
-
- # [USER_MODULES_FILES]
- # ====================
- global wrk_metas, wrk_header, wrk_navbar, wrk_sidebar, wrk_footer
- wrk_metas = os.path.join(wrk_mods, "tyto_metas.raw")
- wrk_header = os.path.join(wrk_mods, "tyto_header.raw")
- wrk_navbar = os.path.join(wrk_mods, "tyto_navbar.raw")
- wrk_sidebar = os.path.join(wrk_mods, "tyto_sidebar.raw")
- wrk_footer = os.path.join(wrk_mods, "tyto_footer.raw")
-
- cf_set("USER_MODULES_FILES", "metas", wrk_metas)
- cf_set("USER_MODULES_FILES", "header", wrk_header)
- cf_set("USER_MODULES_FILES", "navbar", wrk_navbar)
- cf_set("USER_MODULES_FILES", "sidebar", wrk_sidebar)
- cf_set("USER_MODULES_FILES", "footer", wrk_footer)
-
-
- # [WIP_FILES]
- # ===========
- global wip_favicon, wip_logo, wip_styles, wip_rss, wip_stats
- wip_favicon = os.path.join(wip_tpl, favicon)
- wip_logo = os.path.join(wip_tpl, logo)
- wip_styles = os.path.join(wip_tpl, styles)
- wip_rss = os.path.join(wip_tpl, rss)
- wip_stats = os.path.join(wip_tpl, stats)
-
- cf_set("WIP_FILES", "favicon", wip_favicon)
- cf_set("WIP_FILES", "logo", wip_logo)
- cf_set("WIP_FILES", "styles", wip_styles)
- cf_set("WIP_FILES", "rss", wip_rss)
- cf_set("WIP_FILES", "stats", wip_stats)
-
- global wip_metas, wip_header, wip_navbar, wip_sidebar, wip_footer
- wip_metas = os.path.join(wip_tpl, "metas.html")
- wip_header = os.path.join(wip_tpl, "header.html")
- wip_navbar = os.path.join(wip_tpl, "navbar.html")
- wip_sidebar = os.path.join(wip_tpl, "sidebar.html")
- wip_footer = os.path.join(wip_tpl, "footer.html")
-
- cf_set("WIP_FILES", "metas", wip_metas)
- cf_set("WIP_FILES", "header", wip_header)
- cf_set("WIP_FILES", "navbar", wip_navbar)
- cf_set("WIP_FILES", "sidebar", wip_sidebar)
- cf_set("WIP_FILES", "footer", wip_footer)
-
-
- # [WWW_FILES]
- # ===========
- global www_favicon, www_logo, www_styles, www_rss, www_stats
- www_favicon = os.path.join(www_tpl, favicon)
- www_logo = os.path.join(www_tpl, logo)
- www_styles = os.path.join(www_tpl, styles)
- www_rss = os.path.join(www_tpl, rss)
- www_stats = os.path.join(www_tpl, stats)
-
- cf_set("WWW_FILES", "favicon", www_favicon)
- cf_set("WWW_FILES", "logo", www_logo)
- cf_set("WWW_FILES", "styles", www_styles)
- cf_set("WWW_FILES", "rss", www_rss)
- cf_set("WWW_FILES", "stats", www_stats)
-
- global www_metas, www_header, www_navbar, www_sidebar, www_footer
- www_metas = os.path.join(www_tpl, "metas.html")
- www_header = os.path.join(www_tpl, "header.html")
- www_navbar = os.path.join(www_tpl, "navbar.html")
- www_sidebar = os.path.join(www_tpl, "sidebar.html")
- www_footer = os.path.join(www_tpl, "footer.html")
-
- cf_set("WWW_FILES", "metas", www_metas)
- cf_set("WWW_FILES", "header", www_header)
- cf_set("WWW_FILES", "navbar", www_navbar)
- cf_set("WWW_FILES", "sidebar", www_sidebar)
- cf_set("WWW_FILES", "footer", www_footer)
-
+ langs.load_site()
+ cf_set("WEBSITE_MODULES", "sidebar_title", langs.site.sidebar_title, False)
+ cf_set("WEBSITE_MODULES", "sidebar_items", "6", False)
+ cf_set("WEBSITE_MODULES", "rss_items", "100", False)
+ cf_set("WEBSITE_MODULES", "sitemaps", True, True)
+
+ # [WEBSITE_FOOTER]
+ # Footer links configuration. typle format: ("Show", "URL", "TITLE")
+ cf_set(
+ "WEBSITE_FOOTER",
+ "link_1",
+ '("%s%s %s", "%s", "%s %s")'%(
+ langs.site.license, langs.logs.pp, license,
+ license_url,
+ langs.site.license_title, title
+ ), False
+ )
+ cf_set(
+ "WEBSITE_FOOTER",
+ "link_2",
+ '("%s", "/", "%s %s")'%(
+ langs.site.legals, langs.site.legals_title, title
+ ), False
+ )
+ cf_set(
+ "WEBSITE_FOOTER",
+ "link_3",
+ '("%s", "/", "%s %s")'%(
+ langs.site.terms, langs.site.terms_title, title
+ ), False
+ )
+ cf_set(
+ "WEBSITE_FOOTER",
+ "link_4",
+ '("%s", "/", "%s %s")'%(
+ langs.site.bylaws, langs.site.bylaws_title, title
+ ), False
+ )
+
+ # [SERVER]
+ global srv_root
+ cf_set("SERVER", "srv_root", "", False)
+
+ # [TEMPLATE_FILENAMES]
+ cf_set("TEMPLATE_FILENAMES", "favicon", "favicon.png", False)
+ cf_set("TEMPLATE_FILENAMES", "logo", "logo.png", False)
+ cf_set("TEMPLATE_FILENAMES", "styles", "styles.css", False)
+ cf_set("TEMPLATE_FILENAMES", "rss", "rss.xml", False)
+ cf_set("TEMPLATE_FILENAMES", "stats", "tyto_stats.ini", False)
# [TYTO]
- # ======
- cf_set("TYTO", "domain_hash", cf_id)
- cf_set("TYTO", "domain_conf", cf_uri)
- cf_set("TYTO", "domain_user", ult_cf_uri)
+ cf_set("TYTO", "id", cf_id, False)
+ cf_set("TYTO", "conf_uri", cf_uri, False)
+ cf_set("TYTO", "user_uri", ult_cf_uri, False)
-
- # ================================= #
- # Write Configuration file #
- # Only if needed or when new domain #
- # --------------------------------- #
- if new_val or write:
- with open(cf_uri, "w") as f:
- cf.write(f)
-
-
- #=============================================#
- # Update User local domain configuration file #
- #---------------------------------------------#
- ult_write = False
- ult_cf_load()
- if ult_cf.get("DOMAIN", "name") != name:
+ # New config values was set: write new ini config files
+ if cf_write:
+ try:
+ with open(cf_uri, "w") as f:
+ cf.write(f)
+ debug.out(206, "tyto_domain.ini", cf_uri, False, 0, False)
+ except:
+ debug.out(5, langs.logs.error, cf_uri, True, 2, True)
+
+ cf_write = False
+ cf_load()
+
+ # With new ini file, update ult config file
+ ult_cf_create()
ult_cf.set("DOMAIN", "name", name)
- ult_write = True
-
- cf_hash_c = tools.get_filesum(cf_uri, True)
- if ult_cf.get("DOMAIN", "hash") != cf_hash_c:
- ult_cf.set("DOMAIN", "hash", cf_hash_c)
- ult_write = True
-
- if ult_cf.get("DOMAIN", "root") != wrk_dir:
- ult_cf.set("DOMAIN", "root", wrk_dir)
- ult_write = True
-
- if ult_cf.get("DOMAIN", "conf") != cf_uri:
- ult_cf.set("DOMAIN", "conf", cf_uri)
- ult_write = True
-
- if ult_cf.get("SERVER", "root") != srv:
- ult_cf.set("SERVER", "root", srv)
- ult_write = True
-
- if ult_write:
- with open(ult_cf_uri, "w") as f:
- ult_cf.write(f)
-
-
- # Update User local Domains List File
- #------------------------------------
- ult_dlf_load()
- dlf_write = False
- try:
- dlf_line = ult_dlf.get("DOMAINS", name)
- if dlf_line != wrk_dir:
- dlf_write = True
- except:
- dlf_write = True
-
- if dlf_write:
- ult_dlf.set("DOMAINS", name, wrk_dir)
- with open(ult_dlf_uri, "w") as f:
- ult_dlf.write(f)
+ ult_cf.set("DOMAIN", "directory", wrk_root)
+ ult_cf.set("DOMAIN", "config", cf_uri)
+ ult_cf.set("DOMAIN", "id", tools.get_HID(cf_uri, True))
+ try:
+ with open(ult_cf_uri, "w") as f:
+ ult_cf.write(f)
+ debug.out(206, "%s.ini"%cf_id, ult_cf_uri, False, 0, False)
+ ult_cf_load()
+ except:
+ debug.out(5, "!?", ult_cf_uri, True, 2, True)
+
+ # Add domain to list if not exists yet
+ try:
+ domains_updated = \
+ tools.same_values(ult_domains.get("DOMAINS", name), wrk_root)
+ except:
+ domains_updated = False
+ ult_domains.set("DOMAINS", name, wrk_root)
+
+ if not domains_updated:
+ try:
+ with open(ult_domains_uri, "w") as f:
+ ult_domains.write(f)
+ debug.out(206, "domains.ini", ult_domains_uri, False, 0, False)
+ ult_domains_load()
+ except:
+ debug.out(5, "!?", ult_domains_uri, True, 2, True)
-#========================================#
-# When user wants to (de)activate domain #
-# Update key value and ensure conf is ok # #
-# if activated, check/create wrk dirs #
-#----------------------------------------#
-def userset_status(action):
- do = {
- "start" : "yes",
- "stop" : "no"
- }
-
- tools.update_ini_file(cf_uri, "DOMAIN", "activated", do[action])
- cf_update_values(False)
- ready()
-
- if action == "start":
- status = cf.get("DOMAIN", "activated")
- debug.out(209, "[DOMAIN] activated = %s"%status, cf_uri, True, 0, False)
-
-
-#========================================#
-# (After configuration file was checked) #
-# Exit if domain not activated #
-# #
-# or check/create wrk directories #
-#----------------------------------------#
-def ready():
- if not activated:
- status = cf.get("DOMAIN", "activated")
- debug.out(105, "[DOMAIN] activated = %s"%status, cf_uri, True, 1, True)
-
- for key, directory in cf.items("USER_DIRS"):
- tools.create_dirs(directory)
-
-
-#======#=======================================================================
-# MAIN #
-#------#
-#===================================#
-# Check if current directory exists #
-# Exit Tyto if in black hole... #
-#-----------------------------------#
-try:
- user_dir = os.getcwd() + "/"
- home_dir = os.path.expanduser('~')
-except:
- debug.out(2, "PWD", "?", True, 2, True)
-
-
-#======#
-# main #
-#======#
-#==========================================#
-# utl: $USER/.local/Tyto #
-# cf: Domain Configuration File #
-#------------------------------------------#
-# Domain Configuration directory
-wrk_dir = user_dir.rsplit("articles/")[0]
-wrk_articles = os.path.join(wrk_dir, "articles/")
-wrk_images = os.path.join(wrk_dir, "articles/images/")
-wrk_files = os.path.join(wrk_dir, "articles/files/")
-wrk_tpl = os.path.join(wrk_dir, "template/")
-wrk_mods = os.path.join(wrk_dir, "modules/")
-wrk_db = os.path.join(wrk_dir, ".db/")
-
-# Domain name from current basename directory
-# Exit if not format at least "abc.tld"
-name = os.path.basename(os.path.dirname(wrk_dir))
-
-cf_name = "tyto_domain.ini"
-cf_uri = os.path.join(wrk_dir, cf_name)
-cf_id = tools.get_filesum(cf_uri, False) # ID from URI
-
-# Tyto directory in home local user files
-ult_dir = os.path.join(home_dir, ".local/Tyto/")
-ult_dlf_uri = os.path.join(ult_dir, "domains.ini") # Domains list file
-ult_cf_uri = os.path.join(ult_dir, cf_id + ".ini")
-
-
-#===========================#
-# Templates #==================================================
-#===========================#
#=============================#
-# Domain configuration file #
-# Create file with new domain #
+# Set item in config ini file #
#-----------------------------#
-ini_template = """[DOMAIN]
-activated = no
-name = %s
-title =
-date =
-about =
-tags =
-mail =
-license = gfdl-1.3
-license_url = https://www.gnu.org/licenses/fdl-1.3.txt
+def cf_set(section, key, val, boolean):
+ global cf_write
+
+ # if a new val has to be written, do not deactivate
+ try: cf_write
+ except: cf_write = False
+
+ # Get current val set
+ # if section is not set, create it
+ try:
+ if boolean: cur_val = cf.getboolean(section, key)
+ else: cur_val = cf.get(section, key)
+ except:
+ #no_val = True
+ try: cf.add_section(section)
+ except: pass
+ cur_val = val
+ cf_write = True
+
+ # User set with forms
+ forms_names = ("title", "about", "date", "tags", "mail", "lang")
+ forms_dirs = ("srv_root")
+ if key in forms_names and not cur_val or \
+ key in forms_dirs and not os.path.exists(cur_val):
+ cur_val = user_set(key, cur_val)
+
+ if cf_write:
+ cf.set(section, key, str(cur_val))
+
+ return str(cur_val)
+
+
+#==========================================#
+# Start form from key (if not already set) #
+#------------------------------------------#
+def user_set(key, default):
+ global cf_write, forms
+
+ try: cf_write
+ except: cf_write = False
+ try: forms
+ except:
+ forms = {
+ "title" : form.ask_domain_title,
+ "date" : form.ask_domain_date,
+ "about" : form.ask_domain_about,
+ "tags" : form.ask_domain_tags,
+ "mail" : form.ask_domain_mail,
+ "lang" : form.ask_website_lang,
+ "srv_root" : form.ask_srv_root,
+ }
+
+ for item in forms:
+ if item == key:
+ while True:
+ cur_val = forms[key](default)
+ if cur_val:
+ cf_write = True
+ return cur_val
+
+
+
+#======#
+# Main #=======================================================================
+#======#
+
+# configuration file (.ini) template (tyto_domain.ini)
+ini_cf_tpl = """[DOMAIN]
[WEBSITE]
-www_url =
-wip_url =
-lang =
-css = tyto
-separator = |
-article_code = yes
-static = no
-navbar = yes
[WEBSITE_FOOTER]
-legals_url =
-terms_url =
-bylaws_url =
[WEBSITE_MODULES]
-navbar = yes
-sidebar_title =
-sidebar_items = 6
-rss_items = 100
-sitemaps = yes
[TEMPLATE_FILENAMES]
-favicon = favicon.png
-logo = logo.png
-styles = styles.css
-rss = rss.xml
-stats = tyto_stats.ini
-
-[USER_DIRS]
-root =
-articles =
-images =
-files =
-modules =
-database =
-template =
-
-[USER_TEMPLATE_FILES]
-logo =
-favicon =
-styles =
-
-[USER_MODULES_FILES]
-metas =
-header =
-navbar =
-sidebar =
-footer =
[SERVER]
-root = /var/www/
-domain =
-wip =
-www =
-
-[WIP_DIRS]
-images =
-files =
-template =
-
-[WIP_FILES]
-favicon =
-logo =
-styles =
-rss =
-stats =
-metas =
-header =
-navbar =
-sidebar =
-footer =
-
-[WWW_DIRS]
-images =
-files =
-template =
-
-[WWW_FILES]
-favicon =
-logo =
-styles =
-rss =
-stats =
-metas =
-header =
-navbar =
-sidebar =
-footer =
[TYTO]
-domain_hash =
-domain_conf =
-domain_user =
+"""
+
+# Configuration file (.ini) template (.loacl/Tyto/id.ini)
+ini_ult_tpl = """[DOMAIN]
+"""
+
+# Configuration file (.ini) template (.loacl/Tyto/domains.ini)
+ini_domains = """[DOMAINS]
"""
diff --git a/src/var/lib/tyto/program/feed.py b/src/var/lib/tyto/program/feed.py
new file mode 100644
index 0000000..e015ee3
--- /dev/null
+++ b/src/var/lib/tyto/program/feed.py
@@ -0,0 +1,191 @@
+#!/usr/bin/env python3
+# Tyto - Littérateur
+
+# Copyright (C) 2023 Cyrille Louarn
+
+# 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 ..
+
+#----------------------------------------------------------------------
+# XMPP: echolib (im@echolib.re)
+#
+# Description: Create RSS/feed (when publish only)
+# File: /var/lib/tyto/program/feed.py
+#----------------------------------------------------------------------
+
+import os, configparser, datetime, glob
+import domain, args, debug, tools, langs
+
+
+#=========================================#
+# Create RSS/Feed file in www server only #
+# Only published articles are included #
+# Feed can be deactivated in domain conf #
+#-----------------------------------------#
+def create():
+ max_item = int(domain.cf.get("WEBSITE_MODULES", "rss_items"))
+ if max_item == 0:
+ return
+
+ db_dir = domain.wrk_dirs["db"]
+
+ # Scan DB directory and sort files by last updated
+ items = filter(os.path.isfile, glob.glob(db_dir + '*.ini'))
+ items = sorted(items, key = os.path.getmtime, reverse=True)
+
+ nbr_item = 0
+ feed_items = ""
+ bld_date = tools.nowdate("feed") # General Build date
+
+ for db_uri in items:
+ if nbr_item == max_item:
+ print("MAX")
+ break
+
+ if not check_db(db_uri):
+ continue
+
+ nbr_item += 1
+ pub_date = datetime.datetime.strptime(DB["date"], '%Y-%m-%d').date()
+ pub_date = pub_date.strftime("%a, %d %b %Y")
+
+ feed_item = \
+ feed_item_tpl%(
+ nbr_item, max_item,
+ DB["title"],
+ DB["www_url"],
+ DB["www_url"],
+ pub_date,
+ DB["about"],
+ DB["authors"],
+ DB["logo"],
+ "%s (logo)"%DB["title"],
+ DB["www_url"],
+ DB["tags"]
+ )
+
+
+ if not feed_items: feed_items = feed_item
+ else: feed_items = "%s\n%s"%(feed_items, feed_item)
+
+ feed = \
+ feed_tpl%(
+ bld_date,
+ domain.web["www"] + domain.cf.get("TEMPLATE_FILENAMES", "rss"),
+ domain.conf["title"],
+ domain.web["www"],
+ domain.conf["about"],
+ domain.web["www"] + "template/" + domain.cf.get("TEMPLATE_FILENAMES", "logo"),
+ "%s (logo)"%(domain.conf["title"]),
+ domain.web["www"],
+ domain.lang,
+ domain.conf["tags"],
+ bld_date,
+ domain.cf.get("WEBSITE", "license"),
+ domain.conf["mail"],
+ feed_items
+ )
+
+ feed_uri = domain.www + domain.cf.get("TEMPLATE_FILENAMES", "rss")
+ tools.create_file(feed_uri, feed)
+
+ debug.out(250, "RSS/Feed", feed_uri, True, 0, False)
+
+
+#===============================#
+# Check/Set article DB #
+# Check if article can be added #
+#-------------------------------#
+def check_db(db_uri):
+ global DB
+
+ cf = configparser.ConfigParser()
+ cf.read(db_uri)
+
+ try:
+ DB = {
+ "uri_web" : cf.get("URIS", "web"),
+ "title" : cf.get("ARTICLE", "title"),
+ "about" : cf.get("ARTICLE", "about"),
+ "tags" : cf.get("ARTICLE", "tags"),
+ "date" : cf.get("ARTICLE", "date"),
+ "authors" : cf.get("ARTICLE", "authors"),
+ "logo" : cf.get("ARTICLE", "logo"),
+ "www_url" : cf.get("ARTICLE", "www_url"),
+ "hash_www" : cf.get("HASHES", "www"),
+ "norss" : cf.getboolean("MODULES", "norss"),
+ }
+ except:
+ return False
+
+ if not DB["hash_www"] or DB["norss"]:
+ return False
+
+ return True
+
+
+#======#
+# MAIN #=======================================================================
+#======#
+#=======================#
+# RSS/Feed xml template #
+#-----------------------#
+feed_tpl = """
+
+
+
+
+
+
+
+
+
+
+
+ %s
+ %s
+ %s
+ '
+ %s
+ %s
+ %s
+
+ %s
+ %s
+ %s
+ %s
+ %s
+ Tyto - Littérateur
+
+
+%s
+
+
+
+"""
+
+feed_item_tpl = """
+ -
+
%s
+ %s
+ %s
+ %s
+ %s
+ %s
+
+ %s
+ %s
+ %s
+
+ %s
+ """
diff --git a/src/var/lib/tyto/program/form.py b/src/var/lib/tyto/program/form.py
new file mode 100644
index 0000000..6ef9345
--- /dev/null
+++ b/src/var/lib/tyto/program/form.py
@@ -0,0 +1,179 @@
+#!/usr/bin/env python3
+# Tyto - Littérateur
+
+# Copyright (C) 2023 Cyrille Louarn
+
+# 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 ..
+
+#----------------------------------------------------------------------
+# XMPP: echolib (im@echolib.re)
+#
+# Description: Manage forms. When a question is asked.
+# File: /var/lib/tyto/program/forms.py
+#----------------------------------------------------------------------
+
+import os, sys
+import langs, domain, debug, tools
+
+
+#======================================================#
+# Ask a question #
+# in yes_mod, value is from local langs.logs.ok values #
+# has a keyboad interrupt #
+#------------------------------------------------------#
+def ask(q, yes_mod, default):
+ answer = expected = ""
+ if yes_mod:
+ expected = langs.logs.ok
+
+ try:
+ answer = input(q)
+ except KeyboardInterrupt:
+ print()
+ debug.out(99, q, expected, False, 2, True)
+
+ if yes_mod:
+ for ok in expected:
+ if answer.lower() == ok.lower():
+ return True
+ debug.out(199, q, expected, True, 1, True)
+
+ if default and not answer: return default
+ elif not answer: return False
+
+ return answer
+
+
+#=========================#
+# Confirm domain creation #
+#-------------------------#
+def ask_domain_creation():
+ q = '- %s "%s"%s '%(
+ langs.logs.ask_domain_name, domain.name, langs.logs.q)
+
+ # Create domain configuration file
+ if ask(q, True, ""):
+ domain.cf_create()
+
+
+#=================================================#
+# Forms #
+# Each questions are asked from domain.user_set() #
+# In mismatch case, question is asked again #
+#-------------------------------------------------#
+#======================#
+# Ask for domain title #
+#----------------------#
+def ask_domain_title(default):
+ q = '- %s "%s"%s '%(
+ langs.logs.ask_domain_title, default, langs.logs.q)
+
+ return ask(q, False, default) or ""
+
+
+#==============================#
+# Ask for domain creation date #
+#------------------------------#
+def ask_domain_date(default):
+ default = tools.nowdate("int-short").rsplit("-")[0] # Set year only
+ debug.out(101, "[YYYY[-MM][-DD]]", "", True, 0, False)
+ q = '- %s "%s"%s '%(
+ langs.logs.ask_domain_date, default, langs.logs.q)
+
+ return ask(q, False, default) or ""
+
+
+#============================#
+# Ask for domain description #
+#----------------------------#
+def ask_domain_about(default):
+ q = '- %s "%s"%s '%(
+ langs.logs.ask_domain_about, default, langs.logs.q)
+
+ return ask(q, False, default) or ""
+
+
+#=====================#
+# Ask for domain tags #
+#---------------------#
+def ask_domain_tags(default):
+ default = domain.cf.get("DOMAIN", "title") + ","
+ q = '- %s "%s"%s '%(
+ langs.logs.ask_domain_tags, default, langs.logs.q)
+
+ return ask(q, False, default) or ""
+
+
+#============================#
+# Ask for administrator mail #
+#----------------------------#
+def ask_domain_mail(default):
+ q = '- %s "%s"%s '%(
+ langs.logs.ask_domain_mail, default, langs.logs.q)
+
+ return ask(q, False, default) or ""
+
+
+#=============================#
+# Ask for wzbsite language #
+# Check if translation exists #
+#-----------------------------#
+def ask_website_lang(default):
+ default = langs.logs_lang
+
+ q = '- %s "%s"%s '%(
+ langs.logs.ask_website_lang, default, langs.logs.q)
+
+ lang = ask(q, False, default)
+ if not os.path.exists(langs.lang_files["site"]["uri"]%lang):
+ debug.out(8, lang, langs.lang_files["site"]["uri"]%lang, True, 2, False)
+ lang = ""
+
+ return lang
+
+
+#===============================#
+# Ask for server root directory #
+# Check if directory exists #
+#-------------------------------#
+def ask_srv_root(default):
+ srv_uris = (default, "/var/www/", "/srv/http/")
+ for srv_uri in srv_uris:
+ if os.path.exists(srv_uri):
+ default = srv_uri
+ break;
+
+ q = '- %s "%s"%s '%(
+ langs.logs.ask_srv_root, default, langs.logs.q)
+
+ srv_uri = ask(q, False, default)
+ if srv_uri:
+ if not srv_uri.endswith("/"):
+ srv_uri = srv_uri + "/"
+ if not os.path.exists(srv_uri):
+ debug.out(6, q, srv_uri, True, 2, False)
+ srv_uri = ""
+
+ return srv_uri
+
+
+#
+#
+#
+def ask_reset_modules():
+ q = "- %s%s "%(langs.logs.ask_reset_modules, langs.logs.q)
+
+ if ask(q, True, ""):
+ return
+
diff --git a/src/var/lib/tyto/program/help.py b/src/var/lib/tyto/program/help.py
index 5974fc9..6077eba 100644
--- a/src/var/lib/tyto/program/help.py
+++ b/src/var/lib/tyto/program/help.py
@@ -14,30 +14,64 @@
# 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 .
+# along with this program. If not, see ..
#----------------------------------------------------------------------
-# XMPP: echolib > im@echolib.re
+# XMPP: echolib (im@echolib.re)
#
-# Description: Show help commands
+# Description: Show help, and manage some arguments with it
# File: /var/lib/tyto/program/help.py
#----------------------------------------------------------------------
-#-------------------------
-# Funny Stats Project
-#-------------------------
-# file lines :
-# file comments :
-# file functions:
-# file program :
-#--------------------------
+import sys
+import args, langs
-import langs, debug
+#
+#
+#
+def manage():
+ helps = {
+ "new" : langs.logs.help_new,
+ "check" : langs.logs.help_check,
+ "wip" : langs.logs.help_wip,
+ "modules" : langs.logs.help_modules,
+ "list" : langs.logs.help_list,
+ "cite" : langs.logs.help_cite,
+ "image" : langs.logs.help_image,
+ "link" : langs.logs.help_link,
+ "file" : langs.logs.help_file,
+ "code" : langs.logs.help_code,
+ "words" : langs.logs.help_words,
+ "abbr" : langs.logs.help_abbr,
+ "anchor" : langs.logs.help_anc,
+ "raw" : langs.logs.help_raw,
+ "article" : langs.logs.help_article,
+ }
+ norepeat = \
+ (
+ "list", "cite", "image", "link", "words", "code", "raw", "abbr", "anchor",
+ "file",
+ )
-#==========================================#
-# Show help in system langage #
-# Help Contents is in translations/logs_XX #
-#------------------------------------------#
-def show(action, target):
- print(langs.logs.help_contents)
+ try:
+ sys.argv[2]
+ if not sys.argv[2] in helps: show_main = True
+ else: show_main = False
+ except:
+ show_main = True
+
+ if show_main:
+ print(langs.logs.help_man)
+
+ if args.commands["targets"]["all"]:
+ for h in helps:
+ if not h in norepeat:
+ print(helps[h])
+ return
+
+ for arg in range(2, len(sys.argv)):
+ if sys.argv[arg] in helps:
+ print(helps[sys.argv[arg]])
+
+
diff --git a/src/var/lib/tyto/program/langs.py b/src/var/lib/tyto/program/langs.py
index 636b9b4..1f2a69f 100644
--- a/src/var/lib/tyto/program/langs.py
+++ b/src/var/lib/tyto/program/langs.py
@@ -14,127 +14,65 @@
# 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 .
+# along with this program. If not, see ..
#----------------------------------------------------------------------
-# XMPP: echolib > im@echolib.re
+# XMPP: echolib (im@echolib.re)
#
-# Description: Load lang logs file according to system language
-# Load lang site file according to domain configuration
+# Description: Set languages for logs and website
# File: /var/lib/tyto/program/langs.py
#----------------------------------------------------------------------
-#-------------------------
-# Funny Stats Project
-#-------------------------
-# file lines :
-# file comments :
-# file functions:
-# file program :
-#--------------------------
-
-import sys, locale, os
-import args, debug, domain
+import locale
+import domain
-trfs = "/var/lib/tyto/translations/"
+# Settings files
+def set_lang_files():
+ global lang_files, files_set
-#==================================#
-# Check if translation file exists #
-# module: #
-# - "logs": logs_xx #
-# - "website": website_xx #
-# lang: 2 chars language #
-# out: exit if True
-# return True or False #
-#----------------------------------#
-def translation_exists(module, lang, out):
- global tr_file
-
- modules = ("logs", "website")
- # in case of internal typo error
- if not module in modules:
- print("! langs: internal error: 'logs', 'website'")
- sys.exit(254)
-
- tr_file = "%s%s_%s.py"%(trfs, module, lang)
- if not os.path.exists(tr_file):
- debug.out(5, lang, tr_file, True, 2, False)
- return False
-
- return True
+ lang_files = \
+ {
+ "logs" : {
+ "name" : "logs_%s",
+ "uri" : "/var/lib/titi/translations/logs_%s.py",
+ },
+ "site" : {
+ "name" : "site_%s",
+ "uri" : "/var/lib/titi/translations/site_%s.py",
+ },
+ }
+
+ files_set = True
-#=============================================================================#
-# LOGS | #
-# Set and import file | #
-#=============================================================================#
-#=============================#
-# Get system Lang to set logs #
-#-----------------------------#
-def get_sys_lang():
- global lang, tr_logs_uri
-
- tr_logs_uri = "%slogs_%s.py"
-
- try: lang = locale.getdefaultlocale()[0].rsplit("_")[0]
- except: lang = "en"
-
- if not translation_exists("logs", lang, False):
- lang = "en"
-
- tr_logs_uri = tr_logs_uri%(trfs, lang)
-
- return lang
+# Use logs from system language or default "en"
+def load_logs():
+ global logs, logs_lang, logs_uri
+ set_lang_files()
-#===============================#
-# Import logs lang file in logs #
-#-------------------------------#
-def load_logs_lang():
- global logs, lang, set_logs
-
try:
- set_logs
+ logs_lang = locale.getdefaultlocale()[0].rsplit("_")[0]
except:
- logs = __import__("logs_%s"%get_sys_lang())
- debug.out(201, lang, tr_logs_uri, False, 0, False)
- set_logs = True
+ logs_lang = "en"
+
+ # Load language file
+ logs_name = lang_files["logs"]["name"]%logs_lang
+ logs_uri = lang_files["logs"]["uri"]%logs_lang
+ logs = __import__(logs_name)
-#=============================================================================#
-# WEBSITE | #
-# Get/Set and import file | #
-#=============================================================================#
-#=======================================#
-# Get website lang from cf to set site #
-#---------------------------------------#
-def get_website_lang():
- global site_lang, tr_website_uri
+# loan language website values
+def load_site():
+ global site
- tr_website_uri = "%swebsite_%s.py"
- try: site_lang = domain.cf.get("WEBSITE", "lang")
- except: site_lang = get_sys_lang()
+ try: files_set
+ except: set_lang_files()
- if not translation_exists("website", site_lang, False):
- site_lang = get_sys_lang() # or default "en"
-
- tr_website_uri = tr_website_uri%(trfs, site_lang)
-
- return site_lang
+ try: site_lang = domain.lang
+ except: site_lang = "en"
+ try: site = __import__(lang_files["site"]["name"]%site_lang)
+ except: site = __import__(lang_files["site"]["name"]%"en")
-#==================================#
-# Import website lang file in site #
-#----------------------------------#
-def load_website_lang():
- global site, site_lang, set_site
-
- site = __import__("website_%s"%get_website_lang())
-
- try:
- set_site
- except:
- debug.out(208, site_lang, tr_website_uri, False, 0, False)
- set_site = True
-
diff --git a/src/var/lib/tyto/program/modules.py b/src/var/lib/tyto/program/modules.py
new file mode 100644
index 0000000..b689711
--- /dev/null
+++ b/src/var/lib/tyto/program/modules.py
@@ -0,0 +1,601 @@
+#!/usr/bin/env python3
+# Tyto - Littérateur
+
+# Copyright (C) 2023 Cyrille Louarn
+
+# 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 ..
+
+#----------------------------------------------------------------------
+# XMPP: echolib (im@echolib.re)
+#
+# Description: Manage modules creations (metas, to footer called by nginx)
+# File: /var/lib/tyto/program/modules.py
+#----------------------------------------------------------------------
+
+import os, ast, configparser
+import args, domain, langs, tools, debug, form
+
+
+#=================================================#
+# Manage modules creations #
+# metas, header, navbar, sidebar, footer #
+# - User must configure: navbar, sidebar #
+# - Default contents: metas, header, footer #
+# From [module].raw, create [module].html #
+# All are called from file with nginx in web page #
+#-------------------------------------------------#
+def manage(module):
+ global files, wrk_dir, asked, mod_write, wip_dir
+
+ # Set directories
+ wrk_dir = domain.wrk_dirs["modules"]
+ wip_dir = domain.wip_dirs["template"]
+ www_dir = domain.www_dirs["template"]
+
+ debug.out(212, module, wrk_dir, False, 0, False)
+
+ files = {
+ "metas" : {
+ "wrk" : wrk_dir + "metas.raw",
+ "wip" : wip_dir + "metas.html",
+ "www" : www_dir + "metas.html",
+ "set" : set_metas_raw,
+ },
+ "header" : {
+ "wrk" : wrk_dir + "header.raw",
+ "wip" : wip_dir + "header.html",
+ "www" : www_dir + "header.html",
+ "set" : set_header_raw,
+ },
+ "navbar" : {
+ "wrk" : wrk_dir + "navbar.raw",
+ "wip" : wip_dir + "navbar.html",
+ "www" : www_dir + "navbar.html",
+ "set" : set_navbar_raw,
+ },
+ "sidebar" : {
+ "wrk" : wrk_dir + "sidebar.raw",
+ "wip" : wip_dir + "sidebar.html",
+ "www" : www_dir + "sidebar.html",
+ "set" : set_sidebar_raw,
+ },
+ "footer" : {
+ "wrk" : wrk_dir + "footer.raw",
+ "wip" : wip_dir + "footer.html",
+ "www" : www_dir + "footer.html",
+ "set" : set_footer_raw,
+ },
+ }
+
+ # Load/Create new modules in DB file
+ cf_mod_load()
+ mod_write = False
+
+ # Check/Set raw files in modules/
+ for mod in files:
+ # For all modules to reset, confirm once
+ if os.path.exists(files[mod]["wrk"]):
+ if module == "all":
+ try: asked
+ except: form.ask_reset_modules() ; asked = True
+
+ elif mod != module:
+ continue
+
+ mod_write = True
+ files[mod]["set"](mod)
+ tools.create_file(files[mod]["wrk"], files[mod]["usr"])
+ cid = tools.get_HID(files[mod]["wrk"], True)
+ cf_mod_set("RAWS", mod, cid)
+
+ cf_mod_write()
+ if args.action == "new":
+ debug.out(250, module, wrk_dir, True, 0, False)
+
+ # When an article is "wip"
+ # - create html modules
+ # - - if not already exists
+ # - - if raw module has changed
+ if module == "wip":
+ for mod in files:
+ if os.path.exists(files[mod]["wip"]):
+ raw_cid = tools.get_HID(files[mod]["wrk"], True)
+ try: db_id = cf_mod.get("RAWS", mod)
+ except: db_id = ""
+ if raw_cid == db_id:
+ continue
+ else:
+ cf_mod_set("RAWS", mod, raw_cid)
+ mod_write = True
+
+ create_htmls(mod)
+
+ cf_mod_write()
+
+ # When user wants to force update HTML modules
+ # using wip [MODULE] ; called in wip.py
+ elif module == "update":
+ # Create again ALL modules in wip/template
+ if args.commands["modules"]["modules"]:
+ for mod in files:
+ if os.path.exists(files[mod]["wip"]):
+ create_htmls(mod)
+ # Create again specific module from command line
+ else:
+ for mod in args.commands["modules"]:
+ if args.commands["modules"][mod]:
+ if os.path.exists(files[mod]["wip"]):
+ create_htmls(mod)
+
+
+#=======================================#
+# Manage modules configuration ini file #======================================
+#---------------------------------------#
+#================================#
+# Create new modules DB ini file #
+#--------------------------------#
+def cf_mod_load():
+ global cf_mod_uri, cf_mod
+
+ cf_mod_uri = wrk_dir + "modules.ini"
+
+ if not os.path.exists(cf_mod_uri):
+ tools.create_file(cf_mod_uri, "")
+
+ cf_mod = False
+ cf_mod = configparser.ConfigParser()
+ cf_mod.read(cf_mod_uri)
+
+
+#============================#
+# Set datas to cf_mod ini DB #
+#----------------------------#
+def cf_mod_set(section, key, value):
+ global cf_mod
+
+ # Add section if not exists
+ try: cf_mod.add_section(section)
+ except: pass
+
+ cf_mod.set(section, key, value)
+
+
+#==================================#
+# Write to cf_mod ini DB if needed #
+#----------------------------------#
+def cf_mod_write():
+ if mod_write:
+ with open(cf_mod_uri, "w") as f:
+ cf_mod.write(f)
+
+
+#==================================================#
+# Create default raw modules in modules/ directory #===========================
+#--------------------------------------------------#
+#=====================================#
+# Set metas.raw with default contents #
+#-------------------------------------#
+def set_metas_raw(mod):
+ global files
+
+ files["metas"]["usr"] = langs.logs.metas_raw%(
+ domain.conf["title"],
+ domain.wrk_dirs["articles"],
+ files[mod]["wrk"],
+ files[mod]["wip"],
+ files[mod]["www"],
+ ) + metas_raw
+
+
+#======================================#
+# Set header.raw with default contents #
+#--------------------------------------#
+def set_header_raw(mod):
+ global files, header_raw
+
+ # ----------------------------------- #
+ # Fille values for generic header_raw #
+ # ----------------------------------- #
+ header_raw = \
+ header_raw%(
+ "%s %s"%(langs.site.home, domain.conf["title"]),
+ "/template/%s"%domain.cf.get("TEMPLATE_FILENAMES", "logo"),
+ "logo: %s"%domain.conf["title"],
+ domain.conf["title"],
+ domain.conf["about"]
+ )
+
+ files["header"]["usr"] = langs.logs.header_raw%(
+ domain.conf["title"],
+ domain.wrk_dirs["articles"],
+ files[mod]["wrk"],
+ files[mod]["wip"],
+ files[mod]["www"],
+ ) + header_raw
+
+#===============================#
+# Set navbar.raw with help only #
+#-------------------------------#
+def set_navbar_raw(mod):
+ global files
+
+ files["navbar"]["usr"] = langs.logs.metas_raw%(
+ domain.conf["title"],
+ domain.wrk_dirs["articles"],
+ files[mod]["wrk"],
+ files[mod]["wip"],
+ files[mod]["www"],
+ )
+
+
+#================================#
+# Set sidebar.raw with help only #
+#--------------------------------#
+def set_sidebar_raw(mod):
+ global files
+
+ files["sidebar"]["usr"] = langs.logs.sidebar_raw%(
+ domain.conf["title"],
+ domain.wrk_dirs["articles"],
+ files[mod]["wrk"],
+ files[mod]["wip"],
+ files[mod]["www"],
+ )
+
+#======================================#
+# Set footer.raw with default contents #
+#--------------------------------------#
+def set_footer_raw(mod):
+ global files, footer_raw
+
+ # ---------------------------------- #
+ # Fill values for generic footer_raw #
+ # ---------------------------------- "
+ footer_menu = ""
+ footer_link = \
+ '\n'
+
+ for key, value in domain.cf.items("WEBSITE_FOOTER"):
+ try:
+ tupvalues = ast.literal_eval(value)
+ footer_menu = footer_menu + \
+ footer_link%(tupvalues[1], tupvalues[2], "", tupvalues[0])
+ except:
+ debug.out(102, "%s = %s"%(key, value), domain.cf_uri, True, 1, False)
+
+ if domain.conf["sitemaps"]:
+ footer_menu = footer_menu + \
+ footer_link%(
+ "/sitemap.html",
+ langs.site.sitemap, domain.conf["title"],langs.site.sitemap
+ )
+
+ footer_menu = footer_menu + \
+ footer_link%(
+ "/" + domain.cf.get("TEMPLATE_FILENAMES", "rss"),
+ langs.site.feed_rss, domain.conf["title"], langs.site.feed_rss
+ )
+
+ # Copyright link
+ cur_date = tools.nowdate("year")
+ if domain.conf["date"][:4] != cur_date:
+ cur_date = "%s - %s"%(domain.conf["date"][:4], cur_date)
+ footer_copy = "Copyright © %s %s"%(cur_date, domain.conf["title"])
+
+ # Tyto credit links
+ tyto_site_link = "https://tyto.echolib.re/"
+ tyto_code_link = "https://forge.a-lec.org/echolib/tyto-litterateur"
+ footer_tyto = \
+ '%s ['%tyto_code_link + \
+ '%s'%langs.site.source_code + \
+ ' ]'
+
+ # Create full footer_raw contents
+ footer_raw = footer_raw%(
+ #
+ langs.site.about, domain.conf["title"],
+ # About
+ domain.conf["about"],
+ # Menu list items
+ footer_menu,
+ # Copyright and Tyto credit
+ footer_copy,
+ footer_tyto,
+ )
+
+ files["footer"]["usr"] = langs.logs.footer_raw%(
+ domain.conf["title"],
+ domain.wrk_dirs["articles"],
+ files[mod]["wrk"],
+ files[mod]["wip"],
+ files[mod]["www"],
+ ) + footer_raw
+
+
+#===================================================#
+# Create HTML modules files in template/ wip only #============================
+# At publish process, files are copied, not created #
+#---------------------------------------------------#
+#============================#
+# Create [module].html files #
+#----------------------------#
+def create_htmls(mod):
+ html_file = ""%(mod, mod)
+
+ if mod == "navbar":
+ html_file = create_navbar_html(html_file)
+
+ elif mod == "sidebar":
+ html_file = create_sidebar_html(html_file)
+
+ else:
+ with open(files[mod]["wrk"], "r") as f:
+ for line in f.read().rsplit("\n"):
+ if not line or line.isspace() or line.lstrip().startswith("#"):
+ continue
+
+ html_file = "%s\n%s"%(html_file, line)
+
+ tools.create_file(files[mod]["wip"], html_file)
+ debug.out(250, mod, wip_dir, True, 0, False)
+
+
+#==============================================#
+# Create HTML navbar contents, from navbar.raw #
+#----------------------------------------------#
+def create_navbar_html(html_file):
+ menu_links = ""
+ with open(files["navbar"]["wrk"], "r") as f:
+ for ln, line in enumerate(f.read().rsplit("\n"), 1):
+ line = line.lstrip()
+ if not line or line.isspace() or line.startswith("#"):
+ continue
+
+ # Item has a "title" set with # as separator
+ set_dir = line.rstrip()
+
+
+ # Set_dir begins with "/" ; apply correction
+ if set_dir.startswith("/"): set_dir = set_dir[1:]
+ if set_dir.endswith("/"): set_dir = set_dir[:-1]
+ if not set_dir: # No home / in navbar menu
+ continue
+
+ dir_uri = domain.wrk_dirs["articles"] + set_dir
+
+ # Set_dir must exists
+ if not os.path.exists(dir_uri) or \
+ not os.path.isdir(dir_uri):
+ debug.out(6, "%s. navbar '%s'"%(
+ ln, set_dir
+ ), files["navbar"]["wrk"], True, 1, False)
+ continue
+
+ # Check for index.tyto, load DB if exists, get title
+ if cf_load(ln, set_dir + "/index.tyto", "navbar"):
+ try: set_title = cf.get("ARTICLE", "title")
+ except: continue
+
+ # Check and inform if not index.html exists
+ srv_index_html = domain.wip + "/index.html"
+ if not os.path.exists(srv_index_html):
+ debug.out(11, "%s. navbar (404) wip/%s/index.html"%(
+ ln, set_dir
+ ), files["navbar"]["wrk"], True, 1, False)
+
+ # Create menu links
+ if not menu_links:
+ menu_links = navbar_link%(
+ "/" + set_dir, set_title, os.path.basename(set_dir)
+ )
+ else:
+ menu_links = "%s\n%s"%(
+ menu_links,
+ navbar_link%(
+ "/" + set_dir, set_title, os.path.basename(set_dir)
+ )
+ )
+
+ if menu_links:
+ html_file = html_file + navbar_html%menu_links
+
+ return html_file
+
+
+#================================================#
+# Create HTML sidebar contents, from sidebar.raw #
+#------------------------------------------------#
+def create_sidebar_html(html_file):
+ # Set from config file max links. Return if 0
+ max_items = int(domain.cf.get("WEBSITE_MODULES", "sidebar_items"))
+ sidebar_title = domain.cf.get("WEBSITE_MODULES", "sidebar_title")
+ if max_items == 0:
+ return html_file
+
+ html_items = ""
+ items = 0
+ with open(files["sidebar"]["wrk"], "r") as f:
+ for ln, line in enumerate(f.read().rsplit("\n"), 1):
+ if items == max_items:
+ break
+
+ line = line.lstrip()
+ if not line or \
+ line.isspace() or \
+ line.startswith("#") or \
+ not line.endswith(".tyto"):
+ continue
+
+ # Target begins with "/"... Remove it
+ if line.startswith("/"): line = line[1:]
+
+ # check/load article files
+ if not cf_load(ln, line, "sidebar"):
+ continue
+
+ items += 1
+ print("> -",items, cf.get("ARTICLE", "title"))
+
+ if not html_items:
+ html_items = sidebar_item%(
+ #
+ cf.get("URIS", "web"),
+ cf.get("ARTICLE", "title"),
+ #
+ cf.get("ARTICLE", "title"),
+ cf.get("ARTICLE", "authors"),
+ cf.get("ARTICLE", "local_date"),
+ # Show about
+ cf.get("ARTICLE", "about")
+ )
+ else:
+ html_items = "%s\n%s"%(html_items, sidebar_item%(
+ cf.get("ARTICLE", "title"),
+ cf.get("ARTICLE", "about")
+ )
+ )
+
+ if html_items:
+ html_file = html_file + sidebar_html%(sidebar_title, html_items)
+
+ return html_file
+
+
+#==========================================#
+# Get DB post from URI, and load if exists #
+#------------------------------------------#
+def cf_load(ln, line, modname):
+ global cf
+
+ uri = domain.wrk_dirs["articles"] + line
+ if not os.path.exists(uri):
+ debug.out(11, "%s. %s '%s'"%(
+ ln, modname, line
+ ), files[modname]["wrk"], True, 1, False)
+ return False
+
+ db_uri = domain.wrk_dirs["db"] + tools.get_HID(uri, False) + ".ini"
+ if not os.path.exists(db_uri):
+ debug.out(12, "%s. %s '%s'"%(
+ ln, modname, line
+ ), files[modname]["wrk"], True, 1, False)
+ return False
+
+ cf = configparser.ConfigParser()
+ cf.read(db_uri)
+
+ try: srv_uri = cf.get("URIS", "wip")
+ except: srv_uri = ""
+ if not srv_uri or not os.path.exists(srv_uri):
+ debug.out(13, "%s. %s '%s'"%(
+ ln, modname, line
+ ), files[modname]["wrk"], True, 1, False)
+ return False
+
+ return True
+
+
+#===============#
+# MAIN settings #==============================================================
+#---------------#
+# ---------------------------- #
+# Default raw modules contents #
+# ---------------------------- #
+#-------#
+# Metas #
+#-------#
+metas_raw = """
+
+
+
+
+
+"""
+
+#--------#
+# Header #
+#--------#
+header_raw = """
+
+
+"""
+
+#--------#
+# Navbar #
+#--------#
+navbar_html = """
+
+"""
+navbar_link = '
'
+
+#---------#
+# Sidebar #
+#---------#
+sidebar_html = """
+
+"""
+sidebar_item = """"""
+
+#--------#
+# Footer #
+#--------#
+footer_raw = """
+
+"""
diff --git a/src/var/lib/tyto/program/new.py b/src/var/lib/tyto/program/new.py
index 558aa6c..25ac0f4 100644
--- a/src/var/lib/tyto/program/new.py
+++ b/src/var/lib/tyto/program/new.py
@@ -14,60 +14,37 @@
# 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 .
+# along with this program. If not, see ..
#----------------------------------------------------------------------
-# XMPP: echolib > im@echolib.re
+# XMPP: echolib (im@echolib.re)
#
-# Description: When user wants to create something new
+# Description: When something new must be created (domain, modules...)
# File: /var/lib/tyto/program/new.py
#----------------------------------------------------------------------
-#-------------------------
-# Funny Stats Project
-#-------------------------
-# file lines :
-# file comments :
-# file functions:
-# file program :
-#--------------------------
+import args, domain, form, modules, sitemap
-import os
-import args, domain, debug, sitemaps
-
-
-#====================================#
-# Manage arguments from command line #
-# Specific to action "new" #
-#------------------------------------#
-def manage(action, target):
- do = {
- "domain" : create_domain,
- "sitemaps" : sitemaps.manage,
- }
-
- do[target]()
-
-
-
-#===================================#
-# From command line "new domain" #
-# Create and set only if not exists #
-# or if user "force" option
-#-----------------------------------#
-def create_domain():
- # Check if in a domain set yet
- d_uri = "/"
- dirs = domain.user_dir.rsplit("/")
- for d in dirs:
- if not d:
- continue
+def manage():
+ if args.commands["targets"]["domain"]:
+ domain.set_name()
- d_uri = d_uri + d + "/"
- if os.path.exists(d_uri + "tyto_domain.ini"):
- debug.out(202, d, d_uri, True, 2, True)
+ if not domain.cf_exists():
+ form.ask_domain_creation()
- domain.cf_create()
+ domain.cf_load()
+ domain.cf_update()
+ return
+ domain.is_ready()
+ if args.commands["modules"]["modules"]:
+ modules.manage("all")
+ return
-
+ args.commands["modules"]["metas"] and modules.manage("metas")
+ args.commands["modules"]["header"] and modules.manage("header")
+ args.commands["modules"]["navbar"] and modules.manage("navbar")
+ args.commands["modules"]["sidebar"] and modules.manage("sidebar")
+ args.commands["modules"]["footer"] and modules.manage("footer")
+
+ args.commands["modules"]["sitemap"] and sitemap.create()
diff --git a/src/var/lib/tyto/program/page.py b/src/var/lib/tyto/program/page.py
new file mode 100644
index 0000000..8867375
--- /dev/null
+++ b/src/var/lib/tyto/program/page.py
@@ -0,0 +1,219 @@
+#!/usr/bin/env python3
+# Tyto - Littérateur
+
+# Copyright (C) 2023 Cyrille Louarn
+
+# 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 ..
+
+#----------------------------------------------------------------------
+# XMPP: echolib (im@echolib.re)
+#
+# Description: Create full HTML page
+# File: /var/lib/tyto/program/page.py
+#----------------------------------------------------------------------
+
+import os
+import domain, post, wip, langs, tools
+
+
+#========================================#
+# Main function to create Full HTML Page #
+#----------------------------------------#
+def create():
+ global pub_date, article, local_date
+
+ pub_date = tools.nowdate("int-full")
+ local_date = tools.local_date(post.needed_tags["date"])
+
+ # Create specific article metas tags
+ post_metas = article_metas()
+
+ # Create references in div
+ post_refs = article_refs()
+
+ # Create full HTML page
+ article = template%(
+ # First line comment
+ post.needed_tags["title"], domain.conf["title"],
+ # lang=""
+ domain.lang,
+ # nginx metas
+ nginx_mods%"metas",
+ # metas
+ post_metas,
+ # nginx header, navbar
+ nginx_mods%"header",
+ nginx_mods%"navbar",
+ #
+ pub_date,
+ # h1 Main Title link
+ post.datas["www_url"],
+ post.needed_tags["title"], post.needed_tags["authors"], local_date,
+ post.needed_tags["title"],
+ # article references
+ post_refs,
+ # Article contents
+ wip.html_article,
+ # nginx sidebar
+ nginx_mods%"sidebar",
+ # nginx footer
+ nginx_mods%"footer",
+ )
+
+
+#======================================#
+# Create all '
+ pub_date,
+ post.needed_tags["title"],
+ post.needed_tags["authors"],
+ domain.cf.get("WEBSITE", "separator"),
+ domain.conf["title"]
+ )
+
+ return post_metas
+
+
+#========================================#
+# Create div inclding article references #
+# In template, is put under main title #
+#----------------------------------------#
+def article_refs():
+ link_post_code = ""
+ if domain.conf["post_code"]:
+ link_post_code = \
+ ' [%s ]'%(
+ domain.web["css"], post.datas["src_file"],
+ langs.site.source_code, langs.logs.pp, post.needed_tags["title"],
+ langs.site.source_code
+ )
+
+ post_refs = template_refs%(
+ post.needed_tags["authors"], local_date, link_post_code
+ )
+
+ return post_refs
+
+
+#===============#
+# MAIN settings #==============================================================
+#---------------#
+nginx_mods = ''
+
+template = """
+
+
+
+%s
+%s
+
+
+
+
+
+%s
+%s
+
+
+
+
+
+
+%s
+
+
+
+%s
+
+
+
+%s
+
+
+
+
+
+"""
+
+template_metas = """
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%s (%s) %s %s """
+
+# Article referencies (author, date, source code)
+template_refs = """
+%s, %s%s
+
"""
diff --git a/src/var/lib/tyto/program/post.py b/src/var/lib/tyto/program/post.py
index d8f2405..a5f611b 100644
--- a/src/var/lib/tyto/program/post.py
+++ b/src/var/lib/tyto/program/post.py
@@ -14,581 +14,266 @@
# 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 .
+# along with this program. If not, see ..
#----------------------------------------------------------------------
-# XMPP: echolib > im@echolib.re
+# XMPP: echolib (im@echolib.re)
#
-# Description: About post (from target) database, uri...
-# File: /var/lib/tyto/program/new.py
+# Description: Manage datas and DB from/for article
+# File: /var/lib/tyto/program/post.py
#----------------------------------------------------------------------
-#-------------------------
-# Funny Stats Project
-#-------------------------
-# file lines :
-# file comments :
-# file functions:
-# file program :
-#--------------------------
-
-import os, sys, configparser
-import args, domain, debug, tools, tyto, check
+import os, configparser
+import args, domain, debug, tools
-error = 0
-write = False # When updating database in cf_set(), cf_write()
+#=============================================================#
+# Set full article file URI from current directory and target #
+#-------------------------------------------------------------#
+def set_uri(target):
+ global uri, uid, db, db_uri
+
+ if target == "sitemap.tyto" or args.commands["targets"]["all"]:
+ domain.user_dir = domain.wrk_dirs["articles"]
+
+ uri = domain.user_dir + target
+ uid = tools.get_HID(uri, False)
+
+ # DB exists ?
+ db_uri = domain.wrk_dirs["db"] + uid + ".ini"
+ db = bool(os.path.exists(db_uri))
-#============================================#
-# Check if current directory is in articles/ #
-# Check if article from target exists #
-# Set post configuration file database #
-# load database #
-#--------------------------------------------#
-def is_article(target):
- global error
-
- debug.out(211, '"%s"'%target, "", False, 0, False)
+#=====================================#
+# Exit if article file does not exist #
+#-------------------------------------#
+def exists(target):
+ found = bool(os.path.exists(uri))
+ found or debug.out(11, "!?", uri, True, 2, True)
- # User MUST be in articles/
- domain.user_dir.startswith(domain.wrk_articles) or \
- debug.out(2, "-> articles/", domain.wrk_articles, True, 2, True)
-
- # Target URI most be from legacy directory or not begins with
- if target.startswith(tyto.notarget):
- error = debug.out(20, "./, ../", target, True, 2, False)
- return False
-
- # Article exists
- global uri
- if args.targets: cur_dir = domain.wrk_articles
- else: cur_dir = domain.user_dir
- uri = os.path.join(cur_dir, target)
- if not os.path.exists(uri):
- error = debug.out(5, "False", uri, True, 2, False)
- return False
-
- # Article is a Tyto format and not empty (exit on errors)
- if not is_tyto_format():
- return False
-
- global uri_id, wrk_id, cf_uri, wrk_target, web_target
- # Set post ID from...
- uri_id = tools.get_filesum(uri, False) # ...URI
- wrk_id = tools.get_filesum(uri, True) # ...CONTENTS
-
- # Set post configuration file database
- cf_uri = os.path.join(domain.wrk_db, uri_id + ".ini")
-
- # Set target from articles/
- wrk_target = uri.rsplit(domain.wrk_articles)[1]
-
- # Set web target, replace last .tyto with .html
- web_target = wrk_target[:-4] + "html"
-
- # Load Database, get and compare values
- cf_load()
- cf_datas()
- compare_datas()
-
- return True
-
-
-#=========================================#
-# Article is in Tyto format and not empty #
-# Return True or False #
-#-----------------------------------------#
-def is_tyto_format():
- global head_contents, text_contents, contents
- global head_lines, text_lines, lines
-
- head_contents = text_contents = ""
- separator = False
-
- with open(uri, "r") as contents:
- contents = contents.read()
- for line in contents.rsplit("\n"):
- if not line:
- line = " "
-
- if line.startswith(sep):
- separator = True
- continue
-
- if separator:
- if not text_contents: text_contents = line
- else: text_contents = "%s\n%s"%(text_contents, line)
- else:
- if not head_contents: head_contents = line
- else: head_contents = "%s\n%s"%(head_contents, line)
-
-
- if not separator:
- error = debug.out(21, sep, uri, True, 2, False)
- return False
-
- if not head_contents:
- error = debug.out(22, "?", uri, True, 2, False)
- return False
-
- if not text_contents:
- error = debug.out(23, "?", uri, True, 2, False)
- return False
-
- head_lines = len(head_contents.splitlines()) + 1 # Count with sep line
- text_lines = len(text_contents.splitlines())
- lines = head_lines + text_lines
-
- return True
-
-
-#=======================================#
-# Load post database #
-# return True, or False if unused (yet) #
-#---------------------------------------#
-def cf_load():
- global cf, not_chk
- cf = not_chk = False
-
-
- 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(module, wrk_post, wrk_post_uri):
- global error
-
- db_uri = os.path.join(
- domain.wrk_db,
- tools.get_filesum(wrk_post_uri, False) + ".ini"
- )
-
- if not os.path.exists(db_uri):
- error = \
- 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, "check: %s"%langs.logs.error, db_uri, True, 2, False)
- return False
-
- global tmp_title, tmp_about, tmp_logo
- try:
- tmp_title = tmp_cf.get("HEADERS", "title")
- except:
- error = \
- debug.out(51, "title:", wrk_post_uri, True, 2, False)
- return False
-
- try:
- tmp_about = tmp_cf.get("HEADERS", "about")
- except:
- error = \
- debug.out(51, "about:", wrk_post_uri, True, 2, False)
- return False
-
- try:
- tmp_logo = tmp_cf.get("HEADERS", "logo")
- except:
- error = \
- debug.out(51, "logo:", wrk_post_uri, True, 2, False)
- return False
-
- 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 #
+# Create datas from article file #
#--------------------------------#
-def cf_get(section, key, boolean):
- if boolean:
- try: return cf.getboolean(section, key)
- except: return False
+def set_datas():
+ global datas
- try: return cf.get(section, key)
- except: return ""
+ src_target = uri.rsplit(domain.wrk_dirs["articles"])[1]
+ srv_target = src_target[:-4] + "html"
+ src_file = os.path.basename(uri)
+ dir_target = src_target.replace(src_file, "")
+
+ # Settings
+ datas = \
+ {
+ "cid" : tools.get_HID(uri, True),
+ "src_target" : src_target,
+ "srv_target" : srv_target,
+ "src_file" : src_file,
+ "src_rpa" : "/" + src_target,
+ "web_rpa" : "/" + srv_target,
+ "www_url" : domain.web["www"] + src_target[:-4] + "html",
+ "dir_target" : dir_target,
+ "rpa" : get_rpa(),
+ # URIS format, "files" : {f_nbr : (full_uri, web_uri)}
+ "files" : {},
+ }
-#=============================================#
-# Get and prepare new vars from post database #
-#---------------------------------------------#
-def cf_datas():
- # [CHECK]
- # -------
- global chk_hash, chk_date, chk_static, chk_errors
- chk_hash = cf_get("CHECK", "hash", False)
- chk_date = cf_get("CHECK", "date", False)
- chk_static = cf_get("CHECK", "static", True)
- chk_errors = cf_get("CHECK", "errors", True)
+#=====================================================#
+# Return relative path for files from root, like "./" #
+#-----------------------------------------------------#
+def get_rpa():
+ src_link = "/" + uri.rsplit(domain.wrk_dirs["articles"])[1]
+ rpa = src_link.count("/")
+
+ if rpa > 1: rpa = rpa -1 ; rpa = rpa * "../"
+ else: rpa = "./"
- # [WIP]
- # -----
- global wip_hash, wip_date, wip_uri, wip_static
- wip_hash = cf_get("WIP", "hash", False)
- wip_date = cf_get("WIP", "date", False)
- wip_uri = cf_get("WIP", "uri", False)
- wip_static = cf_get("WIP", "static", True)
-
- # [WIP]
- # -----
- global www_hash, www_date, www_uri, www_static
- www_hash = cf_get("WWW", "hash", False)
- www_date = cf_get("WWW", "date", False)
- www_uri = cf_get("WWW", "uri", False)
- www_static = cf_get("WWW", "static", True)
-
- global set_title, set_about, set_date, set_tags, set_author
- set_title = cf_get("HEADERS", "title", False)
- set_about = cf_get("HEADERS", "about", False)
- set_date = cf_get("HEADERS", "date", False)
- set_tags = cf_get("HEADERS", "tags", False)
- set_author = cf_get("HEADERS", "authors", False)
-
- global sub_uri, www_logo
- sub_uri = cf_get("FILE", "sub_uri", False)
- www_logo = cf_get("HEADERS", "logo", False)
-
-
-#===============================#
-# Do some datas comparisons #
-# after post cf_datas() setup #
-# Used to do processes (mainly) #
-#-------------------------------#
-def compare_datas():
- global do_chk, do_wip, has_changed
-
- # check can be done ?
- has_changed = False
- if wrk_id != chk_hash:
- has_changed = True
-
- do_chk = False
- if chk_errors or \
- chk_static != domain.static or \
- args.force == True:
- do_chk = True
- else:
- do_chk = tools.compare_values(wrk_id, chk_hash)
-
-
- # wip can be done
- do_wip = False
- if wip_static != domain.static or \
- args.force:
- do_wip = True
- else:
- do_wip = tools.compare_values(chk_hash, wip_hash)
-
-
-#===============================#
-# Set a value in post database #
-# only if changed value #
-# check for [section] in file #
-# or create it with key and val #
-# config file must be loaded #
-#-------------------------------#
-def cf_set(section, key, value):
- global write
-
- try: cf
- except: cf_load()
-
- if not cf.has_section(section):
- cf.add_section(section)
-
- try: curval = cf.get(section, key)
- except: curval = ""
-
- if not curval or curval != value:
- cf.set(section, key, value)
- write = True
-
-
-#=====================#
-# Write post database #
-# if new value is set #
-#---------------------#
-def cf_write():
- global 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
-
-
-#====================================================#
-# Search and return .tyto file in domain root folder #
-#----------------------------------------------------#
-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):
- if root.startswith(nothere):
- continue
-
- for f in files:
- if f.endswith(".tyto"):
- f_uri = os.path.join(root, f)
- target = f_uri.rsplit(domain.wrk_articles)[1]
-
- args.action == "check" and check.is_article(target)
-
-
-
-
-#======#
-# MAIN #=======================================================================
-#======#
-# Statistics
-# ==========
-stats_bcodes_lines = 0
-
-stats_bcodes = 0
-stats_quotes = 0
-stats_parags = 0
-stats_lists = 0
-stats_divs = 0
-
-stats_links = 0
-stats_images = 0
-stats_files = 0
-stats_raws = 0
-stats_codes = 0
-stats_abbrs = 0
-
-stats_text_links = 0
-stats_text_files = 0
-stats_text_images = 0
-stats_text_abbrs = 0
-stats_text_codes = 0
-stats_text_raws = 0
-
-
-# head_contents
-#==============
-# Optional Tags
-nositemap = "! NoSitemap" # Article will not be included in sitemap
-
-# One Line needed
-sep = "-----" # Splitter between header and article texts
-
-# Will replace "False" with data value (check process)
-title = ("title:", False)
-about = ("about:", False)
-date = ("date:", False)
-tags = ("tags:", False)
-author = ("author:", False)
-logo = ("logo:", False) # optional
-
-# Multiple lines (3) markers
-ml_tags = (
- "link:",
- "image:",
- "file:",
- "raw:",
- "code:",
- "abbr:"
- )
-ml_tags_marks = {
- ml_tags[0] : "__",
- ml_tags[2] : "--",
- ml_tags[1] : "_image:",
- ml_tags[5] : "::",
- ml_tags[3] : "_raw:",
- ml_tags[4] : "_code:"
- }
-ml_tags_stats = {
- ml_tags[0] : stats_links,
- ml_tags[2] : stats_files,
- ml_tags[1] : stats_images,
- ml_tags[5] : stats_abbrs,
- ml_tags[3] : stats_raws,
- ml_tags[4] : stats_codes,
- }
-
-# Markers with uri in value2
-value2s_uri = (ml_tags[1], ml_tags[2], ml_tags[3], ml_tags[4])
-value2s_ext_uris = ("http", "ftp")
-
-# text_contents
-# =============
-# Paired markers
-ptags = (
- ("{{", "}}", "bcodes"),
- ('["', '"]', "quotes"),
- ("((", "))", "parags", '', "
"),
- ("<:", ":>", "lists", "=", "+"),
- ("[[", "]]", "divs", '', "
")
- )
-
-ptags_stats = {
- ptags[0][2] : stats_bcodes,
- ptags[1][2] : stats_quotes,
- ptags[2][2] : stats_parags,
- ptags[3][2] : stats_lists,
- ptags[4][2] : stats_divs,
- }
-
-# Tyto Titles #1 =
-tyto_titles = ("#1", "#2", "#3", "#4", "#5")
-html_titles = {
- "#1" : '%s ',
- "#2" : '%s ',
- "#3" : '%s ',
- "#4" : '%s ',
- "#5" : '%s ',
- }
-
-html_brline = ("|", ' ')
-html_hrline = ("--", ' ')
-text_comments = (";;", ""%post.cf.get("HEADERS", "title")
-
- for line in raw_post.rsplit("\n"):
- # Line is empty
- if not line or line == " ":
- continue
-
- # Line is a tyto comment or tyto title
- if line.lstrip().startswith("#") and \
- not line.lstrip().startswith(post.tyto_titles):
- continue
+ work_str += " "*cur_rank + ' ' + text + " \n"
+
+ for i in range(cur_rank):
+ work_str += " "*(cur_rank-i-1) + CLOSING[rank_stack.pop()]
- html_post = "%s\n%s"%(html_post, line)
-
-
-#============================#
-# Convert words tags to HTML #
-#----------------------------#
-def words_tags():
- for tags in post.words_tags:
- text_replace(tags[0], tags[3]%domain.css) # Opened tag
- text_replace(tags[1], tags[4]) # closed tag
- text_replace(">%s<"%post.words_ml_tag, "><") # multiple tags for words
-
-
-#=========================#
-# Convert Start line tags #
-# anchors, paragraphs... #
-#-------------------------#
-def sl_tags():
- for ln, line in enumerate(html_post.rsplit("\n")):
- css = ""
-
- # Paragraphs
- if line.lstrip().startswith(post.ptags[2][0]):
- css = tools.get_css(line, post.ptags[2][0], "?")
- text_replace(html_post.rsplit("\n")[ln], post.ptags[2][3]%css)
-
- elif line.lstrip().startswith(post.ptags[2][1]):
- text_replace(line, post.ptags[2][4])
-
- # DIVs
- if line.lstrip().startswith(post.ptags[4][0]):
- css = tools.get_css(line, post.ptags[4][0], "?")
- text_replace(html_post.rsplit("\n")[ln], post.ptags[4][3]%css)
- elif line.lstrip().startswith(post.ptags[4][1]):
- text_replace(line, post.ptags[4][4])
-
- #
- 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)
-
- #
- elif line.lstrip().startswith(post.html_hrline[0]):
- css = tools.get_css(line, post.html_hrline[0][0], "?")
- text_replace(html_post.rsplit("\n")[ln],post.html_hrline[1]%css)
-
- # Anchors
- elif line.lstrip().startswith(post.anchor_target[0]):
- css = tools.get_css(line, post.anchor_target[0], "?")
- text_replace(line, post.anchor_target[1]%css)
+ return work_str
#========================================#
@@ -375,1016 +389,425 @@ def split_size(size):
return tup_size[0] + tup_size[1]
-#=============================#
-# Convert images tags to HTML #
-#-----------------------------#
+#==============================#
+# Convert images marks to HTML #
+#------------------------------#
def images():
- for key, val in post.cf.items("IMAGES"):
- if key.startswith("html"):
- continue
-
- # Get target value by replacing key with html
- html_key = key.replace("image", "html")
- html_val = post.cf.get("IMAGES", html_key)
+ try:
+ stat = check.stats["header"]["images"]
+ marks = check.stats["writer"]["images"] - 1
+ except: return
+
+ debug.out(211, "Images (%s) (%s marks)"%(
+ stat, marks
+ ), post.uri, False, 0, False)
+
+ global html_article
+ html_article = html_article.rsplit("\n")
+ parfmt = '"c=class", "f=Legend", "w=WIDTH", "h=HEIGHT"'
+
+ set_dict, sorted_names = tools.sort_dict(post.option_tags["image"])
+ for l in sorted_names:
+ mark = set_dict[l][1]
+ uri = set_dict[l][3]
+ alt = set_dict[l][4]
+
+ # Find tag in article
+ for ln, line in enumerate(html_article):
+ if line.lstrip().startswith(mark):
+ # reset parameters
+ params = {
+ "c=" : domain.web["css"],
+ "f=" : False,
+ "h=" : False,
+ "w=" : False
+ }
- # Search tag from val in html_post
- for ln, line in enumerate(html_post.rsplit("\n")):
- if line.lstrip().startswith(val):
- css = domain.css
- width = height = figure = figcap_o = figcap_c = style = ""
- options = line.split()
- markers = ('c=', 'w=', 'h=','f=')
-
- # Specific CSS class for _image:logo
- if options[0].rsplit(":")[1] == "logo":
- css = "post_logo"
-
- for option in options:
- # was activated with f=
- if figure and not option.startswith(markers):
- figure = "%s %s"%(figure, option)
-
- # CSS (default domain css)
- try: css = option.rsplit("c=")[1]
- except: pass
-
- # >idth:
+ # Get parameters if set
+ tupic = line.rsplit(mark)[1].lstrip() or ()
+ if tupic:
try:
- width = option.rsplit("w=")[1]
- width = split_size(width)
+ tupic = ast.literal_eval(tupic)
+ for userparam in tupic:
+ for param in params:
+ if param in userparam:
+ params[param] = userparam.rsplit(param)[1]
+ if params["w="]: params["w="] = split_size(params["w="])
+ if params["h="]: params["h="] = split_size(params["h="])
+
+ # Mismatch parameters
except:
pass
- # Height
- try:
- height = option.rsplit("h=")[1]
- height = split_size(height)
- except:
- pass
+ type(tupic) is tuple or \
+ debug.out(39, '%s %s'%(
+ mark, parfmt
+ ), post.uri, True, 2, False)
- try: figure = option.rsplit("f=")[1]
- except: pass
-
- # tag
- if link:
- blockquote_cite = ' cite="%s"'%link
- cite = cite or "Source"
- footer = '%s '%(
- domain.css, link, footer
- )
- if lang:
- blockquote_lang = ' lang="%s"'%lang
-
- # '
-
-
-#=========#
-# 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: #
-# - datas changed #
-# - not created #
-#----------------------------------#
-def modules_db():
- global db_mods_uri, mods_cf
-
- db_mods_uri = os.path.join(domain.wrk_mods, ".modules.ini")
-
- if not os.path.exists(db_mods_uri):
- tools.create_file(db_mods_uri, ini_mods)
-
- mods_cf = configparser.ConfigParser()
- mods_cf.read(db_mods_uri)
-
-
-#============================================#
-# Check / Create modules files (.raw + .html #
-# process: "wip" or "www" #
-# - navbar #
-# - sidebar #
-# - header #
-# - footer #
-#--------------------------------------------#
-def get_modules(srv):
- global modules, datepub
-
- try: datepub
- except: datepub = tools.nowdate()
-
- # Modules settings
- fill_footer_raw()
- modules = \
- {
- "metas" : {
- "raw" : langs.logs.metas_header%(
- domain.title, domain.wrk_articles,
- domain.wrk_metas,
- domain.wip_metas,
- domain.www_metas
- ),
- "wrk" : domain.wrk_metas,
- "wip" : domain.wip_metas,
- "www" : domain.www_metas,
- "set" : metas_html_create
- },
- "header" : {
- "raw" : module_header%(
- "/template/%s"%domain.logo, domain.about,
- "/template/%s"%domain.logo, domain.about, domain.about,
- domain.title,
- domain.about
- ),
- "wrk" : domain.wrk_header,
- "wip" : domain.wip_header,
- "www" : domain.www_header,
- "set" : header_html_create
- },
- "navbar" : {
- "raw" : langs.logs.navbar_header%(
- domain.title, domain.wrk_articles,
- domain.wrk_navbar,
- domain.wip_navbar,
- domain.www_navbar
- ),
- "wrk" : domain.wrk_navbar,
- "wip" : domain.wip_navbar,
- "www" : domain.www_navbar,
- "set" : navbar_check
- },
- "sidebar" : {
- "raw" : langs.logs.sidebar_header%(
- domain.title, domain.wrk_articles,
- domain.wrk_sidebar,
- domain.wip_sidebar,
- domain.www_sidebar
- ),
- "wrk" : domain.wrk_sidebar,
- "wip" : domain.wip_sidebar,
- "www" : domain.www_sidebar,
- "set" : sidebar_check,
- },
- "footer" : {
- "raw" : module_footer%(
- domain.title,
- domain.about,
- footer_items,
- footer_cpr
- ),
- "wrk" : domain.wrk_footer,
- "wip" : domain.wip_footer,
- "www" : domain.www_footer,
- "set" : footer_html_create
- },
- }
-
- # Avois creating again module if files are same
- modules_db()
- mods_cf_write = False
-
- # 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
- if os.path.exists(modules[mod]["wrk"]):
- cur_raw_id = tools.get_filesum(modules[mod]["wrk"], True)
- mod_raw_id = mods_cf.get(mod.upper(), "raw")
- if cur_raw_id != mod_raw_id:
- mods_cf.set(mod.upper(), "raw", cur_raw_id)
- mods_cf_write = True
- create_html_module = True
-
- else:
- tools.create_file(modules[mod]["wrk"], modules[mod]["raw"])
- cur_raw_id = tools.get_filesum(modules[mod]["wrk"], True)
- mods_cf.set(mod.upper(), "raw", cur_raw_id)
- mods_cf_write = True
- create_html_module = True
-
- # Unused module HTML file or "--force" option
- if not os.path.exists(modules[mod][srv]):
- create_html_module = True
-
- # Create HTML module if needed (raw updated, or unused html file)
- if args.force or create_html_module:
- modules[mod]["set"](srv)
-
- if post.error != 0:
- return False
-
- if mods_cf_write:
- with open(db_mods_uri, "w") as f:
- mods_cf.write(f)
-
- return True
-
-
-#================================================#
-# Create metas.html in server (wip/ or www/) #
-# Only use line starting with "%s'
-
- for ln, line in enumerate(navbar_raw, 1):
- if line.lstrip().startswith("#") or \
- not line or \
- line.isspace():
- continue
- # Get directory name and link name (if separated by "#")
- try:
- folder = line.lstrip().rsplit("#")[0].rstrip()
- link_name = line.lstrip().rsplit("#")[1].lstrip().rstrip()
- except:
- link_name = folder = line.lstrip().rstrip()
-
- folder_uri = os.path.join(domain.wrk_articles, folder)
-
- # Unused directory in articles/
- if not os.path.exists(folder_uri):
- post.error = \
- debug.out(6, 'Navbar. %s) "%s"'%(
- ln, folder
- ), domain.wrk_navbar, True, 2, False)
- return False
-
- # Directory exists
- # Unused index.tyto in wrk folder
- wrk_index = os.path.join(folder, "index.tyto")
- wrk_index_uri = os.path.join(folder_uri, "index.tyto")
- if not os.path.exists(wrk_index_uri):
- post.error = \
- debug.out(5, 'Navbar. %s) "%s"'%(
- ln, wrk_index
- ), domain.wrk_navbar, True, 2, False)
- return False
-
- # Unused index.html in srv
- html_index_srv_uri = os.path.join(html_indexes[srv], folder)
- html_index_srv_uri = os.path.join(html_index_srv_uri, "index.html")
- if not os.path.exists(html_index_srv_uri):
- debug.out(5, 'Navbar. %s) "%s"'%(
- ln, html_index_srv_uri.rsplit(domain.srv_name)[1]
- ), domain.wrk_navbar, True, 1, False)
-
- # Load post configuration file in tmp module
- # return if unused or post errors
- if not post.tmp_load("Navbar", wrk_index, wrk_index_uri):
- return False
+ # Set style for image if set
+ styles = ""
+ if params["h="] or params["w="]:
+ styles = ' style="%s%s"'
+ if params["w="]: width = 'width:%s;'%params["w="]
+ else: width = ""
+ if params["h="]: height = 'height:%s;'%params["h="]
+ else: height = ""
+ styles = styles%(width, height)
+
+
+ # Create HTML line
+ img = ' '%(
+ params["c="], uri, alt, styles
+ )
+
+ # Set figure if image has a legend
+ if params["f="]:
+ img = ''%params["c="] + \
+ '%s'%img + \
+ ''%params["c="] + \
+ '%s'%params["f="] + \
+ ' ' + \
+ ' '
+
+ img = HTMLs["image"]%(params["c="], uri, img)
+ html_article[ln] = img
- items = True
- title_html = ' title="%s - %s"'%(post.tmp_title, post.tmp_about)
+ tmp_article = ""
+ for line in html_article:
+ if not tmp_article: tmp_article = line
+ else: tmp_article = "%s\n%s"%(tmp_article, line)
+ html_article = tmp_article
- # Format HTML href uri
- if not folder.startswith("/"):
- folder = "/%s"%folder
- navbar_html = "%s\n%s"%(
- navbar_html,
- html_line%(title_html, domain.css, folder, link_name)
- )
- if not items:
- post.error = \
- debug.out(9, 'Navbar', domain.wrk_navbar, True, 2, False)
- return False
+#=============================#
+# Convert block quote to HTML #
+#-----------------------------#
+def bquotes():
+ try: stat = check.stats["writer"]["bquotes"]
+ except: return
- tools.create_file(modules["navbar"][srv], module_navbar%navbar_html)
-
- return True
-
-
-#=========================================================#
-# Create sidebar.html in server (wip/ or www/) #
-# If sidebar is deactivated, create one HTML comment line #
-# else, create HTML li lists from tyto_sidebar.raw datas #
-#---------------------------------------------------------#
-def sidebar_check(srv):
- # sidebar is NOT activated (= 0) in domain configuration file
- sidebar_html = ""
- if int(domain.sidebar_items) == 0:
- tools.create_file(modules["sidebar"][srv], sidebar_html)
- return True
-
- # Create sidebar HTML file in srv, from raw
- if not sidebar_html_create(srv):
- return False
-
- return True
-
-
-#==================================================#
-# sidebar_items > 0 in domain configuration file #
-# Create HTML li lists from tyto_sidebar.raw datas #
-#--------------------------------------------------#
-def sidebar_html_create(srv):
- max_items = int(domain.sidebar_items)
- items = 0
- html_post_uri = {
- "wip" : domain.wip,
- "www" : domain.www
- }
+ debug.out(211, "bquotes (%s)"%stat, post.uri, False, 0, False)
- with open(domain.wrk_sidebar, "r") as f:
- sidebar_raw = f.read().rsplit("\n")
- sidebar_html = ""
- html_line = ''
+ # Treat each found quote
+ for nbr in post.block_tags["bquotes"]["sources"]:
+ # Default parameters
+ params = {
+ "cite:" : False,
+ "date:" : False,
+ "book:" : False,
+ "lang:" : False,
+ "link:" : False,
+ }
+
+ # Set block-quote parameters
+ quote = post.block_tags["bquotes"]["sources"][nbr][0].rsplit("\n")
+ for ln, line in enumerate(quote):
+ line = line.lstrip()
+ if ln == 0:
+ css = tools.get_css(line, post.block_tags["bquotes"]["marks"][0])
+ quote[ln] = ""
+ elif ln == len(quote) - 1:
+ quote[ln] = ""
+
+ elif line.startswith(tuple(params)):
+ param = line.rsplit()[0]
+ params[param] = line.rsplit(param)[1].lstrip()
+ quote[ln] = ""
+
+ # Set HTML tags with params
+ # Create HTML block quote
+
+ # time/date set
+ date = html_time_o = html_time_c = ""
+ if params["date:"]:
+ date = params["date:"]
+ html_time_o = ''%date
+ html_time_c = " "
+
+ # Simple references: "author,book,date"
+ cite = book = refs = ""
+ if params["cite:"] : cite = "%s, "%params["cite:"]
+ if params["book:"] : book = "%s, "%params["book:"]
+ if cite or book or date: refs = '-- %s%s%s'%(cite, book, date)
+
+ # line
+ bq_cite = bq_lang = bq_title = ""
+ if params["link:"]: bq_cite = ' cite="%s"'%params["link:"]
+ if params["lang:"]: bq_lang = ' lang="%s"'%params["lang:"]
+ if refs : bq_title = ' title="%s"'%refs
- for ln, line in enumerate(sidebar_raw, 1):
- # User wants max_items
- if items > max_items:
- break
-
- if line.lstrip().startswith("#") or \
- not line or \
- line.isspace():
+ if params["link:"] and refs:
+ refs = '%s '%(css, params["link:"], refs)
+
+ html_footer = ""
+ if refs: html_footer = ''%(css, refs)
+
+ # Contents Quote
+ contents = ""
+ for bq_ln, bq_line in enumerate(quote):
+ bq_line = bq_line.lstrip()
+ if not bq_line or bq_line.isspace():
continue
- # Set post uri from line
- wrk_post = line.lstrip()
- wrk_post_uri = os.path.join(domain.wrk_articles, wrk_post)
-
- # Unused file in articles/
- if not os.path.exists(wrk_post_uri):
- post.error = \
- debug.out(5, "Sidebar. %s) %s"%(
- ln, wrk_post
- ), wrk_post_uri, True, 2, False)
- return False
-
- # Set HTML post uri in srv
- srv_post_uri = os.path.join(
- html_post_uri[srv],
- wrk_post[:-4] + "html"
- )
-
- # Unused index.html in srv
- if not os.path.exists(srv_post_uri):
- debug.out(5, "Sidebar. %s) %s"%(
- ln, wrk_post
- ), srv_post_uri, True, 1, False)
-
- # Load post configuration file in tmp module
- # return if unused or post errors
- if not post.tmp_load("Sidebar", wrk_post, wrk_post_uri):
- return False
-
- # Post can be added to list
- items += 1
- if not wrk_post.startswith("/"):
- wrk_post = "/" + wrk_post
- wrk_post = wrk_post[:-4] + "html"
- if wrk_post.endswith("index.html"):
- wrk_post = wrk_post[:-10]
- sidebar_html = "%s\n%s"%(
- sidebar_html,
- html_line%(
- wrk_post,
- post.tmp_title,
- '/%s'%post.tmp_logo.rsplit(domain.www_url)[1],
- post.tmp_title,
- post.tmp_about,
- )
- )
-
- # sidebar configuration error
- if items == 0:
- post.error = \
- debug.out(9, 'Sidebar', domain.wrk_sidebar, True, 2, False)
- return False
+ if not contents: contents = bq_line
+ else: contents = "%s\n%s"%(contents, bq_line)
+
+ bquote = HTMLs["bquotes"]%(
+ css, bq_cite, bq_lang, bq_title,
+ html_time_o,
+ contents,
+ html_time_c,
+ html_footer
+ )
+
+ replace_article(post.block_tags["bquotes"]["sources"][nbr][0], bquote)
- tools.create_file(modules["sidebar"][srv], module_sidebar%sidebar_html)
- return True
+
+#=================================#
+# Convert words tags (strongs...) #
+#---------------------------------#
+def words_tags():
+ for tag in post.words_tags:
+ try: stat = check.stats["writer"][tag]
+ except: continue
+
+ # anchors links are converted in anchors_links()
+ if tag == "anc_links":
+ continue
+
+ debug.out(211, "%s (%s)"%(tag, stat), post.uri, False, 0, False)
+ # Replace tags with space after and before
+ replace_article("%s "%post.words_tags[tag][0],
+ HTMLs[tag][0]%domain.web["css"]
+ )
+ replace_article(" %s"%post.words_tags[tag][1],
+ HTMLs[tag][1]
+ )
+
+ # Replace legacies tags
+ replace_article(post.words_tags[tag][0],
+ HTMLs[tag][0]%domain.web["css"]
+ )
+ replace_article(post.words_tags[tag][1],
+ HTMLs[tag][1]
+ )
+
+
+#=====================#
+# Convert inline code #
+#---------------------#
+def icodes():
+ try: stat = check.stats["writer"]["icodes"]
+ except: return
+
+ for nbr in post.icodes["sources"]:
+ icode = post.icodes["sources"][nbr][0]
+ if icode[0] == "²": icode = post.words_tags["icodes"][0] + icode[1:]
+ if icode[-1] == "²": icode = icode[:-1] + post.words_tags["icodes"][1]
+ icode = tools.convert_html_signs(icode).lstrip().rstrip()
+
+ replace_article(post.icodes["sources"][nbr][1], icode)
+
+
+#==============================================#
+# replace start line tags (div, paragraphs...) #
+# Remove internal comments and empty lines #
+# Rebuild html_article #
+#----------------------------------------------#
+def sl_tags():
+ global html_article
+
+ tmp_article = ""
+
+ for line in html_article.rsplit("\n"):
+ pass_line = False
+ line = line.lstrip()
+
+ # Useliess line
+ if not line \
+ or line.isspace() \
+ or line.startswith("#"):
+ continue
+
+ # HTML comments (default: ";; ...")
+ elif line.startswith(post.html_comments):
+ line = ""%line.rsplit(post.html_comments)[1]
+ pass_line = True
+
+ # new_line mark
+ else:
+ for tag in post.indep_tags:
+ if line.startswith(post.indep_tags[tag]):
+ pass_line = True
+
+ # Anchor source
+ if tag == "anchors":
+ anc = tools.get_css(line, post.indep_tags[tag])
+ line = ' '%anc
+ # hr, br
+ else:
+ line = HTMLs[tag]%domain.web["css"]
+
+ # Paragraphs, divs
+ if not pass_line:
+ for tag in post.sl_ptags:
+ # Opened mark
+ if line.startswith(post.sl_ptags[tag][0]):
+ css = tools.get_css(line, post.sl_ptags[tag][0])
+ line = sl_ptags[tag][0]%css
+ # Close mark
+ elif line.startswith(post.sl_ptags[tag][1]):
+ line = sl_ptags[tag][1]
+
+ if not tmp_article: tmp_article = line
+ else: tmp_article = "%s\n%s"%(tmp_article, line)
+
+ # Rebuild html_article
+ html_article = tmp_article
#===============================#
-# Get datas and fill footer raw #
+# Convert anchors links markers #
#-------------------------------#
-def fill_footer_raw():
- global footer_items, footer_cpr
-
- # Create list items
- footer_items = ""
- item = \
- ''
+def anchors_links():
+ try: stat = check.stats["writer"]["anc_links"]
+ except: return
- # Specific to License
- if not domain.license: domain.license = "Copyleft"
- if not domain.license_url: domain.license_url = "/"
- show_license = "%s%s %s"%(langs.site.license, langs.logs.pp, domain.license)
+ debug.out(211, "Anchors (%s)"%stat, post.uri, False, 0, False)
+ for nbr in post.anchors:
+ replace_article(post.anchors[nbr][0],post.anchors[nbr][1])
+
+
+#=================================================#
+# Convert block-codes to HTML, replacing b2b mark #
+#-------------------------------------------------#
+def bcodes():
+ try: stat = check.stats["writer"]["bcodes"]
+ except: return
- 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:
- keyname = key.rsplit("_url")[0]
- footer_items = "%s\n%s"%(
- footer_items,
- item%(
- link,
- getattr(langs.site, "%s_title"%keyname), domain.title,
- getattr(langs.site, keyname)
- )
- )
+ debug.out(211, "BCodes (%s)"%stat, post.uri, False, 0, False)
- # Create copyright line
- cur_date = datepub.rsplit("-")[0]
- dom_date = domain.date.rsplit("-")[0]
- if cur_date != dom_date: dates = "%s-%s"%(dom_date, cur_date)
- else: dates = cur_date
- footer_cpr = 'Copyright © %s %s'%(dates, domain.title)
-
-
-#================================================#
-# Create footer.html in server (wip/ or www/) #
-# Remove empty lines and those starting with "#" #
-# Copy other lines #
-# modules/tyto_footer.raw has default contents #
-#------------------------------------------------#
-def footer_html_create(srv):
- generator = ''
-
- with open(domain.wrk_footer, "r") as f:
- footer_raw = f.read().rsplit("\n")
- footer_html = ""
-
- for line in footer_raw:
- if not line or \
- line.isspace() or \
- line.lstrip().startswith("#"):
+ for nbr in post.block_tags["bcodes"]["sources"]:
+ lines = post.block_tags["bcodes"]["sources"][nbr][0].rsplit("\n")
+ bcode = ""
+ for ln, line in enumerate(lines, 0):
+ # Opened mark : get CSS (if any) and pass line
+ if ln == 0:
+ css = tools.get_css(line, post.block_tags["bcodes"]["marks"][0])
+ if not css == domain.web["css"]:
+ HTMLs["bcodes"] = HTMLs["bcodes"].replace("bcode", css)
+ else:
+ css = "bcode"
continue
- 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
+ # Get first character to set indent for bcode
+ elif ln == 1:
+ fc = len(line) - len(line.lstrip())
+
+ # closed mark : pass line
+ elif ln == len(lines) - 1:
+ continue
+
+ line = tools.convert_html_signs(line)[fc:]
+ if not bcode: bcode = HTMLs["bcodes"]%(ln, line)
+ else: bcode = "%s\n%s"%(bcode, HTMLs["bcodes"]%(ln, line))
+
+ bcode = '\n%s\n '%(css, bcode)
+ replace_article(post.block_tags["bcodes"]["sources"][nbr][1], bcode)
-#======#
-# MAIN #=======================================================================
-#======#
-# modules .ini configuration file
-ini_mods = """
-[METAS]
-raw =
+#==========================================================#
+# Convert contents file to HTML block-code, replacing mark #
+#----------------------------------------------------------#
+def codes():
+ try: stat = check.stats["header"]["codes"]
+ except: return
+
+ debug.out(211, "Codes (%s)"%stat, post.uri, False, 0, False)
+
+ set_dict, sorted_names = tools.sort_dict(post.option_tags["code"])
+ for l in sorted_names:
+ mark = set_dict[l][1]
+ uri = domain.wrk_dirs["articles"][:-1] + set_dict[l][3]
+ code = '\n'%set_dict[l][4]
+
+ with open(uri, "r") as f:
+ for ln, line in enumerate(f.read().rsplit("\n"), 1):
+ line = tools.convert_html_signs(line)
+ code = "%s\n%s"%(code, HTMLs["bcodes"]%(ln, line))
+
+ code = "%s\n "%code
+ replace_article(mark, code)
-[HEADER]
-raw =
-[NAVBAR]
-raw =
+#==========================================#
+# Insert raw file contents, replacing mark #
+#------------------------------------------#
+def raws():
+ try: stat = check.stats["header"]["raws"]
+ except: return
-[SIDEBAR]
-raw =
+ debug.out(211, "Raws (%s)"%stat, post.uri, False, 0, False)
-[FOOTER]
-raw =
-"""
+ set_dict, sorted_names = tools.sort_dict(post.option_tags["raw"])
+ for l in sorted_names:
+ mark = set_dict[l][1]
+ uri = domain.wrk_dirs["articles"][:-1] + set_dict[l][3]
+
+ with open(uri, "r") as f:
+ raw = "\n%s"%(set_dict[l][4], f.read())
+ replace_article(mark, raw)
-# HTML templates
-#------------------------------------------------------------------------------
-metas_post = """
-
-
-
-
-
-
+#=================================#
+# Create, manage article Database #============================================
+#---------------------------------#
+def create_db():
+ post.cf_create()
+
+ # Add needed files used by article for future copy
+ for nbr in post.datas["files"]:
+ post.cf_set("FILES", "file_%s"%nbr, post.datas["files"][nbr][1])
+
+ post.cf_write()
+ post.cf_load()
-
-
-
-
-
-
-
-
-
-
+#===============#
+# MAIN settings #==============================================================
+#---------------#
+#-----------------------#
+# HTML (generic values) #
+#-----------------------#
+HTMLs = {
+ "link" : '%s ',
+ "file" : '%s ',
+ "abbr" : '%s ',
+ "title" : '%s ',
+ "toc" : '%s %s ',
+ "strongs" : ('', " "),
+ "bolds" : ('', " "),
+ "underlines" : ('', " "),
+ "emphasis" : ('', " "),
+ "italics" : ('', " "),
+ "quotes" : ('', " "),
+ "cites" : ('', " "),
+ "icodes" : ('', "
"),
+ "anc_links" : ('', " "),
+ "bquotes" : '%s\n%s\n%s%s ',
+ "dels" : ('', ""),
+ "customs" : ('', " "),
+ "image" : '%s ',
+ "bcodes" : '' \
+ '%s ' \
+ '%s ' \
+ '
',
+ "hrs" : ' ',
+ "brs" : ' ',
+ }
-
-
-
-
-
-
-
-
-
-
-%s (%s) %s %s """
-
-module_header = """
-