diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c4ba38..0966d9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ Tyto - Littérateur # CURRENTLY IN DEV ! +## [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 diff --git a/src/usr/bin/tyto b/src/usr/bin/tyto index 0888f9a..a98a94f 100755 --- a/src/usr/bin/tyto +++ b/src/usr/bin/tyto @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Version: 1.9.12 -# Updated: 2023-09-30 1696082419 +# Version: 1.9.13 +# Updated: 2023-10-01 1696117427 # Tyto - Littérateur # Copyright (C) 2023 Cyrille Louarn diff --git a/src/var/lib/tyto/program/__pycache__/args.cpython-311.pyc b/src/var/lib/tyto/program/__pycache__/args.cpython-311.pyc index 17afd7e..27a7f6a 100644 Binary files a/src/var/lib/tyto/program/__pycache__/args.cpython-311.pyc and b/src/var/lib/tyto/program/__pycache__/args.cpython-311.pyc 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 index 512ec39..e6c3a41 100644 Binary files a/src/var/lib/tyto/program/__pycache__/check.cpython-311.pyc and b/src/var/lib/tyto/program/__pycache__/check.cpython-311.pyc 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 index d9f7488..7dc85df 100644 Binary files a/src/var/lib/tyto/program/__pycache__/debug.cpython-311.pyc and b/src/var/lib/tyto/program/__pycache__/debug.cpython-311.pyc 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 index b2b65ab..ca43d33 100644 Binary files a/src/var/lib/tyto/program/__pycache__/forms.cpython-311.pyc and b/src/var/lib/tyto/program/__pycache__/forms.cpython-311.pyc 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 index 9dedeaa..40534a4 100644 Binary files a/src/var/lib/tyto/program/__pycache__/post.cpython-311.pyc and b/src/var/lib/tyto/program/__pycache__/post.cpython-311.pyc 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 index df7a87c..31eda4e 100644 Binary files a/src/var/lib/tyto/program/__pycache__/tools.cpython-311.pyc and b/src/var/lib/tyto/program/__pycache__/tools.cpython-311.pyc differ diff --git a/src/var/lib/tyto/program/check.py b/src/var/lib/tyto/program/check.py index d996bc3..3fed254 100644 --- a/src/var/lib/tyto/program/check.py +++ b/src/var/lib/tyto/program/check.py @@ -33,6 +33,8 @@ #-------------------------- import sys +from dateutil.parser import parse + import args, domain, langs, debug, post, tools @@ -61,8 +63,7 @@ def manage(action, target): # target is not "all" ready() - if target.endswith(".tyto"): - is_article(target) + target.endswith(".tyto") and is_article(target) #================================# @@ -70,29 +71,24 @@ def manage(action, target): # Also used with multiple (loop) # #--------------------------------# def is_article(target): - if not post.is_article(target): - if args.multiple: - return # Let other articles pass - - sys.exit(post.error) - - validators() - if post.error != 0: - if args.targets: - return # Let other articles pass - - sys.exit(post.error) - - print("pass", post.error, args.multiple) + valid(target) + print("pass", post.error, args.targets) + print("chk_date", chk_date) + print("post.stats_comments =", post.stats_comments) # # # -def validators(): +def valid(target): targets = args.targets + + # Target is a tyto article + post.is_article(target) or tools.exit(targets, post.error) + + # One Line targs in head_contents post.error == 0 and ol_tags() or tools.exit(targets, post.error) - + post.error == 0 and titles() or tools.exit(targets, post.error) #===========================================# @@ -102,10 +98,16 @@ def multiple_targets(): ready() -#=======================# -# check header contents # -#-----------------------# +#==============# +# check header #=============================================================== +#==============# +#======================# +# One Line needed tags # +#----------------------# def ol_tags(): + global sitemap + + sitemap = "True" for ln, line in enumerate(post.head_contents.rsplit("\n"), 1): if not line or line.isspace() or line.startswith("#"): continue @@ -125,15 +127,22 @@ def ol_tags(): elif not post.tags[1] and line.startswith(post.tags[0]): post.tags = (post.tags[0], ol_tag_value(line, True)) + + elif line.startswith(post.nositemap): + sitemap = "False" + # Sets are done from loop # Check if tag value exists # ========================= - if not is_ol_tag(post.title[0], post.title[1]): return - if not is_ol_tag(post.about[0], post.about[1]): return - if not is_ol_tag(post.date[0], post.date[1]): return - if not is_ol_tag(post.author[0], post.author[1]): return - if not is_ol_tag(post.tags[0], post.tags[1]): return + if not is_ol_tag(post.date[0], post.date[1]): return False + if not is_valid_date(post.date[1]): return False + if not is_ol_tag(post.title[0], post.title[1]): return False + if not is_ol_tag(post.about[0], post.about[1]): return False + if not is_ol_tag(post.author[0], post.author[1]): return False + if not is_ol_tag(post.tags[0], post.tags[1]): return False + + return True #===========================================# @@ -144,7 +153,7 @@ def ol_tags(): def ol_tag_value(line, commas): value = line.rsplit(":")[1].lstrip() - # reformat comma separated items, removing first space + # reformat comma separated items, removing first spaces if commas: tuple_values = value.rsplit(",") value = "" @@ -162,15 +171,57 @@ def ol_tag_value(line, commas): #---------------------------# def is_ol_tag(tag, value): if not value: - post.error = 51 - debug.out(51, "%s ?"%tag, post.uri, True, 2, False) + post.error = debug.out(51, "%s ?"%tag, post.uri, True, 2, False) return False return True -# -# -# -def valid_date(): - +#======================================# +# Check validity date # +# set date of check (YYYY-MM-DD H:M:S) # +# Also set epoch date # +# Return True/False # +#--------------------------------------# +def is_valid_date(date): + global chk_date + + try: + parse(date) + chk_date = tools.nowdate() + return True + except: + post.error = debug.out(50, "%s"%date, post.uri, True, 2, False) + return False + + +#===============# +# check article #============================================================== +#===============# +#============================# +# Check optional title tags # +# Count tyto + html comments # +# Return True/False # +#----------------------------# +def titles(): + for ln, line in enumerate(post.text_contents.rsplit("\n"), + post.head_lines + 1): + if not line or line.isspace(): + continue + + if line.startswith(post.tyto_titles): + if not line[3:]: + post.error = \ + debug.out(52, "%s. %s ?"%(ln, line), post.uri, True, 2, False) + return False + post.stats_titles += 1 + + elif line[1].isdigit() and int(line[1]) >= 6: + post.error = \ + debug.out(52, "%s) %s..."%(ln, line[0:10]), post.uri, True, 1, False) + return False + + elif line.startswith(post.text_comments): + post.stats_comments += 1 + + return True diff --git a/src/var/lib/tyto/program/debug.py b/src/var/lib/tyto/program/debug.py index dc2f8d1..c0e801a 100644 --- a/src/var/lib/tyto/program/debug.py +++ b/src/var/lib/tyto/program/debug.py @@ -49,10 +49,11 @@ import langs, args def out(nbr, var, val, show, color, stop): args.get_options() if not show: - show = args.dlogs or args.erron and color > 0 # Show only warn and error logs + # Show only warn and error logs + show = args.dlogs or args.erron and color > 0 if not show: - return + return nbr # COlors CS = '\033[0;0m' # Unset @@ -89,6 +90,7 @@ def out(nbr, var, val, show, color, stop): 23 : langs.logs.err_post_empty, 50 : langs.logs.err_date, 51 : langs.logs.err_post_data, + 52 : langs.logs.err_post_title, # WARNINGS (100-200) 100 : langs.logs.warn_no_dom, 101 : langs.logs.domain_created, @@ -126,4 +128,6 @@ def out(nbr, var, val, show, color, stop): if nbr >= 200: nbr = 0 sys.exit(nbr) + + return nbr diff --git a/src/var/lib/tyto/program/forms.py b/src/var/lib/tyto/program/forms.py index e7fc2f7..80fb03d 100644 --- a/src/var/lib/tyto/program/forms.py +++ b/src/var/lib/tyto/program/forms.py @@ -32,7 +32,9 @@ # file program : #-------------------------- -import os, re, configparser +import os, re +from dateutil.parser import parse + import debug, domain, langs, tools @@ -53,11 +55,8 @@ def ask(q, yes_only, default): if yes_only: expected = langs.logs.ok - try: - answer = input(q) - except KeyboardInterrupt: - print("") - maybe_later(expected, "?") + try: answer = input(q) + except KeyboardInterrupt: print("") ; maybe_later(expected, "?") # return default answer if exists if not answer: @@ -71,6 +70,7 @@ def ask(q, yes_only, default): for ok in langs.logs.ok: if answer.lower() == ok.lower(): return True + maybe_later(expected, answer) return answer @@ -123,30 +123,21 @@ def ask_domain_title(update): #---------------------------# def ask_domain_date(update): try: date = domain.cf.get("DOMAIN", "date") - except: date = "YYYY[-MM-DD]" + except: date = "YYYY[-MM][-DD]" - example = date or "YYYY[-MM-DD]" + example = date q = "> %s (%s)%s "%(langs.logs.domain_date, example, langs.logs.q) answer = ask(q, False, date) # Check date format (not valid date) - test = True - tuple_date = answer.rsplit("-") - tuple_len = len(tuple_date) - for i in range(tuple_len): - if i == 0: - if len(tuple_date[i]) != 4 or not tuple_date[i].isdigit(): - test = False - break - elif len(tuple_date[i]) != 2 or not tuple_date[i].isdigit(): - test = False - break + try: + parse(answer) + except: + debug.out(50, "YYYY[-MM-DD]", answer, True, 2, False) + ask_domain_date(update) + return - # Exit if not valid - if not test: - debug.out(50, "YYYY[-MM-DD]", answer, True, 2, True) - if update: tools.update_ini_file(domain.cf_uri, "DOMAIN", "date", answer) else: return answer diff --git a/src/var/lib/tyto/program/post.py b/src/var/lib/tyto/program/post.py index 50199c7..12cf0a4 100644 --- a/src/var/lib/tyto/program/post.py +++ b/src/var/lib/tyto/program/post.py @@ -36,6 +36,9 @@ import os, configparser import domain, debug, tools, tyto +error = 0 + + #============================================# # Check if current directory is in articles/ # # Check if article from target exists # @@ -47,20 +50,16 @@ def is_article(target): domain.user_dir.startswith(domain.wrk_articles) or \ debug.out(2, "-> articles/", domain.wrk_articles, True, 2, True) - global error - # Target URI most be from legacy directory or not begins with if target.startswith(tyto.notarget): - debug.out(20, "./, ../", target, True, 2, False) - error = 20 + error = debug.out(20, "./, ../", target, True, 2, False) return False # Article exists global uri uri = os.path.join(domain.wrk_articles, target) if not os.path.exists(uri): - debug.out(5, "False", uri, True, 2, False) - error = 5 + error = debug.out(5, "False", uri, True, 2, False) return False # Article is a Tyto format and not empty (exit on errors) @@ -89,18 +88,16 @@ def is_article(target): # Return True or False # #-----------------------------------------# def is_tyto_format(): - global head_contents, text_contents, error + global head_contents, text_contents + global head_lines, text_lines, lines separator = False head_contents = text_contents = "" with open(uri, "r") as contents: contents = contents.read() - for line in contents.rsplit("\n"): - if not line: - continue - - if line.startswith(post_sep): + for lines, line in enumerate(contents.rsplit("\n"), 1): + if line.startswith(sep): separator = True continue @@ -108,20 +105,20 @@ def is_tyto_format(): else: head_contents = "%s%s\n"%(head_contents, line) if not separator: - debug.out(21, post_sep, uri, True, 2, False) - error = 21 + error = debug.out(21, sep, uri, True, 2, False) return False if not head_contents: - debug.out(22, "?", uri, True, 2, False) - error = 22 + error = debug.out(22, "?", uri, True, 2, False) return False if not text_contents: - debug.out(23, "?", uri, True, 2, False) - error = 23 + error = debug.out(23, "?", uri, True, 2, False) return False + head_lines = len(head_contents.rsplit("\n")) + text_lines = lines - head_lines + return True @@ -156,16 +153,41 @@ def cf_valid(): #======# -# MAIN # +# MAIN #======================================================================= #======# -error = 0 -# Tag separator to split head and text article -post_sep = "-----" +# head_contents +#============== -# One Line Tags in head article +# Optional Tags +nositemap = "! NoSitemap" # Article will not be included in sitemap + +# One Line needed +sep = "-----" # Splitter between header and article title = ("title:", False) about = ("about:", False) date = ("date:", False) tags = ("tags:", False) author = ("author:", False) + + +# text_contents +# ============= +# Comments +text_comments = (";;", "" } + +# Tyto Titles #1 =

