From 6a17add2485f87825b99022f3c92aaaed3791f9b Mon Sep 17 00:00:00 2001 From: Cyrille LOUARN Date: Fri, 22 Sep 2023 11:52:44 +0200 Subject: [PATCH] Starting new code pre v2 --- CHANGELOG.md | 12 +- README.md | 57 +- src/usr/bin/tyto | 102 +- .../share/bash-completion/completions/tyto | 311 ----- src/var/lib/tyto/help/CHANGELOG.md | 14 - src/var/lib/tyto/help/LICENSE | 661 ---------- src/var/lib/tyto/help/README.md | 53 - src/var/lib/tyto/help/styles.css | 224 ---- src/var/lib/tyto/help/tyto_domain.default | 84 -- src/var/lib/tyto/program/args.py | 224 ++-- src/var/lib/tyto/program/check.py | 1145 +---------------- src/var/lib/tyto/program/creators.py | 241 ---- src/var/lib/tyto/program/db.py | 206 --- src/var/lib/tyto/program/debug.py | 118 ++ src/var/lib/tyto/program/dom.py | 318 ----- src/var/lib/tyto/program/domain.py | 376 ++++++ src/var/lib/tyto/program/form.py | 1092 ---------------- src/var/lib/tyto/program/forms.py | 243 ++++ src/var/lib/tyto/program/help.py | 43 + src/var/lib/tyto/program/html.py | 544 -------- src/var/lib/tyto/program/infos.py | 131 -- src/var/lib/tyto/program/langs.py | 171 ++- src/var/lib/tyto/program/logs.py | 127 -- src/var/lib/tyto/program/new.py | 107 +- src/var/lib/tyto/program/publish.py | 294 ----- src/var/lib/tyto/program/rss.py | 129 -- src/var/lib/tyto/program/set.py | 34 + src/var/lib/tyto/program/show.py | 229 +--- src/var/lib/tyto/program/stats.py | 226 ---- src/var/lib/tyto/program/status.py | 241 ---- src/var/lib/tyto/program/tools.py | 113 ++ src/var/lib/tyto/program/tyto.py | 830 ++---------- src/var/lib/tyto/program/userset.py | 53 + src/var/lib/tyto/program/wip.py | 1110 ---------------- src/var/lib/tyto/translations/logs_en.py | 133 +- src/var/lib/tyto/translations/logs_fr.py | 174 +-- src/var/lib/tyto/translations/site_en.py | 342 ----- src/var/lib/tyto/translations/site_fr.py | 339 ----- src/var/lib/tyto/translations/website_en.py | 34 + src/var/lib/tyto/translations/website_fr.py | 34 + 40 files changed, 1671 insertions(+), 9248 deletions(-) delete mode 100755 src/usr/share/bash-completion/completions/tyto delete mode 100644 src/var/lib/tyto/help/CHANGELOG.md delete mode 100644 src/var/lib/tyto/help/LICENSE delete mode 100644 src/var/lib/tyto/help/README.md delete mode 100644 src/var/lib/tyto/help/styles.css delete mode 100644 src/var/lib/tyto/help/tyto_domain.default delete mode 100644 src/var/lib/tyto/program/creators.py delete mode 100644 src/var/lib/tyto/program/db.py create mode 100644 src/var/lib/tyto/program/debug.py delete mode 100644 src/var/lib/tyto/program/dom.py create mode 100644 src/var/lib/tyto/program/domain.py delete mode 100644 src/var/lib/tyto/program/form.py create mode 100644 src/var/lib/tyto/program/forms.py create mode 100644 src/var/lib/tyto/program/help.py delete mode 100644 src/var/lib/tyto/program/html.py delete mode 100644 src/var/lib/tyto/program/infos.py delete mode 100644 src/var/lib/tyto/program/logs.py delete mode 100644 src/var/lib/tyto/program/publish.py delete mode 100644 src/var/lib/tyto/program/rss.py create mode 100644 src/var/lib/tyto/program/set.py delete mode 100644 src/var/lib/tyto/program/stats.py delete mode 100644 src/var/lib/tyto/program/status.py create mode 100644 src/var/lib/tyto/program/tools.py create mode 100644 src/var/lib/tyto/program/userset.py delete mode 100644 src/var/lib/tyto/program/wip.py delete mode 100644 src/var/lib/tyto/translations/site_en.py delete mode 100644 src/var/lib/tyto/translations/site_fr.py create mode 100644 src/var/lib/tyto/translations/website_en.py create mode 100644 src/var/lib/tyto/translations/website_fr.py diff --git a/CHANGELOG.md b/CHANGELOG.md index af06a05..78a3154 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,13 @@ # Changelog Tyto - Littérateur -- Repository: https://git.a-lec.org/echolib/tyto-litterateur -- Issues: https://git.a-lec.org/echolib/tyto-litterateur/-/issues -- Changelog: https://git.a-lec.org/echolib/tyto-litterateur/-/blob/master/CHANGELOG.md -- License: https://git.a-lec.org/echolib/tyto-litterateur/-/blob/master/LICENSE -- Documentation: https://tyto.echolib.re +- Repository: +- Issues: +- Changelog: +- License: +- Documentation: -## [0.10.6] +## [1.9.0] diff --git a/README.md b/README.md index 006d560..83892c0 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,14 @@ -# Tyto -- FR. Pour obtenir de l'aide, taper juste la commande tyto -- EN. To get help, just type tyto. -- - Doc is only in french yet, but Tyto is translated, also for your websites +# Very early IN dev code +This program can ve tested but not at all usable. Lots of work to do... -## Répertoire de code du projet Tyto -https://git.a-lec.org/echolib/tyto-litterateur - -## Documentation officielle -https://tyto.echolib.re (en cours de construction) - -## Créer un domaine -```` -mkdir -p MONDOMAIN -cd MONDOMAIN -tyto new domain URL -```` - -# Créer un article -https://tyto.echolib.re/%C3%A9crire/ +# Commands ``` -cd articles/ -tyto new index -tyto edit index.tyto +# Get commands list help +tyto ``` -# Vérifier, prévisualiser un article -``` -tyto check index.tyto -tyto wip index.tyto -``` +# Working on +- Managing domain(s) +- - needs more checks to be validated +- english logs translation file (French only, for now) -# Les modules -https://tyto.echolib.re/usages/modules.html - -La barre latérale, le menu, le pied de page et les balises génériques metas -ne seront pas visible localement sans serveur nginx. - -Utiliser l'option --static avec la commande wip pour les voir. Attention, -utiliser la commande publish après avoir utilisé l'option --static sur wip -mettra en ligne la version statique de la page. Il faut donc avant la -commande publish, recommencer la commande wip sur un article sans l'option ---static pour utiliser l'include de nginx (comportement par défaut) - - -# Publier ! -``` -# La première fois, ou après mise à jour des modules ou des fichiers (logo, css...) -tyto publish template - -# Mettre dans le dossier "www" officiel -tyto publish index.tyto -``` diff --git a/src/usr/bin/tyto b/src/usr/bin/tyto index f2198e5..ad4f067 100755 --- a/src/usr/bin/tyto +++ b/src/usr/bin/tyto @@ -1,93 +1,59 @@ #!/usr/bin/env python3 -# Version: 1.0.0 +# Version: 1.9.0 # 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 Affero General Public License -# as published by the Free Software Foundation, either version 3 of the -# License, or of the License, or (at your option) any later version. -# +# 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License +# 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: Main binary to execute +# Description: Main binary to execute. +# Import modules and start checking/using arguments # File: /usr/bin/tyto #---------------------------------------------------------------------- #------------------------- # Funny Stats Project #------------------------- -# Project files : 20 -# Project lines : 7508 -# Project comments : 1153 -# Project functions: 109 -# Project program : 5652 +# Project files : +# Project lines : +# Project comments : +# Project functions: +# Project program : # -# file lines : 93 -# file comments : 33 -# file functions: 0 -# file program : 47 +# file lines : +# file comments : +# file functions: +# file program : #-------------------------- +#======# +# MAIN # +#======#======================================================================= import sys -sys.path.insert(0, '/var/lib/tyto/program') - -#====================# -# MAIN # -# Treat Arguments # -#--------------------# -import logs - if not __name__ == "__main__": - logs.out("14", '', True) + print("! Error: '%s' not '%s'"%(__name__, "__main__")) + sys.exit(1) -# Check arguments +# Set librairies to import app files +libs = "/var/lib/tyto/program" +trfs = "/var/lib/tyto/translations" +sys.path.insert(0, libs) +sys.path.insert(0, trfs) + +# Manage arguments from command line, start process import args -action = args.set_action() -target = args.set_target() - -# Check domain -import dom, status -status.domain() - - -# Command start argument -import check, form, html, new, publish, show, wip, infos, creators -actions = { - "check" : check.manage, - "help" : infos.tyto, - "edit" : show.manage, - "edit-about" : show.manage, - "edit-db" : show.manage, - "edit-wip" : show.manage, - "edit-www" : show.manage, - "force-wip" : wip.manage, - "new" : new.manage, - "publish" : publish.manage, - "preview" : show.manage, - "quick-pub" : publish.manage, - "show" : show.manage, - "show-about" : show.manage, - "show-db" : show.manage, - "show-wip" : show.manage, - "show-www" : show.manage, - "status" : status.check, - "wip" : wip.manage, - } - - -# Start action -# Argument's Check done in args.py -#--------------------------------- -actions[action](target) - +args.start_process() diff --git a/src/usr/share/bash-completion/completions/tyto b/src/usr/share/bash-completion/completions/tyto deleted file mode 100755 index acf053b..0000000 --- a/src/usr/share/bash-completion/completions/tyto +++ /dev/null @@ -1,311 +0,0 @@ -#!/bin/bash -# 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 Affero General Public License -# as published by the Free Software Foundation, either version 3 of the -# License, or of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -#---------------------------------------------------------------------- -# XMPP: echolib (im@echolib.re) -# -# Description: Autocompletion commands -# File: /usr/share/bash-completion/completions/tyto -#---------------------------------------------------------------------- - -#------------------------- -# Funny Stats Project -#------------------------- -# file lines : 311 -# file comments : 45 -# file functions: 0 -# file program : 234 -#-------------------------- - - -#=================# -# Actions section # -#=================#============================================================ - -# Actions: argument 1 # -#---------------------# -_tyto_actions() { -cat </dev/null -} - -# Targets with quick-pub -#----------------------- -_tyto_targets_qp() { -find . -type f -name "*.tyto" -printf '%P\n' 2>/dev/null -} - - -# Targets with edit -#------------------ -_tyto_targets_edits() { -cat </dev/null -} - -# Targets with edit -#------------------ -_tyto_targets_shows() { -cat </dev/null -} - -# Targets: argument 2 (all + .tyto files) -#---------------------------------------- -_tyto_targets() { -cat </dev/null -} - -# Targets: only with action "new" -#-------------------------------- -_tyto_targets_new() { -cat < - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU Affero General Public License is a free, copyleft license for -software and other kinds of works, specifically designed to ensure -cooperation with the community in the case of network server software. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -our General Public Licenses are intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - Developers that use our General Public Licenses protect your rights -with two steps: (1) assert copyright on the software, and (2) offer -you this License which gives you legal permission to copy, distribute -and/or modify the software. - - A secondary benefit of defending all users' freedom is that -improvements made in alternate versions of the program, if they -receive widespread use, become available for other developers to -incorporate. Many developers of free software are heartened and -encouraged by the resulting cooperation. However, in the case of -software used on network servers, this result may fail to come about. -The GNU General Public License permits making a modified version and -letting the public access it on a server without ever releasing its -source code to the public. - - The GNU Affero General Public License is designed specifically to -ensure that, in such cases, the modified source code becomes available -to the community. It requires the operator of a network server to -provide the source code of the modified version running there to the -users of that server. Therefore, public use of a modified version, on -a publicly accessible server, gives the public access to the source -code of the modified version. - - An older license, called the Affero General Public License and -published by Affero, was designed to accomplish similar goals. This is -a different license, not a version of the Affero GPL, but Affero has -released a new version of the Affero GPL which permits relicensing under -this license. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU Affero General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Remote Network Interaction; Use with the GNU General Public License. - - Notwithstanding any other provision of this License, if you modify the -Program, your modified version must prominently offer all users -interacting with it remotely through a computer network (if your version -supports such interaction) an opportunity to receive the Corresponding -Source of your version by providing access to the Corresponding Source -from a network server at no charge, through some standard or customary -means of facilitating copying of software. This Corresponding Source -shall include the Corresponding Source for any work covered by version 3 -of the GNU General Public License that is incorporated pursuant to the -following paragraph. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the work with which it is combined will remain governed by version -3 of the GNU General Public License. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU Affero General Public License from time to time. Such new versions -will be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU Affero General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU Affero General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU Affero General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -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 - Copyright (C) 2022 Libre en Communs / Commissions / Infrastructure - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If your software can interact with users remotely through a computer -network, you should also make sure that it provides a way for users to -get its source. For example, if your program is a web application, its -interface could display a "Source" link that leads users to an archive -of the code. There are many ways you could offer source, and different -solutions will be better for different programs; see section 13 for the -specific requirements. - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU AGPL, see -. diff --git a/src/var/lib/tyto/help/README.md b/src/var/lib/tyto/help/README.md deleted file mode 100644 index 006d560..0000000 --- a/src/var/lib/tyto/help/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# Tyto -- FR. Pour obtenir de l'aide, taper juste la commande tyto -- EN. To get help, just type tyto. -- - Doc is only in french yet, but Tyto is translated, also for your websites - -## Répertoire de code du projet Tyto -https://git.a-lec.org/echolib/tyto-litterateur - -## Documentation officielle -https://tyto.echolib.re (en cours de construction) - -## Créer un domaine -```` -mkdir -p MONDOMAIN -cd MONDOMAIN -tyto new domain URL -```` - -# Créer un article -https://tyto.echolib.re/%C3%A9crire/ -``` -cd articles/ -tyto new index -tyto edit index.tyto -``` - -# Vérifier, prévisualiser un article -``` -tyto check index.tyto -tyto wip index.tyto -``` - -# Les modules -https://tyto.echolib.re/usages/modules.html - -La barre latérale, le menu, le pied de page et les balises génériques metas -ne seront pas visible localement sans serveur nginx. - -Utiliser l'option --static avec la commande wip pour les voir. Attention, -utiliser la commande publish après avoir utilisé l'option --static sur wip -mettra en ligne la version statique de la page. Il faut donc avant la -commande publish, recommencer la commande wip sur un article sans l'option ---static pour utiliser l'include de nginx (comportement par défaut) - - -# Publier ! -``` -# La première fois, ou après mise à jour des modules ou des fichiers (logo, css...) -tyto publish template - -# Mettre dans le dossier "www" officiel -tyto publish index.tyto -``` diff --git a/src/var/lib/tyto/help/styles.css b/src/var/lib/tyto/help/styles.css deleted file mode 100644 index 8afea19..0000000 --- a/src/var/lib/tyto/help/styles.css +++ /dev/null @@ -1,224 +0,0 @@ -/* - * All class / ID used by Tyto - Littérateur in a page - * DOMAIN MUST be changed by domain css set in configuration -*/ - - -/* include header to footer */ -div#site_container { -} - -/* Include article + sidebar */ -div#article_sidebar_container { -} - - -/*===================================================================== - * Header -*/ -header#header_page { -} - -/* Block */ -div#site_logo { -} - -a#site_logo_link { -} - -img#site_logo_image { -} - -/* Block */ -div#site_infos { -} - -a#site_link { -} - -h1#site_title { -} - -p#site_about { -} - - -/*===================================================================== - * navbar -*/ -nav#site_menu { -} - -menu#site_menu_items { -} - -li.site_menu_item { -} - -a.site_menu_link { -} - - -/*===================================================================== - * article -*/ -article#article_main { -} - -/* article title */ -h2#main_title { -} - -/* Writer titles*/ -h3.title_3 { -} -h4.title_4 { -} -h5.title_5 { -} -h6.title_6 { -} - -/* Between every IF CONTENTS */ -div.contents { -} -div.contents_2 { -} -div.contents_3 { -} -div.contents_4 { -} -div.contents_5 { -} - -/* Default if not set in post */ -p.DOMAIN { -} - -br.DOMAIN { -} - -a.link { -} -a.link-file { -} - -/* When block quote with _cite:*/ -a.figc { -} - -a.anchor_link { -} - -abbr.DOMAIN { -} - -img.DOMAIN_image { -} - -ul.DOMAIN { -} -li.DOMAIN { -} - -/* Words tags*/ -code.icode { -} -strong.DOMAIN { -} -b.DOMAIN { -} -em.DOMAIN{ -} -i.DOMAIN { -} -del.DOMAIN { -} -u.DOMAIN { -} -cite.DOMAIN { -} -span.custom { -} - -/* Block-code */ -code.DOMAIN { -} -pre.bcode { -} -p.bcode { -} - -/* section for author and date */ -div#article_infos { -} -span#article_author { -} -span#article_pub { -} -span#article_code { -} -a#article_code_link { -} - - -/* Sitemap */ -ul.sitemap { -} - - -/*===================================================================== - * sidebar -*/ - -aside#sidebar { -} -h2#sidebar_title { -} -ul#sidebar_list { -} -li.sidebar_item { -} -a.sidebar_item_link { -} -h3.sidebar_item_title { -} -p.sidebar_item_about { -} - - -/*===================================================================== - * footer -*/ -footer#footer_page { -} - -/* container for footer_infos + footer_references */ -div#footer_container { -} - -/* Block*/ -div#footer_infos { -} -h2#footer_site_title { -} -p#footer_about { -} - -/* Block */ -div#footer_references { -} -ul.footer_items { -} -li.footer_item { -} -a.footer_item_link { -} - -/* Block */ -div#footer_credits { -} -p.footer_copyright { -} -p.footer_generator { -} diff --git a/src/var/lib/tyto/help/tyto_domain.default b/src/var/lib/tyto/help/tyto_domain.default deleted file mode 100644 index 6b2404d..0000000 --- a/src/var/lib/tyto/help/tyto_domain.default +++ /dev/null @@ -1,84 +0,0 @@ -# Home Domain -directory = "" -database = "" - -# Local user configuration -lang_sys = "" -local_user = "" -lang_logs = "" -articles_db_d = "" - -# Working directories -articles_d = "" -files_d = "" -images_d = "" -modules_d = "" - -# Modules files -navbar_f = "" -sidebar_f = "" -metas_f = "" -footer_f = "" - -# Domain -shortname = "" -www_url = "" -wip_url = "" - -# Servers directories -srv_root = "/var/www/" -srv_domain = " -srv_wip = "" -srv_wip_tpl_d = "" -srv_wip_images_d = "" -srv_wip_files_d = "" -srv_www = "" -srv_www_tpl_d = "" -srv_www_images_d = "" -srv_www_files_d = "" - -# Servers files (wip) -wip_favicon_f = "" -wip_logo_f = "" -wip_css_f = "" -wip_navbar_f = "" -wip_sidebar_f = "" -wip_metas_f = "" -wip_footer_f = "" -wip_stats_f = "" - -# Servers files (www) -www_favicon_f = "" -www_logo_f = "" -www_css_f = "" -www_navbar_f = "" -www_sidebar_f = "" -www_metas_f = "" -www_footer_f = "" -www_stats_f = "" -www_rss_f = "" - -# Domain user's settings -favicon = "favicon.png" -logo = "logo.png" -styles = "styles.css" -rss = "rss.xml" -rss_items = 100 -title = "" -date = "" -about = "" -lang_site = "" -mail = "" -tags = "" -license = "gfdl-1.3" -license_url = "" -legal_url = "" -terms_url = "" -css = "tyto" -sep = "-" -article_code = True -relme = "" -sidebar_title = "" -sidebar_items = 6 - -activated = False diff --git a/src/var/lib/tyto/program/args.py b/src/var/lib/tyto/program/args.py index 69dafa1..e165e27 100644 --- a/src/var/lib/tyto/program/args.py +++ b/src/var/lib/tyto/program/args.py @@ -1,174 +1,102 @@ #!/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 Affero General Public License -# as published by the Free Software Foundation, either version 3 of the -# License, or of the License, or (at your option) any later version. -# +# 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License +# 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 arguments from command line +# Description: Manage arguments from command line # File: /var/lib/tyto/program/args.py #---------------------------------------------------------------------- #------------------------- # Funny Stats Project #------------------------- -# file lines : 174 -# file comments : 29 -# file functions: 2 -# file program : 135 +# file lines : +# file comments : +# file functions: +# file program : #-------------------------- +import sys +import langs, tyto, debug, help, new, check, userset, show -import os, sys -import infos -try: - action - target - -except: - - # Arguments from command line - # tyto [action] [target] - #---------------------------- - actions = \ - ( - 'check', - 'edit', - 'edit-db', - 'edit-wip', - 'edit-www', - 'force-wip', - 'new', - 'preview', - 'publish', - 'quick-pub', - 'show', - 'show-db', - 'show-wip', - 'show-www', - 'status', - 'wip', - ) - - quicks = \ - ( - 'force-wip', - 'quick-pub', - ) - - options = \ - ( - '--static', - ) - - pass_actions = ('new') - - # Actions that needs to check for article's database - pass_db = \ - ( - 'check', - 'edit', - 'edit-db', - 'edit-wip', - 'edit-www', - 'force-wip', - 'publish', - 'preview', - 'quick-pub', - 'show', - 'show-about', - 'show-db', - 'show-wip', - 'show-www', - 'status', - 'wip', - ) - - pass_targets = \ - ( - 'added', - 'again', - 'updated', - 'domain', - 'footer', - 'metas', - 'navbar', - 'sidebar', - 'sitemap', - 'stats', - 'template' - ) - - pass_status = \ - ( - 'domain', - ) - - multi_chk = \ - ( - 'added', - 'again', - 'updated' - ) - - helps = \ - ( - 'domains', - 'version', - 'help' - ) - - - # action - #------- +#==================# +# Action Arguments # +#------------------# +def get_action(): + global action try: action = sys.argv[1] - except: action = '' + except: action = "" - act_err = False - - # With no argument, show help - if not action: - infos.tyto('full') - sys.exit(0) - - elif action in helps: - infos.tyto(action) - - # Unused argument [action] - elif not action in actions: - act_err = True - - - # target - #------- - try: - target = sys.argv[2] - except: - infos.tyto('full') - sys.exit(0) - - # options - try: option = sys.argv[3] - except: option = '' -# Set action and target for binary -def set_action(): - return(action) -def set_target(): - return(target) +#==================# +# Target arguments # +#------------------# +def get_target(): + global target + try: target = sys.argv[2] + except: target = "" + + +#================================# +# Searching options in arguments # +#--------------------------------# +def get_options(): + global dlogs, force, erron + + 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 + + +#===========# +# Show logs # +#-----------# +def valid_action(): + global action + if not action in tyto.actions: + debug.out(1, "[action]", action, dlogs,2, False) + action = "help" + + +#==============# +# 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, + "show" : show.manage, + } + + do[action](action, target) + diff --git a/src/var/lib/tyto/program/check.py b/src/var/lib/tyto/program/check.py index bea51a9..e2c99ea 100644 --- a/src/var/lib/tyto/program/check.py +++ b/src/var/lib/tyto/program/check.py @@ -1,1146 +1,43 @@ #!/usr/bin/env python3 # Tyto - Littérateur -# -# Copyright (C) 2023 Cyrille Louarn -# + +# Copyright (C) 2023 Cyrille Louarn + # This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License -# as published by the Free Software Foundation, either version 3 of the -# License, or of the License, or (at your option) any later version. -# +# 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License +# 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 'check' argument. -# Check article's validity in Tyto's format +# Description: Mainly to check article, but also domain and more # File: /var/lib/tyto/program/check.py #---------------------------------------------------------------------- #------------------------- # Funny Stats Project #------------------------- -# file lines : 1146 -# file comments : 163 -# file functions: 25 -# file program : 873 +# file lines : +# file comments : +# file functions: +# file program : #-------------------------- -import time, importlib, sys, os, re, datetime -from datetime import datetime -from time import gmtime, strftime -import args, dom, logs, status, db, form, tyto, langs, wip, html +import sys +import domain -domain_dir = post_err = multi_chk = False +def manage(action, target): + # Load domain configuration, update if needed, check if valid + domain.valid_conf() -#=========================# -# Manage Argument 'check' # -# Start checking article # -#-------------------------#-------------------------------------------- -def manage(target): - dom.valid() - - # target needed - if not target: - logs.out("5", '[target]', True) - - # update, again, newer - elif target in args.multi_chk: - check_all(target) - - # modules (sidebar...) - elif target in args.pass_targets: - check_module(target) - return - - # Unused file - elif not db.post: - logs.out("1", db.uri_file, True) - - # Already check - elif db.exists: - db.show_title() - if not db.old_chk and not args.option == "--force": - logs.out("20", '%s > %s'%(db.date_chk, db.uri_file), False) - answer = form.asking(' ├ %s%s '%( - langs.site.check_a, langs.site.q - ), True) - check_process(target) - - else: - check_process(target) - - # Article is not valid - if post_err and not target in args.multi_chk: - logs.out("7", db.uri_file, True) - - -#===============================# -# Argument is a module name # -# Check if modules files exists # -#-------------------------------# -def check_module(target): - if target == "domain": - status.check(target) - return - - try: - unused_f = False - logs.out("60", '', False) - for t in dom.modules[target]: - if not os.path.exists(t): - logs.out("24", t, False) - unused_f = True - - if not unused_f: - logs.out("28", "%s"%langs.log.all_ok, False) - - except: - logs.out("28", "%s + %s"%(args.action, target), True) - - -#==============================================# -# Argument all # -# check all realdy checkded articles # -# but check only if article source has changed # -#----------------------------------------------# -def check_all(option): - global multi_chk - multi_chk = True - found = False - - # With [added], article must NOT have a DB - # Search every .tyto in domain from articles/ - # Then Do a check, and return - #----------------------------------------- - if option == "added": - no_post = True - for root, dirs, files in os.walk(dom.articles_d[:-1]): - for file in files: - if (file.endswith('.tyto')): - uri_file = "%s/%s"%(root, file) - uri_id = tyto.get_filesum(uri_file, False) - args.target = uri_file.rsplit(dom.articles_d)[1] - db_config = "%s%s.config"%(dom.articles_db_d, uri_id) - if os.path.exists(db_config): - continue - - no_post = False - importlib.reload(db) - check_process(args.target) - print() - - if no_post: - logs.out("28", '%s'%langs.log.nonewpost, True) - return - - # With [updated], Article must have changed - # with [again], force check - # Article must have a DB - #------------------------------------------ - for post_db in os.listdir(dom.articles_db_d): - if post_db.endswith('.config'): - # Load DB - post_db = '%s%s'%(dom.articles_db_d, post_db) - try: - exec(open(post_db).read(),globals()) - args.target = short_src - importlib.reload(db) - except: - continue - - if option == 'updated' and not db.chk_updated: continue - if option == 'again' and not db.chk_again: continue - - found = True - check_process(args.target) - - if post_err: logs.out("44", args.target, False) - - if not found: logs.out("28", args.action, True) - - -#========================# -# Check articles process # -#------------------------# -def check_process(target): - global post_err - - if not db.post: - logs.out("1", db.post, False) - post_err = True - return - - # Start checking processes - #------------------------- - # Convert file to string - # Also check for separator and empty article - file_to_string() - if post_err: - return - - global post_bottom, article_bottom - global date_wip, hash_wip, date_www, hash_www, post_bottom - - date_wip = hash_wip = date_www = hash_www = '' - - # Set values for wip and www from DB - if db.exists: - date_wip = db.date_wip - hash_wip = db.hash_wip - date_www = db.date_www - hash_www = db.hash_www - - # Get extension from target, set short uris - ext_src = os.path.splitext(target) - - # Get uri after articles/ (no starting / in value) - global src_post_short_uri, srv_post_short_uri, direc_src - global srv_post_wip_uri, srv_post_www_uri - - src_post_short_uri = db.uri_file.rsplit(dom.articles_d)[1] - srv_post_short_uri = src_post_short_uri.replace(ext_src[1], '.html') - srv_post_wip_uri = dom.srv_wip + srv_post_short_uri - srv_post_www_uri = dom.srv_www + srv_post_short_uri - direc_src = src_post_short_uri.split("/")[-1] - direc_src = src_post_short_uri.rsplit(direc_src)[0] - - # Get sub_uri for HTML - global sub_uri - sub_uri = db.uri_file.rsplit('articles/')[1] - sub_nbr = sub_uri.count('/') - if sub_nbr == 0: sub_uri = './' - else: sub_uri = sub_nbr * '../' - - # Set HTTP link for wip and www - global http_www, http_wip - if srv_post_short_uri.endswith('index.html'): - http_www = "%s/%s"%(dom.www_url, direc_src) - http_wip = '%s/%s'%(dom.wip_url, direc_src) - else: - http_www = "%s/%s"%(dom.www_url, srv_post_short_uri) - http_wip = '%s/%s'%(dom.wip_url, srv_post_short_uri) - - # Check for icodes, bcodes, quotes - # check icodes marks on same line - if_icodes_bcodes_quotes(post_bottom) - - # Protect block-codes and quotes - if bcode or quote: - tyto.protect_bcodes_quotes('check', post_bottom) - post_bottom = tyto.protect_article - - # Protect inline-codes - if icode: post_bottom = tyto.protect_icodes(post_bottom) - - # Replace escaped markers - post_bottom = tyto.protect_escaped(post_bottom, False) - - - # Check header tags configurations - check_needed_tags(post_header.rsplit('\n')) - if post_err: - if db.exists and tyto.exists(db.config): - os.remove(db.config) - return - print(' │\n ├ [%s] > %s'%(title, db.uri_file)) - - - # Check optional tags configuration - check_opt_tags(post_header.rsplit('\n')) - if post_err: - if db.exists and tyto.exists(db.config): - os.remove(db.config) - return - - check_titles() # #1-5 (titles) - check_words_tags() # Strongs, italics... - check_blocks_tags() # Paragraphs, quotes... - check_anchors() # Anchors - check_contents_list() # Lists ul/ol contents - check_legacy_HTML() # Real HTML tags - check_tags_set() # Check _TAG:Name (_image:Name) - check_contents_writer() # Convinience - - # Remove db (if exists) on post error and return - if post_err: - if db.exists and tyto.exists(db.config): - os.remove(db.config) - return - - # COunt words - count_words(post_bottom.rsplit("\n")) - - # Create article's database - create_database() - - -#=================================# -# Create string article from file # -# Check if separator or exit # -#---------------------------------# -def file_to_string(): - global post_err - global article, post_header, post_bottom - global ln_header, ln_bottom, ln_article - - post_err = False - post_header = post_bottom = '' - sep = content = False - article = open(db.uri_file, 'r').read() - - for line in article.rsplit('\n'): - if line.startswith(logs.shebang): - print(' │') - logs.out("82", db.uri_file, False) - post_err = True - return - - if line.startswith('-----'): - if not sep: - sep = True - continue - - if sep: - if line: content = True - if not post_bottom: post_bottom = line - else: post_bottom = '%s\n%s'%(post_bottom, line) - else: - if not post_header: post_header = line - else: post_header = '%s\n%s'%(post_header, line) - - # Check if separator or exit - if not sep: - print(' │') - logs.out("6", '"-----" > %s'%db.uri_file, False) - post_err = True - return - - if not content: - if db.exists and tyto.exists(db.config): - os.remove(db.config) - logs.out("18", db.uri_file, False) - post_err = True - return - - # +2 > (start at 0 + separator line) - ln_article = len(article.splitlines()) + 1 - ln_header = len(post_header.splitlines()) + 2 - ln_bottom = len(post_bottom.splitlines()) + 2 - - -#=========================================# -# Count words in article. # -# Quotes, block-codes, icode = 1 per each # -# At db creation, remove title numbers # -#-----------------------------------------" -def count_words(post_bottom): - global post_words - post_words = 0 - - for line in post_bottom: - if not line \ - or line.startswith(tyto.nolinewords) \ - or line.startswith("#") and not line.startswith(tyto.titles_user): - continue - - post_words = post_words + len(line.strip().split(" ")) - - -#=============================================# -# Check if bcodes and quotes # -# Check inline code, for markers on same line # -# Stats for titles, quotes, bcodes, uniq_ancs # -#---------------------------------------------# -def if_icodes_bcodes_quotes(post_bottom): - global icode, quote, bcode, post_err - global nbr_quotes, nbr_bcodes, nbr_ancs, post_comments - global post_images, post_raws, fcodes - - icode = quote = in_quote = bcode = in_bcode = in_bq = False - nbr_quotes = nbr_bcodes = nbr_ancs = 0 - post_images = post_comments = post_raws = fcodes = 0 - - for ln, line in enumerate(post_bottom.rsplit('\n'), 1): - # Stat Comments, Titles, Anchors - if not line: - continue - - # quotes - elif line.startswith(tyto.block_tags[1][0]) and not in_bcode: - quote = in_quote = in_bq = True - continue - elif line.startswith(tyto.block_tags[1][1]): - in_quote = False - nbr_quotes += 1 - continue - - # bcode - elif line.startswith(tyto.block_tags[2][0]) and not in_quote: - bcode = in_bcode = in_bq = True - continue - elif line.startswith(tyto.block_tags[2][1]): - in_bcode = False - nbr_bcodes += 1 - continue - - if in_bq: - continue - - elif line.startswith('#') and not line.startswith(tyto.titles_user): - post_comments += 1 - continue - elif line.startswith(tyto.single_tags[1][0]): - nbr_ancs += 1 - continue - elif line.startswith('_image:'): - post_images += 1 - elif line.startswith('_raw:'): - post_raws += 1 - elif line.startswith('_code:'): - fcodes += 1 - - # icodes - elif tyto.icode_tags[0] in line or tyto.icode_tags[1] in line: - icode_m1 = icode_m2 = 0 - icode_m1 = line.count(tyto.icode_tags[0]) - icode_m2 = line.count(tyto.icode_tags[1]) - if icode_m1 != icode_m2: - logs.out("8", 'L=%s. icode "%s" + "%s" > %s'%( - ln + 1 + ln_header, - tyto.icode_tags[0], tyto.icode_tags[1], - db.uri_file - ), False - ) - post_err = True - else: - icode = True - - -#=========================================# -# Check needed tags from article's header # -# Each one must be uniq. Only first taken # -#-----------------------------------------# -def check_needed_tags(post_header): - global post_err - global title, author, about, tags, date, sitemap - global stat_tags - - title = author = about = tags = '' - sitemap = "True" - date = () - stat_tags = 0 - - # Check post header for each needed tags - for tag in tyto.needed_header_tags: - for ln, line in enumerate(post_header, 1): - # Sitemap : set to False if #NoSitemap - if line.startswith("# NoSitemap"): - sitemap = "False" - - # Break if already set - if globals()[tag]: - break - - # Set data from tag - if line.startswith('%s:'%tag): - globals()[tag] = line.rsplit('%s:'%tag)[1].lstrip() - globals()[tag] = tyto.convert_altname(globals()[tag]) - - # Stat for "tags:" - if tag == 'tags': - stat_tags = len(globals()[tag].strip().split(",")) - - # Check if unused needed tags - for tag in tyto.needed_header_tags: - if not globals()[tag]: - logs.out("38", '%s:'%tag, False) - post_err = True - - # Check date format - # Set french format in post DB - if not post_err: - check_date(date) - - -#================================# -# Check Date format and validity # -# Create False date_check # -#--------------------------------# -def check_date(date): - global post_err, date_tr - - # Check if article date is valid (True) - date_tr = date - fmt_article = "%Y-%m-%d" - - try: - bool(datetime.strptime(date, fmt_article)) - except ValueError: - post_err = True - logs.out("3", 'date: "%s" (YYYY-MM-DD) > %s'%( - date, db.uri_file - ), False) - - # Create date_check (epoch) from article's Date + now TIME - if not post_err: - fmt_check = '%Y-%m-%d %H:%M:%S' - time_check = strftime("%H:%M:%S", gmtime()) - date_check = date + ' ' + time_check - date_check = time.mktime(time.strptime(date_check, fmt_check)) - - # Set franch format in post DB - if dom.lang_site == 'fr': - date = date.rsplit('-') - date_tr = date[2] + '/' + date[1] + '/' + date[0] - - -#===========================================# -# Check optional tags from article's header # -# Multiple settings for each on 3 lines # -#-------------------------------------------# -def check_opt_tags(post_header): - global stat_links, stat_images, stat_files, stat_raws, stat_codes - global post_links, stat_snpics, snpic_url, stat_abbrs, post_abbrs - global post_files, opt_tags_post_name - global files_post - - # Statistics - stat_links = stat_images = stat_files = stat_raws = stat_codes = 0 - post_links = post_files = stat_snpics = post_abbrs = stat_abbrs = 0 - files_post = (()) - - # Set default post pic - snpic_url = '%s/template/%s'%(dom.www_url, dom.logo) - - # Search for term in article - opt_tags_post_name = \ - { - "link" : "_%s", - "image" : "_image:%s", - "file" : "__%s", - "raw" : "_raw:%s", - "code" : '_code:%s', - "abbr" : "(%s)" - } - - # Check post header for each optional tags - for tag in tyto.opt_header_tags: - for ln, line in enumerate(post_header, 1): - if line.startswith('%s:'%tag): - check_3lines(tag, ln, line) - - -#===================================# -# Check if registred value is valid # -#-----------------------------------# -def valid_data_name(tag, name): - global post_err - data_inv = '' - data_err = False - - for c in name: - if c in tyto.chrs_invalid: - post_err = True - data_err = True - data_inv = '%s%s'%(data_inv, str(c)) - - if data_err: - logs.out("3", '"%s: %s" > %s'%(tag, name, data_inv), False) - return False - - return True - - -#============================================# -# Do stats, check 3 lines tags from ln # -# Set data for each 2 next lines # -# Exception for snpic (Different conditions) # -#--------------------------------------------# -def check_3lines(tag, ln, line): - global post_err, db_tag, files_post, post_bottom - global post_abbrs, post_links, post_files - - stat_tag = "stat_%ss"%tag - - # Create variable for post DB - globals()[stat_tag] += 1 - db_tag = '%s_%s'%(tag, globals()[stat_tag]) - globals()[db_tag] = (()) - - # NAME - #----- - # ln is legacy (from loop), so take line content - # Take only first word if not a long name tag - if tag in tyto.opt_tags_long_name: - name = line.rsplit('%s:'%tag)[1].lstrip() - else: - name = line.rsplit('%s:'%tag)[1].lstrip().rsplit(' ')[0] - if not valid_data_name(tag, name): return - - - if not name: - logs.out("2", 'L=%s. "%s: %s" > %s'%( - ln, tag, langs.site.name, db.uri_file - ), False) - post_err = True - if tag == "snpic": - return - - # abbr: - elif tag == "abbr": - name_abbr = name.upper() - post_abbrs = post_bottom.count('(%s)'%name_abbr) - - # snpic only needs a Name - elif tag == "snpic": - check_snpic(name) - return - - elif not isin("%s"%(opt_tags_post_name[tag]%name), post_bottom): - logs.out("12", '"%s" > %s'%( - opt_tags_post_name[tag]%name, db.uri_file - ), False) - post_err = True - - globals()[db_tag] = ((opt_tags_post_name[tag]%name),) - - if tag == "file": - post_files = post_files + post_bottom.count('__%s'%name) - post_bottom = post_bottom.replace('__%s'%name, '[file-link]') - elif tag == "link": - post_links = post_links + post_bottom.count('_%s'%name) - - # URI/URL and Alt-Text - #--------------------- - # loop 1,2. Next real line from start tag - for l in range(1,3): - if l == 1: data_log = "URI/URL" - elif l == 2: data_log = "Alt-Text" - - ln += 1 - data = '' - - try: - # ln - 1 as string post_header starts with 0 - data = post_header.rsplit('\n')[ln - 1].lstrip() - if data.startswith(tyto.headers): data = '' - except: - data = '' - - if not data and not l == 2 and not tag == 'raw': - logs.out("2", 'L=%s. "%s" (%s:) > %s'%( - ln, data_log, tag, db.uri_file - ), False) - post_err = True - - # Convert special characters for HTML - if not tag in tyto.opt_tags_check_uri: - data = tyto.convert_altname(data) - - # For tags having URI, check if file exists - # Set data for post DB - if l == 1 and tag in tyto.opt_tags_check_uri: - check_file_uri(tag, data, ln) - if post_err: - return - globals()[db_tag] = globals()[db_tag] + ((web_uri),) - files_post = files_post + (('%s'%web_uri),) - - else: - if post_err: - return - globals()[db_tag] = globals()[db_tag] + ((data),) - - -#=====================# -# Find in post_bottom # -#---------------------# -def isin(term, post_file): - paterm = re.escape(term) - - if re.search(paterm, post_file): return(True) - else: return(False) - - - -#===================================# -# Check if file exists # -# Get filetype, filename, i=var nbr # -#-----------------------------------# -def check_file_uri(filetype, filename, ln): - global post_err, err, web_uri - - filetypes = ('file', 'raw', 'code') - - # Set file uri from filename - # (@ = images/ or files/ - # / = articles/ - # Else in post_dir - if filename.startswith('@'): - if filetype in filetypes: - fileuri = dom.files_d + filename[1: len(filename)] - - elif filetype == 'image' or filetype == "snpic": - fileuri = dom.images_d + filename[1: len(filename)] - - else: - post_dir = db.uri_file.split("/")[-1] - post_dir = db.uri_file.rsplit(post_dir)[0] - if filename.startswith('/'): - fileuri = post_dir + filename[1: len(filename)] - else: - fileuri = post_dir + filename - - # Check if file exists - if not filetype == "snpic" and not tyto.exists(fileuri): - logs.out("1", "L=%s. %s > %s"%(ln, fileuri, db.uri_file), False) - post_err = True - return - - web_uri = '/' + fileuri.replace(dom.articles_d, "") - - -#====================================# -# Check for snpic # -# (Used pic for social network) # -# Needs: # -# - a Name # -# - an image tag set with same name # -#-----------------------------------# -def check_snpic(name): - global snpic_url, snpic_post, post_err - - try: - snpic_post - return - except: - pass - - # Search post_header for image: %name - found = False - tag = tyto.opt_header_tags[1] - for ln, line in enumerate(post_header.rsplit('\n'), 1): - if line.startswith('%s:'%tag): - try: - check_name = line.rsplit('%s:'%tag)[1].lstrip().rsplit(' ')[0] - except: - check_name = '' - - if check_name == name: - found = True - snpic_post = post_header.rsplit('\n')[ln].lstrip() - check_file_uri("snpic", snpic_post, ln) - break - - if not found: - logs.out("27", '"%s: %s" > %s'%(tag, name, db.uri_file), False) - post_err = True - return - - snpic_post = True - snpic_url = dom.www_url + web_uri - - -#==========================================# -# Check anchors target and links # -# Check for duplicate anchor name target # -# Cannot have anchors links without target # -#------------------------------------------# -def check_anchors(): - global post_err - - c_opened = c_closed = 0 - c_opened = post_bottom.count(tyto.anchor_tags[0]) - c_closed = post_bottom.count(tyto.anchor_tags[1]) - - if c_opened != c_closed: - logs.out("8", '%s "%s" + "%s" > %s'%( - tyto.anchor_tags[4], - tyto.anchor_tags[0], tyto.anchor_tags[1], - db.uri_file - ), False) - post_err = True - return - - globals()['post_%s'%tyto.anchor_tags[4]] = int(c_opened) - - - # Anchor target - if nbr_ancs > 0: - # Create anchors names targets - anchors_names = (()) - for line in post_bottom.rsplit('\n'): - if line.startswith(tyto.single_tags[1][0]): - name = tyto.get_css(line) - anchors_names = anchors_names + ((name),) - - # Check for uniq anchor_name - for name in list(anchors_names): - if anchors_names.count(name) > 1: - post_err = True - logs.out("15", '"%s %s" > %s'%( - tyto.single_tags[1][0], name, db.uri_file - ), False) - break - - # Anchor link - if post_anchors == 0: - return - - # Article has anchors links but no anchor target - elif nbr_ancs == 0: - logs.out("12", "%s [NAME] > %s"%( - tyto.single_tags[1][0], db.uri_file - ), False) - post_err = True - return - - # Check if anchor link has target one - else: - for ln, line in enumerate(post_bottom.rsplit('\n'), 1): - ln = ln + ln_header + 1 - - # Anchor link - if tyto.anchor_tags[0] and tyto.anchor_tags[1] in line: - anchors = re.findall(r">_(.*?)_<", line) - for anchor in anchors: - anchor_name = anchor.rsplit(':')[0].lstrip() - if not anchor_name in anchors_names: - logs.out("12", 'L=%s. anchor "%s" > %s'%( - ln, anchor_name, db.uri_file - ), False) - post_err = True - - -#==========================# -# Check titles and content # -#--------------------------# -def check_titles(): - global post_err, post_titles - post_titles = 0 - - for ln, line in enumerate(post_bottom.rsplit('\n'), 1): - ln = ln + ln_header + 1 - - if line.startswith(tyto.titles_user): - title_name = line[2: len(line)].lstrip() - if not title_name: - post_err = True - logs.out("84", 'L=%s > %s'%(ln, db.uri_file), False) - continue - - post_titles += 1 - - -#============================================# -# Check tags for words (strongs, italics...) # -# Set stats for each one # -#--------------------------------------------# -def check_words_tags(): - global post_err, post_bottom - - for tag in tyto.markers_tags: - c_opened = c_closed = 0 - - c_opened = post_bottom.count(tag[0]) - c_closed = post_bottom.count(tag[1]) - # Useless tag now, replace - post_bottom = post_bottom.replace(tag[0], '') - post_bottom = post_bottom.replace(tag[1], '') - - if c_opened != c_closed: - logs.out("8", '%s "%s" + "%s" > %s'%( - tag[4], tag[0], tag[1], db.uri_file - ), False) - post_err = True - - else: - globals()['post_%s'%tag[4]] = int(c_opened) - - -#=========================================# -# Check block tags paragraphs, quotes...) # -# Set stats for each one # -#-----------------------------------------#- -def check_blocks_tags(): - global post_err - - for tag in tyto.block_tags: - c_opened = c_closed = 0 - - for line in post_bottom.rsplit('\n'): - if line.startswith(tag[0]): c_opened += 1 - if line.startswith(tag[1]): c_closed += 1 - - if c_opened != c_closed: - logs.out("8", '%s "%s" + "%s" > %s'%( - tag[4], tag[0], tag[1], db.uri_file - ), False) - post_err = True - - else: - globals()['post_%s'%tag[4]] = int(c_opened) - - -#====================================# -# Lists: check if contents are valid # -#------------------------------------# -def check_contents_list(): - global post_err - - if post_lists > 0: - inlist = False - for ln, line in enumerate(post_bottom.rsplit('\n'), 1): - ln = ln + ln_header + 1 - - if line.startswith(tyto.block_tags[3][0]): - inlist = True - continue - elif line.startswith(tyto.block_tags[3][1]): - inlist = False - - if not inlist: - continue - - if inlist and not line or not line[0] in tyto.markers_lists: - logs.out("3", 'L=%s. %s %s > %s'%( - ln, - tyto.block_tags[3][4], - tyto.markers_lists, - db.uri_file - ), False) - post_err = True - - -#==================================# -# Legacy HTML Tags, check if aired # -#----------------------------------# -def check_legacy_HTML(): - global post_err - - for tag in tyto.leg_html_tags: - leg1 = post_bottom.count(tag[0]) - leg2 = post_bottom.count(tag[1]) - - if leg1 != leg2: - logs.out("8", '"%s" + "%s" > %s'%( - tag[0], tag[1], db.uri_file - ), False) - post_err = True - - -#================================# -# Check for all match _TAGS:NAME # -# (from content in header) # -# _image:, _raw:... # -#--------------------------------# -def check_tags_set(): - global post_err - - set_tags = () - for ln, line in enumerate(post_bottom): - for htag in tyto.head_tags: - match = False - ptag = '_%s'%htag - - if line.startswith(ptag): - ptag_set = line.rsplit(':', 1)[1].lstrip().rsplit(' ')[0] - if ptag_set in set_tags: continue - for hline in post_header: - if re.search(r"^%s\s+%s$"%(htag, ptag_set), hline): - match = True - set_tags = (ptag_set) - - if match: continue - else: - logs.out("12", "%s %s"%(htag, ptag_set), False) - post_err = True - - -#================================================# -# Template Tags (warning for not paired symbols) # -#------------------------------------------------# -def check_contents_writer(): - for tag in tyto.tpl_tags: - tpl1 = post_bottom.count(tag[0]) - tpl2 = post_bottom.count(tag[1]) - - if tpl1 != tpl2: - logs.out("22", '%s*%s + %s*%s > %s'%( - tpl1, tag[0], tpl2, tag[1], db.uri_file - ), False) - - -#==============================================# -# Check if articles in servers are static Page # -#----------------------------------------------# -def check_static_posts(): - global wip_static, www_static - wip_static = www_static = 'False' - - srv_posts = \ - [ - (srv_post_wip_uri, 'wip_static'), - (srv_post_www_uri, 'www_static') - ] - - for srv_post, static in srv_posts: - try: - post_datas = open(srv_post, "r").read() - if not re.findall( - html.tags_html_mods[dom.wip_metas_f], - post_datas - ): - globals()[static] = "True" - except: - continue - - -#===============================# -# Create new article's database # -#------------------------------&co-# -def create_database(): - # Check if article is in servers - check_static_posts() - - - # Post Configurations - #-------------------- - database = \ - '# Writer configurations\n' + \ - 'title = "%s"\n'%title + \ - 'about = "%s"\n'%about + \ - 'author = "%s"\n'%author + \ - 'meta_tags = "%s"\n'%tags + \ - 'date = "%s"\n'%date_tr + \ - 'snpic = "%s"\n'%snpic_url + \ - 'sitemap = %s\n'%sitemap + \ - '\n# Post Configurations\n' + \ - 'post_id = "%s"\n'%db.uri_id + \ - 'post_src = "%s"\n'%db.uri_file + \ - 'direc_src = "%s"\n'%direc_src + \ - 'short_src = "%s"\n'%src_post_short_uri + \ - 'short_srv = "%s"\n'%srv_post_short_uri + \ - 'sub_uri = "%s"\n'%sub_uri + \ - 'date_chk = "%s"\n'%tyto.nowdate() + \ - 'hash_chk = "%s"\n'%db.hash_post + \ - '\n# wip configuration\n' + \ - 'post_wip = "%s"\n'%srv_post_wip_uri + \ - 'http_wip = "%s"\n'%http_wip + \ - 'static_wip = %s\n'%wip_static + \ - 'date_wip = "%s"\n'%date_wip + \ - 'hash_wip = "%s"\n'%hash_wip + \ - '\n# www configuration\n' + \ - 'post_www = "%s"\n'%srv_post_www_uri + \ - 'http_www = "%s"\n'%http_www + \ - 'static_www = %s\n'%www_static + \ - 'date_www = "%s"\n'%date_www + \ - 'hash_www = "%s"\n'%hash_www + \ - '\n# Used files\n' + \ - 'uris = %s'%str(files_post) - - - # Tags configuration - #------------------- - datas_tag = '' - if stat_abbrs > 0: - for i in range(1, stat_abbrs + 1): - datas_tag = '%s\nabbr_%s = %s'%( - datas_tag, i, globals()['abbr_%s'%i] - ) - - if stat_links > 0: - for i in range(1, stat_links + 1): - datas_tag = '%s\nlink_%s = %s'%( - datas_tag, i, globals()['link_%s'%i] - ) - - if stat_images > 0: - for i in range(1, stat_images + 1): - datas_tag = '%s\nimage_%s = %s'%( - datas_tag, i, globals()['image_%s'%i] - ) - - if stat_files > 0: - for i in range(1, stat_files + 1): - datas_tag = '%s\nfile_%s = %s'%( - datas_tag, i, globals()['file_%s'%i] - ) - - if stat_codes > 0: - for i in range(1, stat_codes + 1): - datas_tag = '%s\ncode_%s = %s'%( - datas_tag, i, globals()['code_%s'%i] - ) - - if stat_raws > 0: - for i in range(1, stat_raws + 1): - datas_tag = '%s\nraw_%s = %s'%( - datas_tag, i, globals()['raw_%s'%i] - ) - - - opt_tags = '' - if datas_tag: - opt_tags = \ - '\n# Optional tags configurations' + \ - '%s\n'%datas_tag - - # Statistics configurations - #-------------------------- - stat_words = post_words - post_titles # Count real words - - db_stats = \ - '# Statistics from header\'s tags\n' + \ - 'uniq_anchors = %d\n'%nbr_ancs + \ - 'uniq_abbrs = %d\n'%stat_abbrs + \ - 'uniq_links = %d\n'%stat_links + \ - 'uniq_images = %d\n'%stat_images + \ - 'uniq_files = %d\n'%stat_files + \ - 'uniq_codes = %d\n'%stat_codes + \ - 'uniq_raws = %d\n'%stat_raws + \ - '\n# Statistics from post contents\n' + \ - 'comments = %d\n'%post_comments + \ - 'tags = %d\n'%stat_tags + \ - 'lines = %d\n'%ln_article + \ - 'words = %d\n'%stat_words + \ - 'titles = %d\n'%post_titles + \ - 'paragraphs = %d\n'%post_paragraphs + \ - 'links = %d\n'%post_links + \ - 'images = %d\n'%post_images + \ - 'anchors = %d\n'%post_anchors + \ - 'abbrs = %d\n'%post_abbrs + \ - 'strongs = %d\n'%post_strongs + \ - 'bolds = %d\n'%post_bolds + \ - 'emphasis = %d\n'%post_emphasis + \ - 'italics = %d\n'%post_italics + \ - 'dels = %d\n'%post_dels + \ - 'underlines = %d\n'%post_underlines + \ - 'cites = %d\n'%post_cites + \ - 'customs = %d\n'%post_customs + \ - 'icodes = %d\n'%tyto.nbr_icodes + \ - 'bcodes = %d\n'%nbr_bcodes + \ - 'quotes = %d\n'%nbr_quotes + \ - 'lists = %d\n'%post_lists + \ - '\n# Included files in post\'s contents\n' + \ - 'files = %d\n'%post_files + \ - 'raws = %d\n'%post_raws + \ - 'codes = %d\n'%fcodes - - # Create Post DB - #--------------- - database = '%s\n%s\n%s'%(database, opt_tags, db_stats) - tyto.set_file(db.config, 'New', database) - - if not multi_chk: - logs.out("21", db.uri_file, False) - + print("check:", action, target, domain.dcf.get("DOMAIN", "name")) diff --git a/src/var/lib/tyto/program/creators.py b/src/var/lib/tyto/program/creators.py deleted file mode 100644 index f4f3e64..0000000 --- a/src/var/lib/tyto/program/creators.py +++ /dev/null @@ -1,241 +0,0 @@ -#!/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 Affero General Public License -# as published by the Free Software Foundation, either version 3 of the -# License, or of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -#---------------------------------------------------------------------- -# XMPP: echolib (im@echolib.re) -# -# Description: Manage 'creators' argument. -# Create articles -# File: /var/lib/tyto/program/creators.py -#---------------------------------------------------------------------- - -#------------------------- -# Funny Stats Project -#------------------------- -# file lines : 241 -# file comments : 41 -# file functions: 3 -# file program : 182 -#-------------------------- - - -import os, importlib, datetime, subprocess -import args, dom, db, langs, tyto, check, wip, logs - - -#========================# -# Manage action [create] # -#------------------------# -def manage(target): - target = args.target - - creators = { - "sitemap" : create_sitemap, - } - - try: creators[target](target) - except: logs.out("28", "%s + %s"%(args.action, args.target), True) - - -#=====================# -# Set and return date # -#---------------------# -def nowdate(): - now = datetime.datetime.now() - return(now.strftime('%Y-%m-%d')) - - -#============================# -# Create sitemap.tyto file # -# Then check it, and wip it # -# ! sitemap is the "www" one # -# seen in 'wip' server # -#----------------------------# -def create_sitemap(target): - dom.valid() - - # Define sitemap.tyto - sitemap_tyto = \ - '# %s Tyto - Littérateur [tyto new sitemap]\n'%langs.site.sitemap_gen + \ - '# NoSitemap\n' + \ - 'title: %s (%s %s)\n'%(langs.site.sitemap_t, '%s', langs.site.links) + \ - 'about: %s Tyto - Littérateur\n'%langs.site.sitemap_gen + \ - 'author: Tyto\n' + \ - 'tags: sitemap\n' + \ - 'date: %s\n'%nowdate() + \ - '\n' + \ - '%s\n' + \ - '-----\n' + \ - '\n' + \ - '%s\n' + \ - '|\n' + \ - '
\n' + \ - '|\n' + \ - '\n' + \ - '%s\n' - - tab = 8 - uri_dir_set = "" - - # Contents in article's Header - links = "" - - # Index of all links in article - index_l = '-( index\n= /' - - # All links in sitemap - contents = '-( sitemap\n= / ' - - # Not real articles folder - forbid_dir = ( - dom.files_d, - dom.images_d, - dom.modules_d - ) - - # Get all .tyto files from domain - nbr_files = 0 - for r, dirs, files in os.walk(os.getcwd()): - if r.startswith(forbid_dir): - continue - - # Take only .tyto files - for f in files: - if not f.endswith(".tyto"): - continue - - try: - uri_file = r.rsplit(dom.articles_d)[1] - uri_file = os.path.join(uri_file, f) - except: - uri_file = f - - uri_dir = uri_file.rsplit(f)[0] - if not uri_dir: - uri_dir = "~/" - - # Try to load Article Database - args.action = "check" - args.target = uri_file - importlib.reload(db) - if not db.exists: - continue - else: - try: - db.hash_www - db.sitemap - if not db.sitemap: - continue - except: - continue - - # Count - nbr_files += 1 - - # create defined link - if not links: - links = \ - "link: %s\n%s%s\n%s%s\n"%( - db.title, tab * " ", db.short_srv, tab * " ", db.about - ) - else: - links = \ - "%s\nlink: %s\n%s%s\n%s%s\n"%( - links, - db.title, tab * " ", - db.short_srv, tab * " ", db.about - ) - - - # Create list link line - curr_dir = uri_dir.count("/") - root_dir = uri_dir.rsplit("/")[0] - ranc_dir = root_dir.replace(" ", "_") - - - try: prev_dir - except: prev_dir = curr_dir - - try: name_dir - except: name_dir = root_dir - - #print(":",prev_dir, name_dir, curr_dir, root_dir) - #print(": %s"%(uri_dir.rsplit("/")[int(curr_dir - 1)])) - #print(">", subdirs, uri_dir.rsplit("/")) - #print(":", prev_dir, curr_dir) - if name_dir != root_dir: - index_l = '%s\n= %s'%( - index_l, - ranc_dir, - root_dir - ) - contents = '%s\n%s [%s] '%( - contents, - int(curr_dir) * "=", - root_dir, - ranc_dir - ) - name_dir = root_dir - prev_dir = curr_dir - - if prev_dir != curr_dir: - sanc_dir = uri_dir.rsplit("/")[int(curr_dir - 1)].replace(" ", "_") - index_l = '%s\n%s %s'%( - index_l, - int(curr_dir) * "=", - sanc_dir, - uri_dir.rsplit("/")[int(curr_dir - 1)] - ) - contents = '%s\n%s [%s] '%( - contents, - int(curr_dir) * "=", - uri_dir.rsplit("/")[int(curr_dir - 1)], - sanc_dir - ) - prev_dir = curr_dir - - contents = "%s\n%s _%s"%( - contents, - int(curr_dir + 1) * '=', - db.title - ) - - # Ending markers - index_l = "%s\n-)"%index_l - contents = "%s\n-)"%contents - - # Fill new sitemap.tyto and create - sitemap_tyto = \ - sitemap_tyto%( - nbr_files, - links, - index_l, - contents - ) - sitemap_file = "%ssitemap.tyto"%dom.articles_d - tyto.set_file(sitemap_file, "New", sitemap_tyto) - - # Check and wip - print() - www = subprocess.run( - [ - '/usr/bin/tyto', - 'force-wip', - 'sitemap.tyto' - ], - ) diff --git a/src/var/lib/tyto/program/db.py b/src/var/lib/tyto/program/db.py deleted file mode 100644 index cce60ad..0000000 --- a/src/var/lib/tyto/program/db.py +++ /dev/null @@ -1,206 +0,0 @@ -#!/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 Affero General Public License -# as published by the Free Software Foundation, either version 3 of the -# License, or of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -#---------------------------------------------------------------------- -# XMPP: echolib (im@echolib.re) -# -# Description: Load article's database and check validity -# File: /var/lib/tyto/program/db.py -#---------------------------------------------------------------------- - -#------------------------- -# Funny Stats Project -#------------------------- -# file lines : 206 -# file comments : 37 -# file functions: 1 -# file program : 152 -#-------------------------- - - -import os -import args, logs, dom, form, tyto, check, publish - -remove = exists = post = corrupt = file_wip = file_www = False -chk_again = chk_updated = False -wip_again = wip_added = wip_updated = False -www_again = www_added = www_updated = False - -if dom.hole: - logs.out("13", '', True) - - -# target needs db (file). -# action like show, wip, edit-db -# not domain, all, again... -if args.target \ - and args.action in args.pass_db \ - and not args.target in args.pass_targets: - - # Domain must be valid - if not dom.exists: logs.out("10", '', True) - - uri_file = '%s%s'%(dom.articles_d, args.target) - uri_id = tyto.get_filesum(uri_file, False) - - # Set DB file - config = '%s%s.config'%(dom.articles_db_d, uri_id) - if tyto.exists(config): - exists = True - try: - exec(open(config).read()) - except: - exists = False - else: - exists = False - - # Article file exists - if tyto.exists(uri_file): - post = True - hash_post = tyto.get_filesum(uri_file, True) - else: - remove = True - - # Check if database config is valid (contains values) - if exists: - values = \ - ( - 'post_id', - 'post_src', - 'post_wip', - 'static_wip', - 'post_www', - 'static_www', - 'direc_src', - 'short_src', - 'short_srv', - 'sub_uri', - 'http_wip', - 'http_www', - 'date_chk', - 'hash_chk', - 'date_wip', - 'hash_wip', - 'date_www', - 'hash_www', - 'title', - 'about', - 'author', - 'meta_tags', - 'date', - 'snpic', - 'sitemap', - 'uris', - 'uniq_anchors', - 'uniq_abbrs', - 'uniq_links', - 'uniq_images', - 'uniq_files', - 'uniq_raws', - 'comments', - 'tags', - 'words', - 'titles', - 'paragraphs', - 'links', - 'images', - 'anchors', - 'abbrs', - 'strongs', - 'bolds', - 'emphasis', - 'italics', - 'dels', - 'underlines', - 'cites', - 'customs', - 'icodes', - 'bcodes', - 'quotes', - 'lists', - 'files', - 'raws', - 'codes', - ) - - # Set exist for wip and www files - for value in values: - try: - eval(str(value)) - except: - remove = True - corrupt = True - break - - # Remove DB if unused source article or corrupted DB - if remove and exists: - os.remove(config) - exists = False - logs.out("23", config, False) - - old_chk = old_wip = old_www = False - no_chk = no_wip = no_www = False - sync_srvs = False - - # Set Statuses for chk, wip, www - if exists: - # File exists on servers - if tyto.exists(post_wip): file_wip = True - if tyto.exists(post_www): file_www = True - - # Statuses not set in Db - if not hash_chk: no_chk = True - if not hash_wip: no_wip = True - if not hash_www: no_www = True - - # Source article has changed - if hash_post != hash_chk: old_chk = chk_updated = True - if hash_chk: chk_again = True - - # WIP article is old - if not old_chk: - if hash_wip and hash_chk != hash_wip: old_wip = wip_updated = True - if no_wip: wip_added = True - if hash_wip: wip_again = True - if not file_wip: - old_wip = wip_updated = True - wip_added = True - wip_again = True - - # WWW article is old - if not old_wip: - if hash_www and hash_www != hash_wip: old_www = www_updated = True - if hash_www: www_again = True - if no_www: www_added = True - if not file_www: - old_www = www_updated = True - www_added = True - www_again = True - - # Article is updated on both servers - if hash_chk == hash_wip == hash_www: sync_srvs = True - - -#=========================# -# Show title and uri file # -#-------------------------# -def show_title(): - try: - print(' ├ "%s" > %s'%(title, uri_file)) - except: - return diff --git a/src/var/lib/tyto/program/debug.py b/src/var/lib/tyto/program/debug.py new file mode 100644 index 0000000..0236cd5 --- /dev/null +++ b/src/var/lib/tyto/program/debug.py @@ -0,0 +1,118 @@ +#!/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: Add more logs when debug is set in command line +# File: /var/lib/tyto/program/debug.py +#---------------------------------------------------------------------- + +#------------------------- +# Funny Stats Project +#------------------------- +# file lines : +# file comments : +# file functions: +# file program : +#-------------------------- + +import sys +import langs, args + + +#===================================# +# Show logs if "show" is True # +# -D argument for specific ones # +# color is for "*" in message # +# - 3 colors levels: # +# - - 0 = Green # +# - - 1 = Yellow # +# - - 2 = Red # +# stop to sys exit with nbr if True # +#-----------------------------------# +def out(nbr, var, val, show, color, stop): + args.get_options() + if not show and not args.dlogs: return # Show Very less logs + if args.erron and color == 0: return # Show only warn and error logs + + # COlors + CS = '\033[0;0m' # Unset + CL = '\033[0;2m' # Gray + CB = '\033[1;34m' # Blue + CC = '\033[1;36m' # Cyan + CR = '\033[1;31m' # Red + CG = '\033[1;32m' # Green + CY = '\033[1;33m' # Yellow + CP = '\033[1;35m' # Pink + + # Color of "*" + SC = CL # Default gray + if color == 0: SC = CG + elif color == 1: SC = CY + elif color == 2: SC = CR + + # Messages for logs + 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, + 50 : langs.logs.err_date, + # 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, + # 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, + 255 : langs.logs.later, + } + + + # 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 + sys.exit(nbr) + diff --git a/src/var/lib/tyto/program/dom.py b/src/var/lib/tyto/program/dom.py deleted file mode 100644 index 224a6ea..0000000 --- a/src/var/lib/tyto/program/dom.py +++ /dev/null @@ -1,318 +0,0 @@ -#!/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 Affero General Public License -# as published by the Free Software Foundation, either version 3 of the -# License, or of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -#---------------------------------------------------------------------- -# XMPP: echolib (im@echolib.re) -# -# Description: Load domain database and check validity -# File: /var/lib/tyto/program/dom.py -#---------------------------------------------------------------------- - -#------------------------- -# Funny Stats Project -#------------------------- -# file lines : 318 -# file comments : 31 -# file functions: 1 -# file program : 277 -#-------------------------- - - -import os, sys, importlib, langs -import args - - -try: - ready - -except: - - lib = 'tyto_domain' - exists = incomplete = active = ready = shortname = corrupt = False - local_user = articles_db_d = False - hole = False - - # Set current directory - try: - user_dir - except: - try: - user_dir = os.getcwd() + "/" - except: - hole = True - - # Set current user name - try: - user - except: - try: - user = os.environ.get('USER') - except: - user = '' - - - # Settings for domain, check if db is not corrupted - dom_values = \ - ( - 'directory', - 'database', - 'local_user', - 'lang_sys', - 'lang_logs', - 'articles_db_d', - 'articles_d', - 'files_d', - 'images_d', - 'modules_d', - 'navbar_f', - 'sidebar_f', - 'metas_f', - 'footer_f', - 'shortname', - 'www_url', - 'wip_url', - 'srv_root', - 'srv_domain', - 'srv_wip', - 'srv_wip_tpl_d', - 'srv_wip_images_d', - 'srv_wip_files_d', - 'srv_www', - 'srv_www_tpl_d', - 'srv_www_images_d', - 'srv_www_files_d', - 'wip_favicon_f', - 'wip_css_f', - 'wip_logo_f', - 'wip_navbar_f', - 'wip_sidebar_f', - 'wip_metas_f', - 'wip_footer_f', - 'wip_stats_f', - 'www_navbar_f', - 'www_sidebar_f', - 'www_metas_f', - 'www_footer_f', - 'www_stats_f', - 'www_logo_f', - 'www_css_f', - 'www_rss_f', - 'www_favicon_f', - 'favicon', - 'logo', - 'styles', - 'rss', - 'rss_items', - 'title', - 'date', - 'about', - 'lang_site', - 'mail', - 'tags', - 'license', - 'license_url', - 'legal_url', - 'terms_url', - 'css', - 'sep', - 'article_code', - 'relme', - 'sidebar_title', - 'sidebar_items', - 'activated' - ) - - create_files = \ - ( - 'navbar_f', - 'sidebar_f', - 'metas_f', - 'footer_f', - ) - - wip_html_mods = () - err_val = (()) # Make a list from values error - - if not hole: - home_dir = os.path.expanduser('~') - - # Set configuration domain directory - root_dir = user_dir - if '/articles' in user_dir: - root_dir = user_dir.rsplit('/articles')[0] + "/" - - # Set configuration domain file - config = '%styto_domain.py'%root_dir - shortname = config - - # Set exists if configuration file - if os.path.exists(config): - exists = True - try: - exec(open(config).read()) - try: - os.path.exists(articles_d) - if '/articles' in user_dir: - user_uri_dir = user_dir.rsplit(articles_d)[1] - else: - user_uri_dir = '' - os.chdir(articles_d) - except: corrupt = True - except: - corrupt = True - - if not args.target in args.pass_targets: - if args.target.startswith("articles/"): - args.target = args.target.rsplit("articles/")[1] - args.target = user_uri_dir + args.target - - # For logs: show uri if not shortname known - try: shortname - except: pass - - try: active = activated - except: pass - - # Check set values configuration - if not corrupt: - for value in dom_values: - try: - eval(str(value)) - value_set = True - except: - err_val = err_val + ((value),) - value_set = False - incomplete = True - active = False - - - #==============================================# - # When an active and complete domain is needed # - #----------------------------------------------# - if exists and not incomplete and not corrupt: - if active: - ready = True - - wip_html_mods = \ - ( - eval(str('wip_navbar_f')), - eval(str('wip_sidebar_f')), - eval(str('wip_metas_f')), - eval(str('wip_footer_f')) - ) - www_html_mods = \ - ( - eval(str('www_navbar_f')), - eval(str('www_sidebar_f')), - eval(str('www_metas_f')), - eval(str('www_footer_f')) - ) - metas = \ - ( - eval(str('metas_f')), - eval(str('wip_metas_f')), - eval(str('www_metas_f')) - ) - navbars = \ - ( - eval(str('navbar_f')), - eval(str('wip_navbar_f')), - eval(str('www_navbar_f')) - ) - sidebars = \ - ( - eval(str('sidebar_f')), - eval(str('wip_sidebar_f')), - eval(str('www_sidebar_f')) - ) - footers = \ - ( - eval(str('footer_f')), - eval(str('wip_footer_f')), - eval(str('www_footer_f')), - ) - - templates = \ - ( - eval(str('wip_logo_f')), - eval(str('wip_favicon_f')), - eval(str('wip_css_f')), - eval(str('wip_navbar_f')), - eval(str('wip_sidebar_f')), - eval(str('wip_metas_f')), - eval(str('wip_footer_f')), - eval(str('wip_stats_f')), - eval(str('www_favicon_f')), - eval(str('www_logo_f')), - eval(str('www_css_f')), - eval(str('www_navbar_f')), - eval(str('www_sidebar_f')), - eval(str('www_metas_f')), - eval(str('www_footer_f')), - eval(str('www_stats_f')), - eval(str('www_rss_f')), - ) - - statistics = \ - ( - eval(str('wip_stats_f')), - eval(str('www_stats_f')), - ) - - modules = \ - { - "metas" : metas, - "navbar" : navbars, - "sidebar" : sidebars, - "footer" : footers, - "template": templates, - "stats" : statistics, - } - - templates_files_wip = \ - ( - eval(str('wip_favicon_f')), - eval(str('wip_logo_f')), - eval(str('wip_css_f')), - eval(str('wip_navbar_f')), - eval(str('wip_sidebar_f')), - eval(str('wip_metas_f')), - eval(str('wip_footer_f')), - eval(str('wip_stats_f')), - ) - - templates_files_www = \ - ( - eval(str('www_favicon_f')), - eval(str('www_logo_f')), - eval(str('www_css_f')), - eval(str('www_navbar_f')), - eval(str('www_sidebar_f')), - eval(str('www_metas_f')), - eval(str('www_footer_f')), - eval(str('www_stats_f')), - eval(str('www_rss_f')) - ) - -#====================================# -# Check if domain is ready and ready # -#------------------------------------# -def valid(): - if incomplete: sys.exit(41) - elif not active: sys.exit(42) - elif not ready: sys.exit(41) diff --git a/src/var/lib/tyto/program/domain.py b/src/var/lib/tyto/program/domain.py new file mode 100644 index 0000000..690a817 --- /dev/null +++ b/src/var/lib/tyto/program/domain.py @@ -0,0 +1,376 @@ +#!/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 configuration domain(s) +# 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 + + +#=========================================================# +# Exit if directory name is compatible with a domain name # +#---------------------------------------------------------# +def compatible_name(): + if len(conf_name.rsplit(".")) <= 1: + debug.out(3, "abc.tld", conf_name, True, 2, True) + + +#================================# +# Load Domain Configuration file # +# As needed, exit if not exists # +#--------------------------------# +def dcf_load(): + global dcf + + dcf = False + if not dcf_exists(): + debug.out(100, conf_name, dcf_uri, True, 1, True) + + dcf = configparser.ConfigParser() + dcf.read(dcf_uri) + + +#=====================================# +# Load User Domain Configuration file # +# As needed, exit if not exists # +#-------------------------------------# +def ult_dcf_load(): + global ult_dcf + + ult_dcf = False + if not os.path.exists(ult_dcf_uri): + debug.out(100, conf_name, ult_dcf_uri, True, 1, True) + + ult_dcf = configparser.ConfigParser() + ult_dcf.read(ult_dcf_uri) + + +#===================================# +# Load User local Domains List File # +#-----------------------------------# +def ult_dlf_load(): + global ult_dlf + + ult_dlf = False + ult_dlf = configparser.ConfigParser() + ult_dlf.read(ult_dlf_uri) + + +#===========================================# +# Check if Domain COnfiguration file exists # +# Show status message only once # +# return True or False +#-------------------------------------------# +def dcf_exists(): + global shown_ok, shown_no + + if os.path.exists(dcf_uri): + try: shown_ok + except: debug.out(202, conf_name, dcf_uri, True, 0, False) + shown_ok = True + return True + else: + try: shown_no + except: debug.out(100, "False", dcf_uri, True, 1, False) + shown_no = True + return False + + +#=============================================# +# Ensure domain is valid and ready to be used # +#---------------------------------------------# +def valid_conf(): + dcf_load() + try: + dcf_name = dcf.get("DOMAIN", "name") + except: + debug.out(100, conf_name, dcf_uri, True, 1, True) + + # Check some values in ult_dcf + ult_dcf_load() + try: + ult_dcf_name = ult_dcf.get("DOMAIN", "name") + ult_dcf_hash = ult_dcf.get("DOMAIN", "hash") + ult_dcf_conf = ult_dcf.get("DOMAIN", "conf") + ult_dcf_root = ult_dcf.get("DOMAIN", "root") + except: + debug.out(100, conf_name, ult_dcf_uri, True, 1, True) + + # Compare values (exit if mismatch) + if ult_dcf_name != conf_name or \ + ult_dcf_conf != dcf_uri or \ + dcf_name != ult_dcf_name: + debug.out(100, conf_name, "?", True, 1, True) + + # Check if dcf need to be updated + now_dcf_hash = tools.get_filesum(dcf_uri, True) + if now_dcf_hash != ult_dcf_hash: + dcf_update_values("") + + +#=========================================# +# Guess and return wip_url from conf_name # +#-----------------------------------------# +def create_wip_url(): + wip_url = "https://www-wip.%s/" + len_cn = conf_name.count(".") + + # Domain name Format: a.b + if len_cn == 1: + return wip_url%conf_name + + # Domain name format: (at least) a.b.c + len_cn = len(conf_name.rsplit(".")[0]) + 1 + tld = conf_name[len_cn:] + 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 dcf_create(): + compatible_name() + + # This fonction is only called with "new domain" argument + # If a conf already exists, show important RESET log + if dcf_exists(): + debug.out(102, "!?", dcf_uri, True, 1, False) + + # Ask User to create new domain. Will exit if not ok. + forms.ask_domain_shortname(conf_name) + + # Create default files + tools.create_file(dcf_uri, tyto.ini_domain) + tools.create_dirs(ult_dir) + tools.create_file(ult_dcf_uri, tyto.ini_domain_user) + + # User Domains list file + if not os.path.exists(ult_dlf_uri): + tools.create_file(ult_dlf_uri, tyto.ini_domains_list) + + # Ask user for domain settings + forms.ask_domain_title() + forms.ask_domain_date() + forms.ask_domain_about() + forms.ask_domain_mail() + forms.ask_domain_tags() + + # Set default lang, from config file or system lang + forms.ask_domain_lang() + + # Set server directory + forms.ask_domain_server() + + +#===========================================# +# Set or Update domain configuration values # +#-------------------------------------------# +def dcf_update_values(srv): + # Prepare Domain Configuration File keys values + #----------------------------------------------- + dcf_load() + + # Test server directory, and exit if not exists + if not srv: srv = dcf.get("SERVER", "root") # Set from db if unknown + if srv: tools.dir_exists(srv, True) + + # Test registred website lang + # change to default lang sys, or "en" if no translation file + langs.load_website_lang() + + srv_dom = os.path.join(srv, conf_name + "/") + srv_wip = os.path.join(srv_dom, "wip/") + srv_www = os.path.join(srv_dom, "www/") + + favicon = dcf.get("TEMPLATE_FILENAMES", "favicon") + logo = dcf.get("TEMPLATE_FILENAMES", "logo") + styles = dcf.get("TEMPLATE_FILENAMES", "styles") + rss = dcf.get("TEMPLATE_FILENAMES", "rss") + stats = dcf.get("TEMPLATE_FILENAMES", "stats") + + www_url = dcf.get("WEBSITE", "www_url") + wip_url = dcf.get("WEBSITE", "wip_url") + + sdb_title = dcf.get("WEBSITE_MODULES", "sidebar_title") + + usr_mods = os.path.join(dcf_dir + "modules/") + usr_tpl = os.path.join(dcf_dir, "template/") + usr_favicon = os.path.join(usr_tpl, favicon) + usr_logo = os.path.join(usr_tpl, logo) + usr_styles = os.path.join(usr_tpl, styles) + + wip_tpl = srv_wip + "template/" + 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) + + www_tpl = srv_www + "template/" + 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) + + + # Update Domain Configuration File + #--------------------------------- + dcf.set("DOMAIN", "name", conf_name) + dcf.set("TYTO", "domain_hash", tools.get_filesum(dcf_uri, False)) + dcf.set("TYTO", "domain_conf", dcf_uri) + dcf.set("TYTO", "domain_user", ult_dcf_uri) + + # USER + dcf.set("USER_DIRS", "root", dcf_dir) + dcf.set("USER_DIRS", "articles", dcf_dir + "articles/") + dcf.set("USER_DIRS", "images", dcf_dir + "images/") + dcf.set("USER_DIRS", "files", dcf_dir + "files/") + dcf.set("USER_DIRS", "modules", usr_mods) + dcf.set("USER_DIRS", "database", dcf_dir + ".db/") + dcf.set("USER_DIRS", "template", usr_tpl) + dcf.set("USER_MODULES_FILES", "metas", usr_mods + "tyto_metas.raw") + dcf.set("USER_MODULES_FILES", "header", usr_mods + "tyto_header.raw") + dcf.set("USER_MODULES_FILES", "navbar", usr_mods + "tyto_navbar.raw") + dcf.set("USER_MODULES_FILES", "sidebar", usr_mods + "tyto_sidebar.raw") + dcf.set("USER_MODULES_FILES", "footer", usr_mods + "tyto_footer.raw") + dcf.set("USER_TEMPLATE_FILES", "favicon", usr_favicon) + dcf.set("USER_TEMPLATE_FILES", "logo", usr_logo) + dcf.set("USER_TEMPLATE_FILES", "styles", usr_styles) + + # WEBSITE + dcf.set("WEBSITE", "lang", langs.site_lang) + www_url or dcf.set("WEBSITE", "www_url", "https://%s/"%conf_name) + wip_url or dcf.set("WEBSITE", "wip_url", create_wip_url()) + + sdb_title or dcf.set("WEBSITE_MODULES", "sidebar_title", langs.site.sidebar_title) + + # SERVER + dcf.set("SERVER", "root", srv) + dcf.set("SERVER", "domain", srv_dom) + + # WIP + dcf.set("WIP_DIRS", "root", srv_wip) + dcf.set("WIP_DIRS", "images", srv_wip + "images/") + dcf.set("WIP_DIRS", "files", srv_wip + "files/") + dcf.set("WIP_DIRS", "template", wip_tpl) + dcf.set("WIP_FILES", "favicon", wip_favicon) + dcf.set("WIP_FILES", "logo", wip_logo) + dcf.set("WIP_FILES", "styles", wip_styles) + dcf.set("WIP_FILES", "rss", wip_rss) + dcf.set("WIP_FILES", "stats", wip_stats) + dcf.set("WIP_FILES", "metas", wip_tpl + "metas.html") + dcf.set("WIP_FILES", "header", wip_tpl + "header.html") + dcf.set("WIP_FILES", "navbar", wip_tpl + "navbar.html") + dcf.set("WIP_FILES", "sidebar", wip_tpl + "sidebar.html") + dcf.set("WIP_FILES", "footer", wip_tpl + "footer.html") + + + # WWW + dcf.set("WWW_DIRS", "root", srv_www) + dcf.set("WWW_DIRS", "images", srv_www + "images/") + dcf.set("WWW_DIRS", "files", srv_www + "files/") + dcf.set("WWW_DIRS", "template", www_tpl) + dcf.set("WWW_FILES", "favicon", www_favicon) + dcf.set("WWW_FILES", "logo", www_logo) + dcf.set("WWW_FILES", "styles", www_styles) + dcf.set("WWW_FILES", "rss", www_rss) + dcf.set("WWW_FILES", "stats", www_stats) + dcf.set("WWW_FILES", "metas", www_tpl + "metas.html") + dcf.set("WWW_FILES", "header", www_tpl + "header.html") + dcf.set("WWW_FILES", "navbar", www_tpl + "navbar.html") + dcf.set("WWW_FILES", "sidebar", www_tpl + "sidebar.html") + dcf.set("WWW_FILES", "footer", www_tpl + "footer.html") + + with open(dcf_uri, "w") as f: + dcf.write(f) + + # Update User local domain configuration file + #-------------------------------------------- + ult_dcf_load() + ult_dcf.set("DOMAIN", "name", conf_name) + ult_dcf.set("DOMAIN", "hash", tools.get_filesum(dcf_uri, True)) + ult_dcf.set("DOMAIN", "root", dcf_dir) + ult_dcf.set("DOMAIN", "conf", dcf_uri) + ult_dcf.set("SERVER", "root", srv) + + with open(ult_dcf_uri, "w") as f: + ult_dcf.write(f) + + # Update User local Domains List File + #------------------------------------ + ult_dlf_load() + ult_dlf.set("DOMAINS", conf_name, dcf_dir) + + with open(ult_dlf_uri, "w") as f: + ult_dlf.write(f) + + debug.out(204, "True", dcf_uri, True, 0, False) + + +#======#======================================================================= +# 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) + + +#==========================================# +# utl: $USER/.local/Tyto # +# dcf: Domain Configuration File # +#------------------------------------------# +# Domain Configuration directory +dcf_dir = user_dir.rsplit("articles/")[0] + +# Domain name from current basename directory +# Exit if not format at least "abc.tld" +conf_name = os.path.basename(os.path.dirname(dcf_dir)) + +dcf_name = "tyto_domain.ini" +dcf_uri = os.path.join(dcf_dir, dcf_name) +dcf_id = tools.get_filesum(dcf_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_dcf_uri = os.path.join(ult_dir, dcf_id + ".ini") diff --git a/src/var/lib/tyto/program/form.py b/src/var/lib/tyto/program/form.py deleted file mode 100644 index f72f529..0000000 --- a/src/var/lib/tyto/program/form.py +++ /dev/null @@ -1,1092 +0,0 @@ -#!/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 Affero General Public License -# as published by the Free Software Foundation, either version 3 of the -# License, or of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -#---------------------------------------------------------------------- -# XMPP: echolib (im@echolib.re) -# -# Description: Manage 'domain' argument. -# Create domain config from form -# Create config files for user to custom -# File: /var/lib/tyto/program/form.py -#---------------------------------------------------------------------- - -#------------------------- -# Funny Stats Project -#------------------------- -# file lines : 1092 -# file comments : 104 -# file functions: 7 -# file program : 872 -#-------------------------- - - -from datetime import datetime -import os, sys, shutil, re, locale, importlib -import logs, dom, tyto, html, show, langs - -try: - lang_site -except: - # locale translation directory - trans_dir = '/var/lib/tyto/translations' - - # Get default System language - try: - lang_sys = locale.getdefaultlocale()[0].split('_')[0] - os.path.exists('%s/site_%s.py'%(trans_dir, lang_sys)) - except: - lang_sys = 'en' - - lang_site = lang_sys - -# Generic answer -try: answer_yes -except: answer_yes = langs.answer_yes - - -#=======================================# -# Function called when asking something # -# Catch interruption # -# if logs.out True: sys exit # -# yes_no False: return answer # -# True: exit if not in yes # -#---------------------------------------# -def asking(question, yes_no): - try: - answer = input(question) - except KeyboardInterrupt: - print('') - logs.out("255", '', True) - - if yes_no: - go = False - for yes_names in answer_yes: - if answer.lower() in yes_names: - go = True - if not go: - logs.out("255", '', True) - - else: - return(answer) - - -#==========================# -# Manage Argument 'domain' # -# target: 3rd argument # -#--------------------------# -def manage(target): - if not dom.exists: - logs.out("43", '', False) - create_domain(target) - elif dom.incomplete: - create_domain(target) - else: - asking(' ├ %s%s '%(langs.site.form_edit, langs.site.q), True) - create_domain(target) - - -#=====================# -# Create a new domain # -#---------------------# -def create_domain(target): - valid_url = ('http://', 'https://') - invalid = False - - if target and not target.startswith(valid_url): - logs.out("51", '"%s" -> http(s)://...'%target, False) - target = '' - - print(langs.site.form_start) - - # Get complete URL from target or ask - #------------------------------------ - try: - www_url = dom.www_url - except: - if target: www_url = target - else: www_url = '' - - answer = asking(' ├ [http(s)://...] %s%s {%s} '%( - langs.site.form_url, langs.site.q, www_url - ), False) - - if answer: - if answer.startswith(valid_url): www_url = answer - else: logs.out("2", '"http(s)://%s"%s'%(answer, langs.site.q), True) - elif not www_url: - logs.out("255", '', True) - - if www_url[-1] == "/": www_url = www_url[:-1] - - protocol = www_url.rsplit('://')[0] - shortname = www_url.rsplit('://')[1] - - - # Prefix wip ; guess it if unknown - #--------------------------------- - try: - wip_url = dom.wip_url - except: - # Set domain with www-wip - try: - wip_url = shortname.rsplit('.', 2) - if len(wip_url) > 2: - wip_url = '%s://www-wip.%s.%s'%( - protocol, wip_url[1], wip_url[2] - ) - else: - wip_url = '%s://www-wip.%s.%s'%( - protocol, wip_url[0], wip_url[1] - ) - except: - wip_url = '' - - answer = asking(' ├ [http(s)://...] %s%s {%s} '%( - langs.site.form_wip, langs.site.q, wip_url - ), False) - if answer: - if answer.startswith(valid_url): wip_url = answer - else: logs.out("2", '"http(s)://www-wip.%s"%s'%( - answer, langs.site.q - ), True) - elif not wip_url: - logs.out("255", '', True) - - if wip_url[-1] == "/": wip_url = wip_url[:-1] - - - # Translations for logs - #---------------------- - try: lang_logs = dom.lang_logs - except: lang_logs = lang_sys - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_trlog, langs.site.q, lang_logs - ), False) - - if answer: - if len(answer) == 2: lang_logs = answer.lower() - else: logs.out("3", answer, False) - - if not tyto.exists('%s/logs_%s.py'%(trans_dir, lang_logs)): - lang_logs = 'en' - - - # Start registering variables in domain database - #----------------------------------------------- - local_user = '%s/.local/tyto/%s/'%(dom.home_dir, shortname) - modules_dir = '%sarticles/_configs/'%dom.root_dir - footer_about_f = '%sfooter_about.html'%modules_dir - config_bkp = '%sdomain_config.bkp'%local_user - - set_f = \ - '# Home Domain\n' + \ - 'directory = "%s"\n'%dom.root_dir + \ - 'database = "%s"\n'%dom.config + \ - '\n# Local user configuration\n' + \ - 'lang_sys = "%s"\n'%lang_sys + \ - 'local_user = "%s"\n'%local_user + \ - 'lang_logs = "%s"\n'%lang_logs + \ - 'articles_db_d = "%sarticles/"\n'%local_user + \ - '\n# Working directories\n' + \ - 'articles_d = "%sarticles/"\n'%dom.root_dir + \ - 'files_d = "%sarticles/files/"\n'%dom.root_dir + \ - 'images_d = "%sarticles/images/"\n'%dom.root_dir + \ - 'modules_d = "%s"\n'%modules_dir + \ - '\n# Modules files\n' + \ - 'navbar_f = "%styto.navbar"\n'%modules_dir + \ - 'sidebar_f = "%styto.sidebar"\n'%modules_dir + \ - 'metas_f = "%styto.metas.html"\n'%modules_dir + \ - 'footer_f = "%styto.footer.html"\n'%modules_dir + \ - '\n# Domain\n' + \ - 'shortname = "%s"\n'%shortname + \ - 'www_url = "%s"\n'%www_url + \ - 'wip_url = "%s"\n'%wip_url - - tyto.set_file(dom.config, True, set_f) - - - # Get srv root - #------------- - try: srv = dom.srv - except: srv = '/var/www' - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_srv, langs.site.q, srv - ), False) - - if answer: srv = answer - if not tyto.exists(srv): - logs.out("1", srv, False) - srv = '' - invalid = True - elif srv[-1] == "/": - srv = srv[:-1] - - - # Get logo's website - #------------------- - try: logo = dom.logo - except: logo = 'logo.png' - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_logo, langs.site.q, logo - ), False) - - if answer: logo = answer - - # Get css file name - #------------------ - try: css_file = dom.css_file - except: css_file = "styles.css" - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_css_f, langs.site.q, css_file - ), False) - - if answer: css_file = answer - - # Get favicon file name - #---------------------- - try: favicon_file = dom.favicon_file - except: favicon_file = "favicon.png" - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_fav_f, langs.site.q, favicon_file - ), False) - - if answer: favicon_file = answer - - - # Set config's directories for servers - #------------------------------------- - root_srv_dom = '%s/%s'%(srv, shortname) - srv_wip_tpl = "%s/wip/template/"%root_srv_dom - stats_wip_f = "%s/wip/tyto_wip_statoolinfos.properties"%root_srv_dom - stats_www_f = "%s/www/tyto_www_statoolinfos.properties"%root_srv_dom - - srv_www_tpl = "%s/www/template/"%root_srv_dom - set_f = \ - '\n# Servers directories\n' + \ - 'srv_root = "%s/"\n'%srv + \ - 'srv_domain = "%s/"\n'%root_srv_dom + \ - 'srv_wip = "%s/wip/"\n'%root_srv_dom + \ - 'srv_wip_tpl_d = "%s"\n'%srv_wip_tpl + \ - 'srv_wip_images_d = "%s/wip/images/"\n'%root_srv_dom + \ - 'srv_wip_files_d = "%s/wip/files/"\n'%root_srv_dom + \ - 'srv_www = "%s/www/"\n'%root_srv_dom + \ - 'srv_www_tpl_d = "%s"\n'%srv_www_tpl + \ - 'srv_www_images_d = "%s/www/images/"\n'%root_srv_dom + \ - 'srv_www_files_d = "%s/www/files/"\n'%root_srv_dom + \ - '\n' + \ - '# Servers files (wip)\n' + \ - 'wip_favicon_f = "%s%s"\n'%(srv_wip_tpl, favicon_file) + \ - 'wip_logo_f = "%s%s"\n'%(srv_wip_tpl, logo) + \ - 'wip_css_f = "%s%s"\n'%(srv_wip_tpl, css_file) + \ - 'wip_navbar_f = "%snavbar.html"\n'%srv_wip_tpl + \ - 'wip_sidebar_f = "%ssidebar.html"\n'%srv_wip_tpl + \ - 'wip_metas_f = "%smetas.html"\n'%srv_wip_tpl + \ - 'wip_footer_f = "%sfooter.html"\n'%srv_wip_tpl + \ - 'wip_stats_f = "%s"\n'%stats_wip_f + \ - '\n' + \ - '# Servers files (www)\n' + \ - 'www_favicon_f = "%s%s"\n'%(srv_www_tpl, favicon_file) + \ - 'www_logo_f = "%s%s"\n'%(srv_www_tpl, logo) + \ - 'www_css_f = "%s%s"\n'%(srv_www_tpl, css_file) + \ - 'www_navbar_f = "%snavbar.html"\n'%srv_www_tpl + \ - 'www_sidebar_f = "%ssidebar.html"\n'%srv_www_tpl + \ - 'www_metas_f = "%smetas.html"\n'%srv_www_tpl + \ - 'www_footer_f = "%sfooter.html"\n'%srv_www_tpl + \ - 'www_stats_f = "%s"\n'%stats_www_f - - tyto.set_file(dom.config, False, set_f) - - - # RSS/Atom filename - #------------------ - try: rss = dom.rss - except: rss = 'rss.xml' - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_rss_f, langs.site.q, rss - ), False) - - if answer: www_rss = answer - - set_f = \ - 'www_rss_f = "%s/www/%s"\n'%(root_srv_dom, rss) + \ - '\n# Domain user\'s settings\n' + \ - 'favicon = "%s"\n'%favicon_file + \ - 'logo = "%s"\n'%logo + \ - 'styles = "%s"\n'%css_file + \ - 'rss = "%s"\n'%rss - - tyto.set_file(dom.config, False, set_f) - - - # RSS/Atom max items - #------------------- - try: rss_items = dom.rss_items - except: rss_items = 100 - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_rss_i, langs.site.q, rss_items - ), False) - - if answer: rss_items = answer - if not str(rss_items).isdigit() or not int(rss_items) > 1: - rss_items = 100 - - set_f = 'rss_items = %d\n'%int(rss_items) - tyto.set_file(dom.config, False, set_f) - - - # Get title domain - #----------------- - try: title = dom.title - except: title = '' - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_title, langs.site.q, title - ), False) - - if answer: title = answer - if not title: invalid = True - else: title = tyto.convert_altname(title) - - set_f = 'title = "%s"\n'%title - tyto.set_file(dom.config, False, set_f) - - - # Get creation date - #------------------ - try: date - except: date = datetime.now().year - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_date, langs.site.q, date - ), False) - - if answer: date = answer - - set_f = 'date = "%s"\n'%date - tyto.set_file(dom.config, False, set_f) - - - # Get Description domain - #----------------------- - try: about = dom.about - except: about = '' - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_about, langs.site.q, about - ), False) - - if answer: about = answer - if not about: invalid = True - else: about = tyto.convert_altname(about) - - set_f = 'about = "%s"\n'%about - tyto.set_file(dom.config, False, set_f) - - - # Get Lang domain for web pages - #------------------------------ - try: lang_site - except: lang_site = lang_sys - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_trsite, langs.site.q, lang_site - ), False) - - if answer: - if len(answer) == 2: lang_site = answer.lower() - else: logs.out("3", answer, False) - - if not tyto.exists('%s/site_%s.py'%(trans_dir, lang_site)): - lang_site = 'en' - - set_f = 'lang_site = "%s"\n'%lang_site - tyto.set_file(dom.config, False, set_f) - - - # Get mail domain - #---------------- - try: mail = dom.mail - except: mail = '' - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_mail, langs.site.q, mail - ), False) - - if answer: mail = answer - passplus = mail.replace('+', '').replace('-', '') - if not re.search('^\w+@\w+.\w+$', passplus): - logs.out("3", mail, False) - invalid = True - - set_f = 'mail = "%s"\n'%mail - tyto.set_file(dom.config, False, set_f) - - - # Get Tags domain - #---------------- - try: tags = dom.tags - except: tags = '' - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_tags, langs.site.q, tags - ), False) - - if answer: tags = answer - if not tags: invalid = True - elif '"' in tags: tags = tags.replace('"', '') - - set_f = 'tags = "%s"\n'%tags - tyto.set_file(dom.config, False, set_f) - - - # Get License domain - #------------------- - try: domlicense = dom.license - except: domlicense = 'gfdl-1.3' - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_lic, langs.site.q, domlicense - ), False) - - if answer: domlicense = answer - if '"' in domlicense: domlicense = domlicense.replace('"', '') - - set_f = 'license = "%s"\n'%domlicense - tyto.set_file(dom.config, False, set_f) - - - # Get License URL (optional) - #--------------------------- - try: licurl = dom.license_url - except: - if domlicense == "gfdl-1.3": - licurl = "https://www.gnu.org/licenses/fdl-1.3.txt" - - answer = asking(' ├ %s [http(s)://...] %s%s {%s} '%( - langs.site.form_opt, langs.site.form_licurl, - langs.site.q, licurl - ), False) - - if answer: licurl = answer - if not licurl.startswith(valid_url): - if answer: - logs.out("2", '"http(s)://%s"%s'%(licurl, langs.site.q), False) - licurl = '' - - set_f = 'license_url = "%s"\n'%licurl - tyto.set_file(dom.config, False, set_f) - - - # Legal Notice URL - #----------------- - try: legalurl = dom.legal_url - except: legalurl = '' - - answer = asking(' ├ %s [http(s)://...] %s%s {%s} '%( - langs.site.form_opt, langs.site.form_legal, - langs.site.q, legalurl - ), False) - - if answer: legalurl = answer - if not legalurl.startswith(valid_url): - if answer: - logs.out("2", '"http(s)://%s"%s'%(legalurl, langs.site.q), False) - legalurl = '' - - set_f = 'legal_url = "%s"\n'%legalurl - tyto.set_file(dom.config, False, set_f) - - - # Terms URL - #----------------- - try: termsurl = dom.terms_url - except: termsurl = '' - - answer = asking(' ├ %s [http(s)://...] %s%s {%s} '%( - langs.site.form_opt, langs.site.form_terms, - langs.site.q, termsurl - ), False) - - if answer: termsurl = answer - if not termsurl.startswith(valid_url): - if answer: - logs.out("2", '"http(s)://%s"%s'%(termsurl, langs.site.q), False) - termsurl = '' - - set_f = 'terms_url = "%s"\n'%termsurl - tyto.set_file(dom.config, False, set_f) - - - # CSS Prefix - #----------- - try: css = dom_css - except: css = 'tyto' - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_css, langs.site.q, css - ), False) - - if answer: css = answer.lower() - if not css.isalnum(): - logs.out("3", css, False) - css = 'tyto' - - set_f = 'css = "%s"\n'%css - tyto.set_file(dom.config, False, set_f) - - - # Titles webpage separator - #------------------------- - try: sep = dom.sep - except: sep = "-" - - answer = asking(' ├ %s%s {%s} '%( - langs.site.form_sep, langs.site.q, sep - ), False) - - if answer: sep = answer - if not len(sep) == 1: - logs.out("3", answer, False) - sep = "-" - - set_f = 'sep = "%s"\n'%sep - tyto.set_file(dom.config, False, set_f) - - - # Show article source ? - #---------------------- - try: - if dom.article_code: article_code = "True" - else: article_code = "False" - except: - article_code = "False" - - answer = asking(' ├ %s%s {%s} (Y|n) '%( - langs.site.form_pscode, langs.site.q, str(article_code) - ), False) - - if answer: - if answer in answer_yes: article_code = "True" - else: article_code = "False" - - set_f = 'article_code = %s\n'%article_code - tyto.set_file(dom.config, False, set_f) - - - # Profile for rel="me" (optionnal) - #--------------------------------- - try: relme = dom.relme - except: relme = '' - - answer = asking(' ├ %s [http(s)://...] %s%s {%s} '%( - langs.site.form_opt, langs.site.form_relme, - langs.site.q, relme - ), False) - - if answer: relme = answer - if not relme.startswith(valid_url): - if answer: - logs.out("2", '"http(s)://%s"%s'%(relme, langs.site.q), False) - relmel = '' - - set_f = 'relme = "%s"\n'%relme - tyto.set_file(dom.config, False, set_f) - - - # Sidebar Title - #-------------- - try: sdb_title = dom.sidebar_title - except: sdb_title = langs.site.site_sdb_t - - answer = asking(' ├ %s. %s%s {%s} '%( - langs.site.sidebar, langs.site.title, - langs.site.q, sdb_title - ), False) - - if answer: sdb_title = answer - if not sdb_title: - sdb_title = '' - invalid = True - else: - sdb_title = tyto.convert_altname(sdb_title) - - set_f = 'sidebar_title = "%s"\n'%sdb_title - tyto.set_file(dom.config, False, set_f) - - - # Sidebar Items - #-------------- - try: sdb_items = dom.sidebar_items - except: sdb_items = 6 - - answer = asking(' ├ [max=16] %s. %s%s {%s} '%( - langs.site.sidebar, langs.site.form_sdb_i, - langs.site.q, sdb_items - ), False) - - if answer: sdb_items = answer - if not str(sdb_items).isdigit() or not int(sdb_items) in range(1,17): - sdb_items = 6 - - set_f = 'sidebar_items = %d\n'%int(sdb_items) - tyto.set_file(dom.config, False, set_f) - - - # Domain config invalid, do not activate - if invalid: - tyto.set_file(dom.config, False, '\nactivated = False') - print(langs.site.form_inv) - logs.out("2", dom.config, True) - - # Resumed configuration - #----------------------- - try: active = dom.activated - except: active = False - - print(langs.site.form_warn) - show.read_lines(dom.config, False) - - - # Activate and prepare domain ? - #------------------------------ - answer = asking(' ├ %s%s '%( - langs.site.form_activ, langs.site.q - ), False) - - if not answer in answer_yes: - tyto.set_file(dom.config, False, '\nactivated = False') - logs.out("255", '', True) - - - # Activate Domain - #---------------- - tyto.set_file(dom.config, False, '\nactivated = True') - - # ReLoad config - #-------------- - importlib.reload(dom) - - # Backup and create local user dir - if not os.makedirs(dom.articles_db_d, exist_ok=True): - logs.out("33", dom.articles_db_d, False) - shutil.copy2(dom.config, config_bkp) - logs.out("32", config_bkp, False) - - - # Create folders from configuration file - #--------------------------------------- - folders = \ - ( - dom.srv_wip_tpl_d, dom.srv_wip_images_d, dom.srv_wip_files_d, - dom.srv_www_tpl_d, dom.srv_www_images_d, dom.srv_www_files_d, - dom.files_d, dom.images_d, dom.modules_d, - dom.articles_db_d, - ) - - print(' │') - for folder in folders: - if tyto.exists(folder): - logs.out("37", folder, False) - else: - os.makedirs(folder, exist_ok=True) - logs.out("33", folder, False) - - print(' │') - - - # Create in _configs/ modules files - #---------------------------------- - - html.create_user_metas('new') - html.create_navbar('new') - html.create_sidebar('new') - html.create_user_footer('new') - - print(langs.site.form_ready) - - -#=============================================================# -# # -# CREATE MODULES' USER FILE AND CREATE WIP FILES FROM MODULES # -# # -#=============================================================# -#========================# -# metas_load source file # -#------------------------# -def create_metas(option): - if not dom.ready: dom.valid() - - print(' │\n ├ %s'%langs.site.metas_inf) - if option != "new": return - - # Create new default config file, or ask if exists - if tyto.exists(dom.metas_f): - answer = asking(' ├ %s%s '%( - langs.site.form_reset, langs.site.q - ), False) - - if not answer in answer_yes: - if option == "new": return - logs.out("255", '', True) - - # Set default content for - # metas config file - # if no translation file - #----------------------- - metas_en = \ - '# For %s\n' + \ - '# Type text/HTML file\n' + \ - '# Description Configuration file for HTML tags\n' + \ - '# Content inserted in section\n' + \ - '# File %s\n' + \ - '# How Insert and \n' + \ - '# Notes - Ony these tags are added :\n' + \ - '# - \n' + \ - '~ - \n' + \ - '# - Do NOT copy this file to template directory\n' + \ - '# - These tags are already set' - - try: metas_lang = langs.site.metas_doc - except: metas_lang = metas_en - - metas_tags = \ - '%s'%metas_lang%(tyto.Tyto, dom.metas_f) + \ - '\n' + \ - '# \n' + \ - '\n' + \ - '\n' + \ - '' - - tyto.set_file(dom.metas_f, 'New', metas_tags) - - -#=============================# -# navbar load file translated # -#-----------------------------# -def create_navbar(option): - if not dom.ready: dom.valid() - - print(' │\n ├ %s'%langs.site.navbar_inf) - if option != "new": return - - # Create new config file, or ask if exists - if tyto.exists(dom.navbar_f): - answer = asking(' ├ %s%s '%( - langs.site.form_reset, langs.site.q - ), False) - - if not answer in answer_yes: - if option == "new": return - logs.out("255", '', True) - - - # Set default content for - # navbar config file - # if no translation file - #----------------------- - navbar_en = \ - '# For %s\n' + \ - '# Type: Text file\n' + \ - '# Description Configuration file for navbar"\n' + \ - '# (directories\'s list)\n' + \ - '# Commands tyto new navbar (reset)\n' + \ - '# tyto wip/publish navbar (Create)\n' + \ - '# tyto show navbar (show config)\n' + \ - '# tyto show-wip/show-www navbar (Show HTML)\n' + \ - '# tyto edit navbar (edit this file)\n' + \ - '# File %s\n' + \ - '# Comment 1 folder name per line *1\n' + \ - '# (from articles/)\n' + \ - '# not begining with "/"\n' + \ - '# Order in sidebar position\n' + \ - '# Remember To avoid 404 error, you must:\n' + \ - '# - add article index.{tyto}\n' + \ - '# in set folder\n' + \ - '# - check and wip article\n' + \ - '# *1 Option To define a title link:' + \ - '# - add "# title link"\n' + \ - '\n# %s\n'%(20 * "-") +\ - '# Examples :\n' + \ - '# documentation\n' + \ - '# about # infos about this website\n' + \ - '# %s\n\n'%(20 * "-") - - try: navbar_lang = langs.site.navbar_doc - except: navbar_lang = navbar_en - - navbar_lang = navbar_lang%(tyto.Tyto, dom.navbar_f) - - tyto.set_file(dom.navbar_f, 'New', navbar_lang) - - -#==============================# -# sidebar load file translated # -#------------------------------# -def create_sidebar(option): - if not dom.ready: dom.valid() - - print(' │\n ├ %s'%langs.site.sidebar_inf) - if option != "new": return - - # Create an empty html file in wip/www server if not exists - if not tyto.exists(dom.wip_sidebar_f): - tyto.set_file(dom.wip_sidebar_f, 'new', '') - - # Create new config file, or ask if exists with option = 'reset' - if tyto.exists(dom.sidebar_f): - answer = asking(' ├ %s%s '%( - langs.site.form_reset, langs.site.q - ), False) - - if not answer in answer_yes: - if option == "new": return - logs.out("255", '', True) - - - # Set default content for - # navbar config file - # if no translation file - #----------------------- - sidebar_en = \ - '# For %s\n' + \ - '# Type Text file\n' + \ - '# Description Configuration file for sidebar\n' + \ - '# (articles\'s list)\n' + \ - '# File %s\n' + \ - '# Commands tyto new sidebar (reset)\n' + \ - '# tyto wip/publish sidebar (Create)\n' + \ - '# tyto show sidebar (Show config)\n' + \ - '# tyto show-wip/show-www sidebar (Show HTML)\n' + \ - '# tyto edit sidebar (edit this file)\n' + \ - '# How 1 article URI per line\n' + \ - '# (from articles/)\n' + \ - '# not begining with "/"\n' + \ - '# Order in sidebar position\n' + \ - '# Max articles = %d\n' + \ - '# Option Tp add sidebar title:\n' + \ - '# ": Sidebar Title"\n' + \ - '\n# %s\n'%(20 * "-") + \ - '# Examples :\n' + \ - '# : My new articles list' - '# index.tyto\n' + \ - '# dir1/index.tyto\n' + \ - '# %s\n\n'%(20 * "-") - - try: sidebar_lang = langs.site.sidebar_doc - except: sidebar_lang = sidebar_en - - sidebar_lang = sidebar_lang%(tyto.Tyto, - dom.sidebar_f, - dom.sidebar_items - ) - - tyto.set_file(dom.sidebar_f, 'New', sidebar_lang) - - -#=============================# -# footer load file translated # -#-----------------------------# -def create_footer(option): - if not dom.ready: dom.valid() - - print(' │\n ├ %s'%langs.site.footer_inf) - if option != "new": return - - # Default footer contents - #------------------------ - Tytosrc = \ - '\n%s(%s)'%(9 * ' ', langs.site.source_code) - - tyto_show = \ - '%s%s %s'%(9 * ' ', tyto.Tyto, Tytosrc) - - # Show copyright date from creation to now year - if int(dom.date) == int(datetime.now().year): - footer_date = dom.date - else: - footer_date = '%s - %s'%(dom.date, datetime.now().year) - - # Simple link to home - domain_home = \ - '\n%s%s'%(9 * ' ', dom.title) - - # Insert content of fabout domain - footer_about = "

%s

"%dom.about - - # License URL. Set to homepage if unknown - if not dom.license_url: dom.license_url = '/' - - # Links for laws (Terms and Legals) - if dom.legal_url: - legal_link = \ - '%s'%(11 * ' ', langs.site.legal_t) - - if dom.terms_url: - terms_link = \ - '%s'%(11 * ' ', langs.site.terms_s) - - # create laws links from terms and legal if exists - footer_laws = '' - if dom.terms_url and dom.legal_url: - footer_laws = '%s - \n%s%s'%(legal_link, 8 * ' ', terms_link) - elif dom.terms_url: - footer_laws = terms_link - elif dom.legal_url: - footer_laws = legal_link - - footer_laws_links = '' - if footer_laws: - footer_laws_links = \ - ' \n' - - # Set default content for - # navbar config file - # if no translation file - #----------------------- - footer_en = \ - '# For %s\n' + \ - '# Type text/HTML file\n' + \ - '# Description Configuration file for footer\n' + \ - '# File %s\n' + \ - '# Commands tyto new footer (reset)\n' + \ - '# tyto wip/publish footer (Create)\n' + \ - '# tyto show footer (Show config)\n' + \ - '# tyto show-wip/show-www footer (Show HTML)\n' + \ - '# tyto edit footer (edit this file)\n' + \ - '# How Put any HTML code\n' + \ - '# Notes - Lines are ignored if:\n' + \ - '# - empty\n' + \ - '# - begin with "#"\n' + \ - '# - Do NOT copy to template directory' - '# %s\n'%(20 * "-") - - try: footer_lang = langs.site.footer_doc - except: footer_lang = footer_en - - # Final HTML footer code - footer = \ - '%s\n'%footer_lang%(tyto.Tyto, dom.footer_f) + \ - '
\n' + \ - ' \n' + \ - ' \n' + \ - '
' - - # Create new default file, or ask if exists - if tyto.exists(dom.footer_f): - answer = asking(' ├ %s%s '%( - langs.site.form_reset, langs.site.q - ), False) - - if not answer in answer_yes: - if option == "new": return - logs.out("255", '', True) - - tyto.set_file(dom.footer_f, 'New', footer) - diff --git a/src/var/lib/tyto/program/forms.py b/src/var/lib/tyto/program/forms.py new file mode 100644 index 0000000..4862460 --- /dev/null +++ b/src/var/lib/tyto/program/forms.py @@ -0,0 +1,243 @@ +#!/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: Forms (edit, create domain, questions...) +# File: /var/lib/tyto/program/form.py +#---------------------------------------------------------------------- + +#------------------------- +# Funny Stats Project +#------------------------- +# file lines : +# file comments : +# file functions: +# file program : +#-------------------------- + +import os, re, configparser +import debug, domain, langs, tools + + +#====================# +# Exit Tyto with log # +# user interrupts... # +#--------------------# +def maybe_later(expected, answer): + debug.out(255, expected, answer, True, 0, True) + + +#=========================# +# When asking something # +# yes_only : True / False # +#-------------------------# +def ask(q, yes_only, default): + expected = "" + if yes_only: + expected = langs.logs.ok + + try: + answer = input(q) + except KeyboardInterrupt: + print("") + maybe_later(expected, "?") + + # return default answer if exists + if not answer: + if default: + return default + + maybe_later(expected, "?") + + # Answer is a Y/N process + if yes_only: + for ok in langs.logs.ok: + if answer.lower() == ok.lower(): + return True + maybe_later(expected, answer) + + return answer + + +#====================================# +# Shorter value to show in questions # +# return value[0:12] +#------------------------------------# +def shorter(value): + if len(value) > 12: + return '%s...'%(value[0:12]) + + # Or legacy + return value + + +#=========================# +# Confirm domain name # +# from directory basename # +# ------------------------# +def ask_domain_shortname(config_name): + q = "> %s (%s)%s "%(langs.logs.configure_domain, config_name, langs.logs.q) + ask(q, True, False) + + + +#======================# +# Getting domain Title # +#----------------------# +def ask_domain_title(): + domain.dcf_load() + title = domain.dcf.get("DOMAIN", "title") + + q = "> %s (%s)%s "%(langs.logs.domain_title, shorter(title), langs.logs.q) + answer = ask(q, False, title) + if answer != title: + tools.update_ini_file(domain.dcf_uri, "DOMAIN", "title", answer) + + +#===========================# +# Get domain creation date # +# Check if date match regex # +#---------------------------# +def ask_domain_date(): + domain.dcf_load() + date = domain.dcf.get("DOMAIN", "date") + example = date or "YYYY[-MM-DD]" + + 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 + + # Exit if not valid + if not test: + debug.out(50, "YYYY[-MM-DD]", answer, True, 2, True) + + if answer != date: + tools.update_ini_file(domain.dcf_uri, "DOMAIN", "date", answer) + + +#========================# +# Get domain description # +#------------------------# +def ask_domain_about(): + domain.dcf_load() + about = domain.dcf.get("DOMAIN", "about") + + q = "> %s (%s)%s "%(langs.logs.domain_about, shorter(about), langs.logs.q) + answer = ask(q, False, about) + if answer != about: + tools.update_ini_file(domain.dcf_uri, "DOMAIN", "about", answer) + + +#=======================# +# Get domain admin mail # +#-----------------------# +def ask_domain_mail(): + domain.dcf_load() + mail = domain.dcf.get("DOMAIN", "mail") + + q = "> %s (%s)%s "%(langs.logs.domain_mail, shorter(mail), langs.logs.q) + answer = ask(q, False, mail) + if answer != mail: + tools.update_ini_file(domain.dcf_uri, "DOMAIN", "mail", answer) + + +#===============================================# +# Get domain tags (wil be used in all articles) # +#-----------------------------------------------# +def ask_domain_tags(): + domain.dcf_load() + tags = domain.dcf.get("DOMAIN", "tags") + + q = "> %s (%s)%s "%(langs.logs.domain_tags, shorter(tags), langs.logs.q) + answer = ask(q, False, tags) + + if answer != tags: + # Remove useless spaces for HTML meta + tuple_tags = answer.rsplit(",") + answer = "" + for i, tag in enumerate(tuple_tags): + answer = answer + tag.strip() + if i != len(tuple_tags) - 1: + answer = answer + "," + + tools.update_ini_file(domain.dcf_uri, "DOMAIN", "tags", answer) + + +#===================================# +# Get domain lang # +# default en if no translation file # > !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! < TODO +#-----------------------------------# +def ask_domain_lang(): + domain.dcf_load() + lang = domain.dcf.get("WEBSITE", "lang") or langs.get_sys_lang() + + q = "> %s (%s)%s "%(langs.logs.domain_lang, lang, langs.logs.q) + answer = ask(q, False, lang).lower() + + # Lang Format is 2 character + if len(answer) != 2: + debug.out("8", "xx", answer, True, 2, False) + ask_domain_lang() + return + + # Check if translation file exists + if not langs.translation_exists("website", answer, False): + debug.out(103, "en", "%swebsite_en.py"%langs.trfs, True, 1, False) + answer = "en" + + if answer != lang: + tools.update_ini_file(domain.dcf_uri, "WEBSITE", "lang", answer) + + +#===================================# +# Get domain server root # +#-----------------------------------# +def ask_domain_server(): + domain.dcf_load() + srv = domain.dcf.get("SERVER", "root") + + if srv: + if not tools.dir_exists(srv, False): + tested = True + srv = "" + + q = "> %s (%s)%s "%(langs.logs.domain_srv, srv, langs.logs.q) + answer = ask(q, False, srv) + + # Check if directory exists + if not tools.dir_exists(answer, False): + answer = srv + ask_domain_server() + return + + domain.dcf_update_values(answer) + diff --git a/src/var/lib/tyto/program/help.py b/src/var/lib/tyto/program/help.py new file mode 100644 index 0000000..fbddfc3 --- /dev/null +++ b/src/var/lib/tyto/program/help.py @@ -0,0 +1,43 @@ +#!/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: Show help commands +# File: /var/lib/tyto/program/help.py +#---------------------------------------------------------------------- + +#------------------------- +# Funny Stats Project +#------------------------- +# file lines : +# file comments : +# file functions: +# file program : +#-------------------------- + +import langs, debug + + +#==========================================# +# Show help in system langage # +# Help Contents is in translations/logs_XX # +#------------------------------------------# +def show(action, target): + print(langs.logs.help_contents) diff --git a/src/var/lib/tyto/program/html.py b/src/var/lib/tyto/program/html.py deleted file mode 100644 index 77bca70..0000000 --- a/src/var/lib/tyto/program/html.py +++ /dev/null @@ -1,544 +0,0 @@ -# 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 Affero General Public License -# as published by the Free Software Foundation, either version 3 of the -# License, or of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -#---------------------------------------------------------------------- -# XMPP: echolib (im@echolib.re) -# -# Description: Create HTML page -# File: /var/lib/tyto/program/html.py -#---------------------------------------------------------------------- - -#------------------------- -# Funny Stats Project -#------------------------- -# file lines : 544 -# file comments : 71 -# file functions: 8 -# file program : 414 -#-------------------------- - - -import os, sys, importlib -import logs, db, dom, tyto, form, langs - - -# Publish option can be -wip_opts = ('wip', 'new') -pub_opts = ('www', 'pub') - -# Not a line if it starts with...(for sidebar, navbar) -nolines = ('#', '/') - -# For static modules -if dom.ready: - tags_html_mods = \ - { - dom.wip_navbar_f : '', - dom.wip_sidebar_f : '', - dom.wip_metas_f : '', - dom.wip_footer_f : '' - } - -#==========================# -# Load article DB # -# Start HTML page sections # -#--------------------------# -def set_page(target, article_bottom): - create_metas_page() # Include metas tags - create_main_page(target, article_bottom) # Create main page - - -#============================================# -# Set metas_page to be included in main page # -#--------------------------------------------# -def create_metas_page(): - global metas_page - - # Settings for metas - #------------------- - metas_page = '' - scale = 'width=device-width, initial-scale=1.0' - all_tags = dom.tags + ',' + db.meta_tags - css_ref = 'href="%stemplate/%s"'%(db.sub_uri, dom.styles) - rss_ref = 'type="application/rss+xml" ' + \ - 'href="%s%s" title="RSS 2.0. %s %s %s"'%( - db.sub_uri, dom.rss, - dom.title, dom.sep, dom.shortname - ) - icon_ref = 'type="image/png" href="%stemplate/%s"'%( - db.sub_uri, dom.favicon - ) - relme = '' # External URL in metas (if exists in config domain) - if dom.relme: - relme = '\n '%( - dom.relme - ) - - # Create author and date publish section infos - create_html_time_meta('wip') - - # Set all raw HTML metas - #----------------------- - global metas - metas = \ - tags_html_mods[dom.wip_metas_f] + '\n' + \ - ' \n'%scale + \ - ' \n'%dom.www_url + \ - ' \n'%dom.lang_site + \ - ' \n'%dom.mail + \ - ' \n'%dom.license + \ - ' \n'%tyto.Tyto + \ - ' \n'%db.title + \ - ' \n'%db.author + \ - ' \n'%db.about + \ - ' \n'%all_tags + \ - '%s'%meta_pub + \ - ' \n'%db.http_www + \ - ' \n'%(rss_ref) + \ - ' \n'%css_ref + \ - ' \n'%icon_ref + \ - ' \n' + \ - ' \n'%dom.title + \ - ' \n'%db.title + \ - ' \n' + \ - ' \n'%db.http_www + \ - ' \n'%db.about + \ - ' \n'%db.snpic + \ - '%s'%relme + \ - ' %s %s %s'%(db.title, dom.sep, dom.title) - - -#=======================================# -# Set main page, with all HTML sections # -#---------------------------------------# -def create_main_page(target, article_bottom): - global main_page, post_html_code - - # Create link for website's logo - #------------------------------- - logo_html = \ - '\n'%(11 * " ") + \ - '%s\n'%(15 * " ") + \ - '%s'%(8 * " ") - - post_html_code = '' - if dom.article_code: - post_html_code = \ - ' \n' + \ - ' {%s} \n'%( - langs.site.tyto_psrc, db.title, - langs.site.source_code - ) - - #-----------------------# - # Create main HTML Page # - #-----------------------# - main_page = \ - '\n' + \ - '\n'%dom.lang_site + \ - ' \n' + \ - '%s\n'%metas + \ - ' \n\n' + \ - ' \n' + \ - '
\n' + \ - '
\n' + \ - ' \n' + \ - '
\n' + \ - '