+tyto_titles = ("#1", "#2", "#3", "#4", "#5") +html_titles = { + "#1" : '

%s', + "#2" : '

%s

', + "#3" : '

%s

', + "#4" : '
%s
', + "#5" : '
%s
', + } + +# Statistics +# ========== +stats_comments = 0 +stats_titles = 0 diff --git a/src/var/lib/tyto/program/tools.py b/src/var/lib/tyto/program/tools.py index 59e66da..290e3c2 100644 --- a/src/var/lib/tyto/program/tools.py +++ b/src/var/lib/tyto/program/tools.py @@ -48,35 +48,10 @@ def exit(targets, error): #==============================# # Set and return date and time # -# With local options from lang # #------------------------------# -def nowdate(spec): - # Default - F_Int = "'%Y-%m-%d %I:%M:%S %p'" # Full International date - S_Int = "'%Y-%m-%d" # Short International date - - # Get spec option for local date - # Get Used domain lang and set format date - locales = ("FLocal", "SLocal") - if spec in locales: - domain.cf_load() - lang = domain.cf.get("WEBSITE", "lang") - if lang == "fr": - S_Int = "'%d/%m/%Y'" - F_Int = "'%d/%m/%Y %H:%M:%S'" - - +def nowdate(): now = datetime.datetime.now() - setdate = { - "FInt" : now.strftime(F_Int), - "SInt" : now.strftime(S_Int), - "FLocal" : now.strftime(F_Int), - "SLocal" : now.strftime(S_Int), - "Year" : now.strftime('%Y'), - "Epoch" : int(now.timestamp()), - } - - return setdate[spec] + return(now.strftime('%Y-%m-%d %H:%M:%S')) #========================# diff --git a/src/var/lib/tyto/translations/__pycache__/logs_fr.cpython-311.pyc b/src/var/lib/tyto/translations/__pycache__/logs_fr.cpython-311.pyc index 535c427..056216d 100644 Binary files a/src/var/lib/tyto/translations/__pycache__/logs_fr.cpython-311.pyc and b/src/var/lib/tyto/translations/__pycache__/logs_fr.cpython-311.pyc differ diff --git a/src/var/lib/tyto/translations/logs_fr.py b/src/var/lib/tyto/translations/logs_fr.py index 76078fe..f35c43c 100644 --- a/src/var/lib/tyto/translations/logs_fr.py +++ b/src/var/lib/tyto/translations/logs_fr.py @@ -49,7 +49,7 @@ domain_srv = "URI du serveur" # Errors err_arg = "Argument invalide" err_hole = "Dossier courant invalide" -err_date = "Format de date invalide" +err_date = "Date invalide" err_lang = "Format de langue invalide" err_dir = "Dossier non compatible" err_no_dir = "Dossier inexistant" @@ -58,10 +58,11 @@ err_no_file = "Fichier manquant" err_cr_file = "Fichier non créé" err_bad_uri = "URI non compatible" err_post_sep = "Séparateur manquant" -err_post_head = "Erreur dans l'Entête" +err_post_head = "Entête vide" err_post_empty = "Article vide" err_ini_file = "Configuration invalide" -err_post_data = "Article: donnée manquante" +err_post_data = "Donnée manquante" +err_post_title = "Titre invalide" # Warnings warn_no_dom = "Domaine non configuré"