\n' + \ - ' %s\n'%dom.title + \ - '

\n' + \ - '

%s

\n'%dom.about + \ - '
\n' + \ - '
\n' + \ - tags_html_mods[dom.wip_navbar_f] + '\n' + \ - '
\n' + \ - '
\n' + \ - '

%s

\n'%( - db.title, langs.site.w_written, db.date, - langs.site.by, db.author, - db.title, - ) + \ - '%s\n'%article_bottom + \ - '
\n' + \ - '

\n' + \ - ' %s, %s\n'%( - db.author, langs.site.author_of, db.title, - db.author, langs.site.le - ) + \ - '%s\n'%time_html_pub + \ - '%s'%post_html_code + \ - '

\n' + \ - '
\n' + \ - '
\n' + \ - '\n' + \ - tags_html_mods[dom.wip_sidebar_f] + '\n' + \ - '
\n' + \ - tags_html_mods[dom.wip_footer_f] + '\n' + \ - '
\n' + \ - ' \n' + \ - '' - - -#============================================# -# Create HTML line for article infos section # -# when wip, and publish # -#--------------------------------------------# -def create_html_time_meta(process): - # Need to reload the DB to get last time updated - importlib.reload(db) - - global time_html_pub, meta_pub, date_raw - - if process == 'wip': - try: - date_raw = db.date_wip #