From ba0e0e826d0b134573b057e8779fc1d06c66864a Mon Sep 17 00:00:00 2001 From: Cyrille L Date: Thu, 15 Dec 2022 12:44:24 +0100 Subject: [PATCH] New cleaned code --- FR_Installation.md | 21 - README.md | 57 +- src/usr/{local => }/bin/tyto | 0 src/var/lib/tyto/help/CHANGELOG.md | 16 - src/var/lib/tyto/help/FR_Installation.md | 21 - src/var/lib/tyto/help/LICENSE | 661 -------- src/var/lib/tyto/help/README.md | 180 --- src/var/lib/tyto/program/check.py | 1771 +++++++--------------- src/var/lib/tyto/program/domain.py | 840 +++++----- src/var/lib/tyto/program/html.py | 331 ---- src/var/lib/tyto/program/log.py | 81 - src/var/lib/tyto/program/publish.py | 9 - src/var/lib/tyto/program/rss.py | 102 -- src/var/lib/tyto/program/sidebar.py | 199 +-- src/var/lib/tyto/program/tyto.py | 403 +++++ src/var/lib/tyto/program/wip.old.py | 412 ----- src/var/lib/tyto/program/wip.py | 850 +---------- 17 files changed, 1371 insertions(+), 4583 deletions(-) delete mode 100644 FR_Installation.md rename src/usr/{local => }/bin/tyto (100%) delete mode 100644 src/var/lib/tyto/help/CHANGELOG.md delete mode 100644 src/var/lib/tyto/help/FR_Installation.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/program/html.py delete mode 100644 src/var/lib/tyto/program/log.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/tyto.py delete mode 100644 src/var/lib/tyto/program/wip.old.py diff --git a/FR_Installation.md b/FR_Installation.md deleted file mode 100644 index f508aec..0000000 --- a/FR_Installation.md +++ /dev/null @@ -1,21 +0,0 @@ -# Installation manuelle - -Si vous utilisez Debian, il est plus que recommandé de procéder à -l'installation par le paquet .deb - -## Préparer les dossiers -```` -sudo mkdir -p /var/lib/tyto /etc/tyto /var/log/tyto -sudo touch /usr/local/bin/tyto -sudo chown -R USER:GROUP /var/lib/tyto /etc/tyto /var/log/tyto -sudo chown USER:GROUP /usr/local/bin/tyto -sudo chmod +x /usr/local/bin/tyto - -git clone https://git.a-lec.org/echolib/tyto -rsync -a folders'repo/ to /folders/ - -# Créer votre dossier pour le serveur web -# On utilise en général /var/www/ -# Celui-ci sera à renseigner lors de la création d'un domaine dans Tyto -sudo mkdir -p /var/www/ -```` diff --git a/README.md b/README.md index d80c415..6a2121e 100644 --- a/README.md +++ b/README.md @@ -41,25 +41,26 @@ abbr: NOM (en majuscule) ### Titre h1 à h6 ``` #1 Titre 1 -( +(( Un paragraphe -) +)) #2 Titre 2 ``` + ### Paragraphes ``` -( CSS +(( CSS Un paragraphe -) +)) ``` ### Code Brut ``` -[[ CSS +{{ CSS def hello_world(): print("Hello") -]] +}} ``` ### Listes ul/ol @@ -75,36 +76,36 @@ def hello_world(): ### Citations ``` -(( CSS +[[ CSS _cite: autheur _lang: langue _link: lien _year: année ou date YYYY-MM-DD _book: référence -( +(( Citation placée dans un paragraphe -) )) +]] -(( CSS +[[ CSS Citation simple sans référence -)) +]] ``` ### Ancres ``` ->> id -( +-> id +(( un long paragraphe -) -( +)) +(( >_id:Retourner au point d'ancre_< -) +)) ``` ### Retour à la ligne HTML ``` -| >>>
+| #
``` ### Lien vers URL @@ -119,21 +120,23 @@ Voir ce __Nom du lien ### Gras, Strong, italique... ``` -*_très gras_* >>> -+_gras léger_+ >>> -/_en italique_/ >>> -\_en italique_\ >>> -~_texte barré_~ >>> -<_Code_> ou (_Code_) >>> -=_Citation rapide_= >>> -×_Classe personnalisée_× >>> --_Souligné_- >>> +*_très gras_* # ++_gras léger_+ # +/_en italique_/ # +[_en italique_] # +~_texte barré_~ # +{_Code_} # +:_Citation rapide_: # +%_Classe personnalisée_% >>> +._Souligné_. # ``` ### Abréviations ``` -# NOM sera remplacé par nom si défini en entête +# ! NOM sera remplacé par "nom" dans la page si défini en entête +# sinon, NOM sera conservé +# Toujours écrire en majuscule les ABBR dans l'article brut # nom Avec ce NOM. ``` diff --git a/src/usr/local/bin/tyto b/src/usr/bin/tyto similarity index 100% rename from src/usr/local/bin/tyto rename to src/usr/bin/tyto diff --git a/src/var/lib/tyto/help/CHANGELOG.md b/src/var/lib/tyto/help/CHANGELOG.md deleted file mode 100644 index 75c6ac6..0000000 --- a/src/var/lib/tyto/help/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -# Changelog - -Tyto - Littérateur -- Repository: https://git.a-lec.org/echolib/tyto -- Issues: https://git.a-lec.org/echolib/tyto/-/issues -- Changelog: https://git.a-lec.org/echolib/tyto/-/blob/main/CHANGELOG.md -- License: https://git.a-lec.org/echolib/tyto/-/blob/main/LICENSE - -Tyto - Litterateur is a Libre project to create and manage multiple -websites from articles' files. Tyto uses its own syntax to convert -your articles in HTML5 static pages. Tyto works on a GNU/Linux system -and needs minimal dependancies. -- python3 rsync nano gawk curl - -## [0.9.0] First Commit version (pre-final) - diff --git a/src/var/lib/tyto/help/FR_Installation.md b/src/var/lib/tyto/help/FR_Installation.md deleted file mode 100644 index f508aec..0000000 --- a/src/var/lib/tyto/help/FR_Installation.md +++ /dev/null @@ -1,21 +0,0 @@ -# Installation manuelle - -Si vous utilisez Debian, il est plus que recommandé de procéder à -l'installation par le paquet .deb - -## Préparer les dossiers -```` -sudo mkdir -p /var/lib/tyto /etc/tyto /var/log/tyto -sudo touch /usr/local/bin/tyto -sudo chown -R USER:GROUP /var/lib/tyto /etc/tyto /var/log/tyto -sudo chown USER:GROUP /usr/local/bin/tyto -sudo chmod +x /usr/local/bin/tyto - -git clone https://git.a-lec.org/echolib/tyto -rsync -a folders'repo/ to /folders/ - -# Créer votre dossier pour le serveur web -# On utilise en général /var/www/ -# Celui-ci sera à renseigner lors de la création d'un domaine dans Tyto -sudo mkdir -p /var/www/ -```` diff --git a/src/var/lib/tyto/help/LICENSE b/src/var/lib/tyto/help/LICENSE deleted file mode 100644 index 2a1caa8..0000000 --- a/src/var/lib/tyto/help/LICENSE +++ /dev/null @@ -1,661 +0,0 @@ - GNU AFFERO GENERAL PUBLIC LICENSE - Version 3, 19 November 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - 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 9f49fa4..0000000 --- a/src/var/lib/tyto/help/README.md +++ /dev/null @@ -1,180 +0,0 @@ -# STL: Statique Littérateur -STL est une évolution du projet GSL. STL permet de créer un ou plusieurs -sites web/blogs statiques, en fonction de leur nom de domaine. - -Tout comme GSL, STL reprend une grande partie de l'écriture nouvelle de -vos articles, en apportant quelques évolutions. Les articles sont donc -au format .stl. - - -# Fonctionnement de STL ; le dossier de base -Contrairement à GSL, vos articles et les pages de votre site web sont -situés dans le même dossier de base. Pour obtenir ce dossier de base, -et configurer votre domaine, vous devez d'abord vous placer dans le -dossier de votre choix, puis lancer la commande de configuration. - -``` -cd MON-DOSSIER-PREFERE -stl domain new - -# Vous pouvez également pré-remplir votre domaine en fonction de l'URL -stl domain new https://mon-site.xyz -``` - -Dans ce dossier de base (MON-DOSSIER-PREFERE), après la configuration de -votre domaine, vous trouverez de nouveaux dossiers : -- articles/ -- - images/ -- - files/ - -Les sous-dossiers images/ et files/ sont proposés afin de faciliter la -réutilisation d'images et de fichiers (PDF, ou autres) déjà présents -dans un autre article. Lors de la synchronisation, il seront copiés à la -racine wip de votre serveur. Le but : faire en sorte que le -navigateur n'ait pas à recharger un même fichier depuis une URL -différente - ce qui plomberait la rapidité d'affichage de la page et -l'intérêt d'un site statique. L'utilisation de cette fonction dans vos -articles est simple ; voir la documentation expliquant comment écrire un -article dans le dossier help. - -Dans le dossier du serveur (/var/www est un exemple), vous trouverez -les dossiers suivants : -- /var/www/DOMAIN/wip/ -- - template (logos, styles.css, sidebar.html, footer.html, metas.html...) -- - images -- - files -- /var/www/DOMAIN/www/ (non créé pour une installation locale) -- - template/ -- - images -- - files - - -## Installation (server, ou local) -Il est possible d'utiliser STL de 2 manières différentes. Lors de la -configuation d'un nouveau domaine, vous devrez choisir entre une -installation faite sur un serveur distant, et une installation faite -en local (sur votre PC). Vous pouvez bien sûr choisir une installation -de type "server" sur votre PC, si celui-ci sert de serveur web. - -Concernant la décoration du site (styles.css, logos), les fichiers -devront être placés dans le dossier serveur /wip/template/ (créé par STL -lors de l'ajout d'un domaine). - - -### Installation "server" -À choisir si votre PC sert de serveur web, ou si vous avez installé STL -sur votre serveur distant. - -Lorsque vous installez STL, sur votre serveur distant, vous pouvez gérer -pour un même nom de domaine, votre site sur 2 adresses URL différentes. -La version WIP, permet de prévisualiser les modifications apportées à -vos pages (sans modifier celles sur WWW) avant de les valider sur votre -site officiel. - -Lorsque votre site prévisualisé sur WIP vous plaît, vous pouvez alors -synchroniser le dossier WIP sur WWW grâce à la commande : - -``` -# Pour publier un article précis -stl publish (ARTICLE) - -# Pour publier tous les articles dans WIP -stl publish all -``` - -Note : cette commande crée automatiquement le flux RSS dans WIP avant -de tous synchroniser sur WWW. - - -### Installation "local" -À choisir si vous voulez utiliser STL sur votre PC, et synchroniser -vous-même le dossier WIP sur votre serveur distant. Inutile donc, -d'installer STL sur le serveur distant. - -Lors d'une utilisation locale, STL ne crée pas le dossier WWW, et ne -synchronise donc pas le dossier WIP vers WWW. C'est à vous de le faire -(via ssh, par exemple). - -Vous devrez lorsque votre site vous plaît localement lancer la création -du flux RSS - avant de synchroniser votre site local sur votre serveur -distant - avec la commande : - -``` -stl rss -``` - - -# Utilisation de STL -Afin de gérer vos articles, vous devez vous placer dans MON-DOSSIER-PREFERE. -L'autocomplétion est activée et personnalisée pour vous aider à trouver -(ARTICLE.stl). - - -## Créer votre arborescence -Dans MON-DOSSIER-PREFERE, vous trouverez le dossier "articles". Celui-ci -sert de base à votre domain.xyz sur votre serveur. C'est dans ce dossier -"articles", que vous pouvez créer vos articles et vos sous-dossiers. -Il est à noter que le nom de l'article est important, puisque STL -l'utilisera en le transformant en .html. Il est donc recommandé - mais -pas obligatoire - de nommer vos articles index.stl, pour obtenir une page -index.html. Si vous voulez créer une page 404, nommez votre article 404.stl -à la racine du dossier "articles". - - -## Convertir votre article en HTML -Placez vous dans MON-DOSSIER-PREFERE. - -Avant de pouvoir convertir votre article, STL dispose d'un système de -vérification de la syntaxe STL. Si des erreurs sont trouvées, un système -de logs vous aidera à corriger ces erreurs. - -``` -# N'oubliez pas d'utiliser l'autocomplétion -stl check (ARTICLE.stl) -``` - -Vous pouvez maintenant le convertir en HTML dans le dossier wip - -``` -stl wip (ARTICLE.stl) -``` - - -## Utiliser la sidebar -C'est la seule partie du site qui est semi-statique. STL fait appel à -nginx, qui va se charger de traduire la balise HTML ``, -et afficher le rendu du fichier sidebar.html - -Chaque article, une fois convertit avec l'argument wip peut être placé -dans la sidebar à la position désirée, entre 1 et la valeur maximum -décidée, lors de la configuration du domaine. - -``` -stl sidebar add 1 (ARTICLE.stl) -``` - -Vous pouvez également décider de placer un article ausitôt convertit -avec l'argument wip sidebar=POSITON - -``` -stl wip sidebar=2 (ARTICLE.stl) -``` - -## Documentation de STL -Les fichiers de documentations sont dans le dossier help. -Le README est accessible depuis la ligne de commande, comme les arguments -utilisables. - -``` -stl help -stl readme -``` - - -## Dépendances -STL est écrit en bash, et a besoin des utilitaires -- gawk -- rsync -- nano -- curl - diff --git a/src/var/lib/tyto/program/check.py b/src/var/lib/tyto/program/check.py index b7c467b..aab12c7 100644 --- a/src/var/lib/tyto/program/check.py +++ b/src/var/lib/tyto/program/check.py @@ -2,8 +2,8 @@ # Name: Tyto - Littérateur # Type: Global functions for check # Description: Check article contents. Create Stats and Database -# file: wip.py -# Folder: /var/lib/tyto/scripts/ +# file: check.py +# Folder: /var/lib/tyto/program/ # By echolib (XMPP: im@echolib.re) # License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 @@ -19,1302 +19,593 @@ # Import needed libs import sys, os, re, datetime -import domain, log, wip +from datetime import datetime +from time import gmtime, strftime +import time +import tyto -Post_Err = False -post_uri = '' -msg_log = '' +# Load domain configuration if exists +if tyto.domain_exists: exec(open(tyto.domain_conf).read()) -# markers (regex) -m_anchor = r'^>>' # No close marker - -# 'Open' , 'Close' , 'Name' -markers_reg = [ - [ r'^\($|^\(\s' , r'^\)$' , 'paragraphs' ], - [ r'^\(\($|^\(\(\s', r'^\)\)$', 'quotes' ], - [ r'^\[\[$|^\[\[\s', r'^\]\]$', 'brut codes' ], - [ r'^-\($|^-\(\s' , r'^-\)$' , 'lists' ] - ] -markers_opt = ( - 'image:', - 'file:', - 'link:', - 'abbr:' - ) - -#=======# -# Tools # -#=======#-------------------------------------------------------------- -#===============================# -# Define article IDs, if exists # -# Used for check, wip... # -#-------------------------------# -def post_IDs(file_post): - # Check if argument's file (.tyto) or exit - if not file_post: - print(':< Unused argument file') - sys.exit(1) - - global post_srv - post_srv = file_post.replace('.tyto','.html') - - # Check if file exists or exit - global post_uri - post_uri = '%s%s'%(domain.domain_articles, file_post) - - if not os.path.exists(post_uri): - print(':< Unused file: %s'%post_uri) - sys.exit(1) - - # Set HTML file from file_post - file_html = file_post.replace('.tyto','.html') - if file_html.endswith('index.html'): - file_html = file_html.replace('index.html', '') - - # Complete URL post file - global post_url - post_url = '%s%s/%s'%( - domain.domain_protocol, domain.domain_name, file_html - ) - - global post_dir - post_dir = file_post.replace(os.path.basename(file_post), '') - - # From argument file_post - # Set WEB link prefix. Count / in uri - global weburi - slash = 0 - weburi = '' - - for s in file_post: - if s == '/': slash += 1 - - if slash == 0: - weburi = './' - else: - for i in range(0,slash): - weburi = '%s../'%weburi - - # Get Hash from article's content - global hash_chk - hash_chk = get_filesum(post_uri, True) - - # Get Hash ID from URI - global curr_post_ID, curr_post_db, post_logs - curr_post_ID = get_filesum(post_uri, False) - - # Set database file for this article - curr_post_db = '%s%s.conf'%(domain.domain_db, curr_post_ID) - - # Set and check/create logs file for this article - post_logs = '%s%s.log'%(domain.domain_logs, curr_post_ID) - - #------------------ - # Article Database - #------------------ - # Check if Article has DB - # Source its conf and compare - global db_exist - try: - exec(open(curr_post_db).read(),globals()) - db_exist = True - except: - db_exist = False - - if db_exist: - # Set HTML file - global srv_post_wip, srv_post_www - srv_post_wip = [False, domain.srv_wip + file_html] - srv_post_www = [False, domain.srv_www + file_html] - - # Set to True, if file exists on servers - if os.path.exists(srv_post_wip[1]): srv_post_wip[0] = True - if os.path.exists(srv_post_www[1]): srv_post_www[0] = True - -#============================================# -# Check and if not exist, create domain dirs # -# Also Used to create when new domain set # -#--------------------------------------------# -def create_domain_dirs(path_type): - # Needed direcories when creating a new domain - if 'all' in path_type: - all_dirs = [ - domain.srv_wip_template, - domain.srv_wip_images, - domain.srv_wip_files, - domain.srv_www_template, - domain.srv_www_images, - domain.srv_www_files, - domain.domain_articles, - domain.domain_images, - domain.domain_files, - domain.domain_sdb_dir, - domain.domain_db, - domain.domain_logs - ] - for folder in all_dirs: - os.makedirs(folder, exist_ok=True) - - # Check/Create needed directories (only for 'check' process) - if 'db' in path_type: - os.makedirs(domain.domain_db, exist_ok=True) - os.makedirs(domain.domain_logs, exist_ok=True) - -#=======================# -# Return sum of srcfile # -# src: True = file # -# False = string # -#-----------------------# -def get_filesum(path,src): - from hashlib import blake2b - file_sum = blake2b(digest_size=4) - - if src: file_sum.update(open(path, 'rb').read()) - else : file_sum.update(path.encode()) - return file_sum.hexdigest() +post_err = False #=========================# # Manage Argument 'check' # # Start checking article # #-------------------------#-------------------------------------------- -def manage_check(file_post, Force): - # Set needed IDs - post_IDs(file_post) +def manage_check(target, option): + global post_bottom, article_bottom + global post_words - # Start checking Post, then exit if errors found in - process_article(post_uri, Force) - - -#==========================# -# Pre-processing post file # -#--------------------------# -def process_article(post_uri, Force): - global article - # Check needed directories. Create if not exist - create_domain_dirs('db') - - # Create logs - #------------- - if not os.path.exists(post_logs): - file = open(post_logs, "w") - file.write('') - file.close() - msg_log = 'Log > Create logs file for %s in %s\n'%( - post_uri, post_logs) - log.append_f(post_logs, msg_log, 0) - - # Article Database - #------------------ - # In check process: no values (kept from db, if exists) - global hash_wip, hash_www, time_wip, time_www - - hash_wip = time_wip = hash_www = time_www = '' - - if db_exist: - # backup hash_wip/www values - hash_wip = post_wip[0];time_wip = post_wip[1] - hash_www = post_www[0];time_www = post_www[1] + # target needed + if not target: tyto.exiting("5", '', True) - # Compare chk Hashes. - # Pass if Force, and not same - if hash_chk == post_chk[0] and not Force: - print(':D Check was already done, on', post_chk[1]) - sys.exit(0) + # Article exists + has DB ? + db_exists = tyto.get_db_post(target) + + # Manage option + if option == 'Edit': + tyto.edit_file(tyto.uri_root) + return - # Processing - #----------- - # Prepare: put post's contents file in headers and article strings - post_to_strings(post_uri) + if db_exists: + exec(open(tyto.post_db).read(),globals()) + if hash_chk == tyto.hash_post and not option == 'Force': + tyto.exiting("20", date_chk, True) + + # Start processes + file_to_string(tyto.uri_root) + + # Protect inline-codes + tyto.protect_icodes(post_bottom, article_bottom) + post_bottom = tyto.protect_article.rsplit('\n') + article_bottom = tyto.protect_article + + # Protect block-codes and quotes + tyto.protect_bcodes_quotes('check', post_bottom) + post_bottom = tyto.protect_article.rsplit('\n') + article_bottom = tyto.protect_article + + # Count words in article. Not from quotes, block-codes, icode = 1 + post_words = len(article_bottom.strip().split(" ")) + + # Check for valid contents + check_content(post_bottom) + post_bottom = article_bottom.rsplit('\n') + + check_headers(post_header) + - # Send to log - msg_log = 'Check > Article: %s. logs: %s'%(post_uri,post_logs) - log.append_f(domain.tyto_logs,msg_log,0) + # Exit if unused needed tags + if post_err: tyto.exiting("7", '', True) - # Check markers in headers - check_post_header(headers.rsplit('\n')) - if Post_Err: sys.exit(1) - - # Protect bCodes, keep markers for stats, before checking other markers - wip.convert_bcodes(article.rsplit('\n'), - '[[', ']]', - domain.domain_css) - article = wip.article_temp - - # Protect quotes, keep markers for stats, before checking other markers - wip.convert_bcodes(article.rsplit('\n'), - '((', '))', - domain.domain_css) - article = wip.article_temp - - # Protect iCodes, keep markers for stats - wip.convert_icodes(article.rsplit('\n'), domain.domain_css) - article = wip.article_temp - - # Check titles/comments in article - check_article_titles(article.rsplit('\n')) - - # Check links (anchors) - check_links_anchors(article) - - # Check titles/comments in article - check_lists_contents(article.rsplit('\n')) - - # Check other markers - check_article_markers(article) - - # Error in article - #--------------------- - if Post_Err: sys.exit(1) - - # No Domain registred yet - #------------------------- - # If in a domain Process to DB - if not domain.domain_active: - print(':/ Article is Ok, but will not be converted') - sys.exit(0) + # No error + create_database() - # No Error... - #------------ - # Create (file).wip for this article to use with wip argument - global post_tmp - post_tmp = '%s%s.wip'%(domain.domain_db, curr_post_ID) - - # Create NEW file - file = open(post_tmp, "w") - file.write('') - for line in article.rsplit('\n'): - if len(line) == 0 : continue - elif line.startswith('# ') : continue - elif line.startswith('##') : continue - file.write(line + '\n') - file.close() - - # Create DB - create_DB(curr_post_db) - print(':D Article is Ok and ready to "tyto wip"') -#=========================================# -# Put file in strings => headers, article # -# But, check if separator is defined... # -#-----------------------------------------# -def post_to_strings(post_uri): - # Check if separator from header and article ; else: exit - file_string = open(post_uri,'r').read() - if not '-----' in file_string: - msg_log = 'Unused separator "-----" (header,post)' - log.append_f(post_logs, msg_log, 1) - sys.exit(0) +#=====================# +# Find in post_bottom # +#---------------------# +def isin(term, post_bottom): + for x in post_bottom: + if re.search(r'%s'%term, x): + return True + return False + + +#=================================# +# Create string article from file # +# Check if separator or exit # +#---------------------------------# +def file_to_string(post_file): + # Check if separator + global article + global article_header, article_bottom + global post_header, post_bottom - # From Separator... - # Split post in 2 strings for Headers and Article - global headers, article, post_lines, headers_ln + article = open(post_file, 'r').read() - headers = article = '' - post_lines = file_string.rsplit('\n') - post = False + if not '-----' in article: + tyto.exiting("6", '-----', True) - for line in post_lines: - if line.startswith('-----'): - post = True + # Set from separator, NOT splitted by new line + article_header = article.rsplit('-----')[0] + article_bottom = article.rsplit('-----')[1] + + # Set from separator, splitted by new line + post_header = article.rsplit('-----')[0].rsplit('\n') + post_bottom = article.rsplit('-----')[1].rsplit('\n') + + +#==================================# +# Check tags from article's header # +#----------------------------------# +def check_headers(post_header): + global post_err, err, web_uri, date_check + global date, title, author, tags, about + global stat_links, stat_images, stat_files, stat_bruts, stat_abbrs + global post_tags + + #post_tags = 0 + + # Needed Tags + title = author = tags = about = '' + date = () + + # Statistics + stat_links = stat_images = stat_files = stat_bruts = stat_abbrs = 0 + +### + # First session for needed tags # + # Read articles lines, till separator # + #-------------------------------------# + for ln, line in enumerate(post_header, 1): + + # Set each needed tag # + # Only the first one is set # + #---------------------------# + tag = 'title:' + if line.startswith(tag): + if title: continue + title = line.rsplit(tag)[1].lstrip() continue - if post: article = '%s\n%s'%(article,line) # In post content - else: headers = '%s\n%s'%(headers,line) # In post header - - # Get number lines in headers, min line separator - headers_ln = len(headers.split("\n")) - 1 + tag = 'about:' + if line.startswith(tag): + if about: continue + about = line.rsplit(tag)[1].lstrip() + continue -#=================# -# HEADERS CONTENT # -#=================# -#====================================# -# Init stats, arrays... # -# Loop into headers to check markers # -#------------------------------------# -def check_post_header(headers): - # Mandatory markers - global title, about, author, tags, date + tag = 'tags:' + if line.startswith(tag): + if tags: continue + tags = line.rsplit(tag)[1].lstrip() + post_tags = len(tags.strip().split(",")) + continue + + tag = 'author:' + if line.startswith(tag): + if author: continue + author = line.rsplit(tag)[1].lstrip() + continue - # Set Mandatory marker. 0:True/False 1:ln 2: Content - title = about = author = tags = date = ('','','') - - # Set Stats - global stats_links_uniq, stats_links, stats_links_p - global stats_files_uniq, stats_files_p - global stats_images_uniq, stats_images_p - global stats_abbrs_uniq, stats_abbrs_p - global stats_bruts_uniq, stats_bruts_p - - stats_links_uniq = stats_links = stats_links_p = 0 - stats_files_uniq = stats_files_p = 0 - stats_images_uniq = stats_images_p = 0 - stats_abbrs_uniq = stats_abbrs_p = 0 - stats_bruts_uniq = stats_bruts_p = 0 - - # Set Optional markers. 0:ln 1:Name 2:URL 3:Alt - link = file = image = brut = ('','','','') - - #----------------------- - # Loop in headers string - #----------------------- - for ln, line in enumerate(headers, 1): - - #----------------------- - # Set mandatory markers - #----------------------- - if line.startswith('title:'): - title = (True,ln,line.split('title:')[1].lstrip()) - elif line.startswith('about:'): - about = (True,ln,line.split('about:')[1].lstrip()) - elif line.startswith('author:'): - author = (True,ln,line.split('author:')[1].lstrip()) - elif line.startswith('tags:'): - tags = (True,ln,line.split('tags:')[1].lstrip()) - elif line.startswith('date:'): - date = (True,ln,line.split('date:')[1].lstrip()) - - #---------------------- - # Set optional markers - #---------------------- - # link: - if line.startswith('link:'): - stats_links_uniq += 1 - check_links(line, ln, stats_links_uniq) - # file: - elif line.startswith('file:'): - stats_files_uniq += 1 - check_files(line, ln, stats_files_uniq) - # image: - elif line.startswith('image:'): - stats_images_uniq += 1 - check_images(line, ln, stats_images_uniq) - # abbr: - elif line.startswith('abbr:'): - stats_abbrs_uniq += 1 - check_abbrs(line, ln, stats_abbrs_uniq) - # brut: - elif line.startswith('brut:'): - stats_bruts_uniq += 1 - check_bruts(line, ln, stats_bruts_uniq) + tag = 'date:' + if line.startswith(tag): + if date: continue + date = line.rsplit(tag)[1].lstrip() + check_date(date, ln) + if not post_err: + if tyto.n == 0: + date = date.rsplit('-') + date = date[2] + '/' + date[1] + '/' + date[0] + date = (date, date_check) + continue - #------------------------------- - # Check valid Mandatory markers - #------------------------------- - if_mandat_marker('title:', title) - if_mandat_marker('about:', about) - if_mandat_marker('author:', author) - if_mandat_marker('tags:', tags) - if_mandat_marker('date:', date) - if date: check_date(date) - - -#===================# -# MANDATORY Markers # -#===================#-------------------------------------------------- -#=====================================# -# Check if marker is used and defined # -#-------------------------------------# -def if_mandat_marker(marker, m_in): - global Post_Err - if not m_in[0]: - msg_log = 'Unused needed marker "%s"'%marker - log.append_f(post_logs, msg_log, 1) - Post_Err = True - elif not m_in[2]: - msg_log = 'Line %s. Undefined marker "%s"'%( - m_in[1], marker - ) - log.append_f(post_logs, msg_log, 1) - Post_Err = True + # Check needed tags # + #-------------------# + # Set needed tags + need_headers = { + 'title:' : title, + 'anout:' : about, + 'tags:' : tags, + 'author:': author, + 'date:' : date + } + + # Check if set needed tags + for tag in need_headers: + if not need_headers[tag]: + tyto.exiting("6", tag, False) + + +### + # Second session for optional tags # + # Read articles lines, till separator # + #-------------------------------------# + for ln, line in enumerate(post_header, 1): + if line.startswith('-----'): break + + + # Set each optional tags + #----------------------- + + # ABBR + #----- + tag = 'abbr:' + if line.startswith(tag): + stat_abbrs += 1 + var_tag = 'abbr_%s'%stat_abbrs + + abbr_short = post_header[ln - 1].rsplit(tag)[1].lstrip() + if not abbr_short: + tyto.exiting("2", "Line %s (SHORT, %s)"%(ln, tag), False) + post_err = True + if not abbr_short.isupper(): + tyto.exiting("3", "Line %s (Upper SHORT, %s)"%(ln, tag), False) + post_err = True + continue + if not isin(r'\b%s\b'%abbr_short, post_bottom): + tyto.exiting("6", abbr_short, False) + post_err = True + + abbr_long = post_header[ln].lstrip() + if abbr_long.startswith(tyto.headers): abbr_long = '' + if not abbr_long: + tyto.exiting("2", "Line %s (Long, %s)"%(ln + 1, tag), False) + post_err = True + + abbr_alt = post_header[ln + 1].lstrip() + if abbr_alt.startswith(tyto.headers): abbr_alt = '' + if not abbr_alt: abbr_alt = abbr_short + + if not post_err: + web_link = '%s'%( + 'abbr', abbr_long, abbr_alt + ) + globals()['abbr_%s'%stat_abbrs] = ( + abbr_short, web_link + ) + + # LINK + #----- + tag = 'link:' + if line.startswith(tag): + stat_links += 1 + var_tag = 'link_%s'%stat_links + + link_name = post_header[ln - 1].rsplit(tag)[1].lstrip() + if not link_name: + tyto.exiting("2", "Line %s (Name, %s)"%(ln, tag), False) + post_err = True + if not isin(r'\b_%s\b'%link_name, post_bottom): + tyto.exiting("6", "_%s"%link_name, False) + post_err = True + + link_url = post_header[ln].lstrip() + if link_url.startswith(tyto.headers): link_url = '' + if not link_url: + tyto.exiting("2", "Line %s (URL, %s)"%(ln + 1, tag), False) + post_err = True + + link_alt = post_header[ln + 1].lstrip() + if link_alt.startswith(tyto.headers): link_alt = '' + if not link_alt: + tyto.exiting("2", "Line %s (Alt-Text, %s)"%(ln + 2, tag), False) + post_err = True + + if not post_err: + web_link = '%s'%( + 'link', link_url, link_alt, link_name + ) + globals()['link_%s'%stat_links] = ( + '_%s'%link_name, web_link + ) + + # IMAGE + #------ + tag = 'image:' + if line.startswith(tag): + stat_images += 1 + var_tag = 'image_%s'%stat_images + + image_name = post_header[ln - 1] + image_name = image_name.rsplit(tag)[1].lstrip().rsplit(' ')[0] + if not image_name: + tyto.exiting("2", "Line %s (Name, %s)"%(ln, tag), False) + post_err = True + if not isin(r'\b_%s%s\b'%(tag, image_name), post_bottom): + tyto.exiting("6", "_%s%s"%(tag, image_name), False) + post_err = True + + image_uri = post_header[ln].lstrip() + if image_uri.startswith(tyto.headers): image_uri = '' + if not image_uri: + tyto.exiting("2", "Line %s (URI, %s)"%(ln + 1, tag), False) + post_err = True + else: + check_file_uri('image', image_uri, ln + 1) + + image_alt = post_header[ln + 1].lstrip() + if image_alt.startswith(tyto.headers): image_alt = '' + if not image_alt: + tyto.exiting("2", "Line %s (Alt-Text, %s)"%(ln + 2, tag), False) + post_err = True + + if not post_err: + globals()['image_%s'%stat_images] = ( + '_%s%s'%(tag, image_name), + web_uri, + image_alt + ) + + # BRUT + #----- + tag = 'brut:' + if line.startswith(tag): + stat_bruts += 1 + var_tag = 'brut_%s'%stat_bruts + + brut_name = post_header[ln - 1] + brut_name = brut_name.rsplit(tag)[1].lstrip().rsplit(' ')[0] + if not brut_name: + tyto.exiting("2", "Line %s (Name, %s)"%(ln, tag), False) + post_err = True + if not isin(r'\b_%s%s\b'%(tag, brut_name), post_bottom): + tyto.exiting("6", "_%s%s"%(tag, brut_name), False) + post_err = True + + brut_uri = post_header[ln].lstrip() + if brut_uri.startswith(tyto.headers): brut_uri = '' + if not brut_uri: + tyto.exiting("2", "Line %s (URI, %s)"%(ln + 1, tag), False) + post_err = True + else: + check_file_uri('file', brut_uri, ln + 1) + + brut_alt = post_header[ln + 1].lstrip() + if brut_alt.startswith(tyto.headers): brut_alt = '' + if not brut_alt: + tyto.exiting("2", "Line %s (Alt-Text, %s)"%(ln + 2, tag), False) + post_err = True + + if not post_err: + globals()['brut_%s'%stat_bruts] = ( + '_%s%s'%(tag, brut_name), + web_uri, + brut_alt + ) + + # FILE + #----- + tag = 'file:' + if line.startswith(tag): + stat_files += 1 + var_tag = 'file_%s'%stat_files + + file_name = post_header[ln - 1].rsplit(tag)[1].lstrip() + if not file_name: + tyto.exiting("2", "Line %s (Name, %s)"%(ln, tag), False) + post_err = True + if not isin(r'\b__%s\b'%file_name, post_bottom): + tyto.exiting("6", "__%s"%file_name, False) + post_err = True + + file_uri = post_header[ln].lstrip() + if file_uri.startswith(tyto.headers): file_uri = '' + if not file_uri: + tyto.exiting("2", "Line %s (URI, %s)"%(ln + 1, tag), False) + post_err = True + else: + check_file_uri('file', file_uri, ln + 1) + + file_alt = post_header[ln + 1].lstrip() + if file_alt.startswith(tyto.headers): file_alt = '' + if not file_alt: + tyto.exiting("2", "Line %s (Alt-Text, %s)"%(ln + 2, tag), False) + post_err = True + + if not post_err: + web_link = '%s'%( + 'file', web_uri, file_alt, file_name + ) + globals()['file_%s'%stat_files] = ( + '__%s'%file_name, web_link + ) + + # Exit if error in optional tags + #------------------------------- + if post_err: + tyto.exiting("7", '', True) + #================================# # Check Date format and validity # # Create False date_check # #--------------------------------# -def check_date(date): - from datetime import datetime - from time import gmtime, strftime - import time - global Post_Err, date_check +def check_date(date, ln): + global post_err, date_check # Check if article date is valid (True) fmt_article = "%Y-%m-%d" try: - bool(datetime.strptime(date[2], fmt_article)) + bool(datetime.strptime(date, fmt_article)) except ValueError: - Post_Err = True - msg_log = 'Line %s. Invalid date: %s'%(date[1],date[2]) - log.append_f(post_logs, msg_log, 1) + post_err = True + tyto.exiting("3", 'Line %s (date, %s)'%(ln, date), False) # Create date_check (epoch) from article's Date + now TIME - if not Post_Err: + if not post_err: fmt_check = '%Y-%m-%d %H:%M:%S' time_check = strftime("%H:%M:%S", gmtime()) - date_check = date[2] + ' ' + time_check - date_check = time.mktime(time.strptime(date_check,fmt_check)) + date_check = date + ' ' + time_check + date_check = time.mktime(time.strptime(date_check, fmt_check)) -#==================# -# OPTIONAL Markers # -#==================#--------------------------------------------------- -#===============================# -# Statistics # -# Return term number in article # -#-------------------------------# -def stats_counter(term): - term = r"%s"%term - return(sum(1 for match in re.finditer(r'\b%s\b'%term, article))) +#===================================# +# Check if file exists # +# Get filetype, filename, i=var nbr # +#-----------------------------------# +def check_file_uri(filetype, filename, ln): + global post_err, err, web_uri -#============================ -# Check optional marker set # -# Called from # -# - check_links # -# - check_files # -# - check_images # -#---------------------------# -def if_option_marker(marker, m_in): - global Post_Err + # Set file uri from filename + # (@ = images/, / = articles/, else = post_dir) + if filename.startswith('@'): + if filetype == 'image': + fileuri = domain_images + filename[1: len(filename)] + elif filetype == 'file': + fileuri = domain_files + filename[1: len(filename)] - if not m_in[1]: - msg_log = 'Line %s. Unused NAME for marker "%s"'%( - m_in[0], marker - ) - log.append_f(post_logs,msg_log,1) - Post_Err = True + elif filename.startswith('/'): + fileuri = domain_articles + filename[1: len(filename)] - if not m_in[2]: - msg_log = 'Line %s. Unused URL for marker "%s"'%( - m_in[0], marker - ) - log.append_f(post_logs,msg_log,1) - Post_Err = True - - if not m_in[3]: - msg_log = 'Line %s. Unused Alt-Text for marker "%s"'%( - m_in[0]+1, marker - ) - log.append_f(post_logs, msg_log, 1) - Post_Err = True - -#=================================# -# Check every marker "link:" # -# For line, from loop header file # -# Also, create Stats # -#---------------------------------# -def check_links(line, ln, stats_links_uniq): - global Post_Err, stats_links_p - - # Create variable array - try: link_name = line.split('link:')[1].lstrip() - except: link_name = '' - try: link_url = headers.rsplit('\n')[ln].lstrip() - except: link_url = '' - try: link_alt = headers.rsplit('\n')[ln+1].lstrip() - except: link_alt = '' - - if not link_name: - msg_log = 'Line %s. Unused NAME for marker "link:"'%ln - log.append_f(post_logs, msg_log, 1) - Post_Err = True - return(1) - - link_nbr = 'link_%s'%stats_links_uniq - # Check 2nd line - check_new_marker(link_url) - if new_marker: link_url = '' - - # Check 3rd line - check_new_marker(link_alt) - if new_marker: link_alt = '' - - link = ( - ln, - link_name, - link_url, - link_alt - ) - - # Set/Check values to check in header - globals()[link_nbr] = link - if_option_marker('link:', globals()[link_nbr]) - - # Check NAME in article - link_page = '_%s'%link_name - if not link_page in article: - msg_log = 'Unused "%s" for marker "link:" in article"'%link_page - log.append_f(post_logs, msg_log, 1) - Post_Err = True - - if Post_Err: return - # Set final marker_N - link = ( - '%s'%link_name, - link_url, - link_alt - ) - globals()[link_nbr] = link - - # Stats: count occurence - stats_links_p = stats_links_p + stats_counter(link_page) - -#=================================# -# Check every marker "file:" # -# For line, from loop header file # -# Also, create Stats # -#---------------------------------# -def check_files(line, ln, stats_files_uniq): - global Post_Err - global stats_files_p - - # Create variable array - try: file_name = line.split('file:')[1].lstrip() - except: file_name = '' - try: file_uri = headers.rsplit('\n')[ln].lstrip() - except: file_uri = '' - try: file_alt = headers.rsplit('\n')[ln+1].lstrip() - except: file_alt = '' - - if not file_name: - msg_log = 'Line %s. Unused NAME for marker "image:"'%ln - log.append_f(post_logs,msg_log,1) - Post_Err = True - return(1) - - file_nbr = 'file_%s'%stats_files_uniq - # Check 2nd line - check_new_marker(file_uri) - if new_marker: file_uri = '' - - # Check 3rd line - check_new_marker(file_alt) - if new_marker: file_alt = '' - - file = ( - ln, - file_name, - file_uri, - file_alt - ) - - # Set/Check values to check in header - globals()[file_nbr] = file - if_option_marker('file:', globals()[file_nbr]) - - # Check NAME in article - file_page = '__%s'%file_name - if not file_page in article: - msg_log = 'Unused "%s" for marker "file:" in article"'%file_page - log.append_f(post_logs, msg_log, 1) - Post_Err = True - - # Check URI value (exists and where) - # In Generic folder /files/ - if file_uri.startswith('@'): - file_uri = file_uri.replace('@','') - gen_file = '%s%s'%(domain.domain_files, file_uri) - if not os.path.exists(gen_file): - msg_log = 'Unused file for marker "file:" in %s'%gen_file - log.append_f(post_logs, msg_log, 1) - Post_Err = True - else: - file_uri = '/files/%s'%file_uri - - # From Root articles (www/ in web) - elif file_uri.startswith('/'): - file_uri = file_uri[1:len(file_uri)] # No need first / to check - usr_file = '%s%s'%(domain.domain_articles, file_uri) - if not os.path.exists(usr_file): - msg_log = 'Unused file for marker "file:" in %s'%usr_file - log.append_f(post_logs, msg_log, 1) - Post_Err = True - else: - file_uri = '/%s'%file_uri - - # Current or custom URI else: - usr_file = '%s%s'%(domain.domain_articles, file_uri) - if not os.path.exists(usr_file): - msg_log = 'Unused file for marker "file:" in %s'%usr_file - log.append_f(post_logs, msg_log, 1) - Post_Err = True + fileuri = tyto.post_dir + filename - if Post_Err: return - #-------------------- - # Set final marker_N - #-------------------- - file = ( - '%s'%file_name, - file_uri, - file_alt - ) - globals()[file_nbr] = file + # Check if file exists + if not os.path.exists(fileuri): + tyto.exiting("1", "Line %s, %s"%(ln, fileuri), False) + post_err = True + return - # Stats: count occurence - stats_files_p = stats_counter(file_page) - -#=================================# -# Check every marker "brut:" # -# For line, from loop header file # -# Also, create Stats # -#---------------------------------# -def check_bruts(line, ln, stats_files_uniq): - global Post_Err - global stats_bruts_p - - # Create variable array - try: brut_name = line.split('brut:')[1].lstrip().rsplit(' ')[0] - except: brut_name = '' - try: brut_uri = headers.rsplit('\n')[ln].lstrip() - except: brut_uri = '' - try: brut_alt = headers.rsplit('\n')[ln+1].lstrip() - except: brut_alt = '' - - if not brut_name: - msg_log = 'Line %s. Unused NAME for marker "brut:"'%ln - log.append_f(post_logs,msg_log,1) - Post_Err = True - return(1) - - brut_nbr = 'brut_%s'%stats_bruts_uniq - # Check 2nd line - check_new_marker(brut_uri) - if new_marker: brut_uri = '' - - # Check 3rd line - check_new_marker(brut_alt) - if new_marker: brut_alt = '' - - brut = ( - ln, - brut_name, - brut_uri, - brut_alt - ) - - # Set/Check values to check in header - globals()[brut_nbr] = brut - if_option_marker('brut:', globals()[brut_nbr]) - - # Check value in article - brut_page = '_brut:%s'%brut_name - if not brut_page in article: - msg_log = 'Unused "%s" for marker "brut:" in article"'%brut_page - log.append_f(post_logs, msg_log, 1) - Post_Err = True - - # Check URI value (exists and where) - # In Generic folder /files/ - if brut_uri.startswith('@'): - brut_uri = brut_uri.replace('@','') - gen_file = '%s%s'%(domain.domain_files, brut_uri) - if not os.path.exists(gen_file): - msg_log = 'Unused file for marker "brut:" in %s'%gen_file - log.append_f(post_logs, msg_log, 1) - Post_Err = True - else: - brut_uri = '/files/%s'%brut_uri - - # From Root articles (www/ in web) - elif brut_uri.startswith('/'): - brut_uri = brut_uri[1:len(brut_uri)] # No need first / to check - usr_file = '%s%s'%(domain.domain_articles, brut_uri) - if not os.path.exists(usr_file): - msg_log = 'Unused file for marker "brut:" in %s'%usr_file - log.append_f(post_logs, msg_log, 1) - Post_Err = True - else: - brut_uri = '/%s'%brut_uri - - # Current or custom URI - else: - usr_file = '%s%s'%(domain.domain_articles, brut_uri) - if not os.path.exists(usr_file): - msg_log = 'Unused file for marker "brut:" in %s'%usr_file - log.append_f(post_logs, msg_log, 1) - Post_Err = True - - if Post_Err: return - #-------------------- - # Set final marker_N - #-------------------- - brut = ( - '%s'%brut_name, - brut_uri, - brut_alt - ) - globals()[brut_nbr] = brut - - # Stats: count occurence - stats_bruts_p = stats_counter(brut_page) - -#=================================# -# Check every marker "image:" # -# For line, from loop header file # -# Also, create Stats # -#---------------------------------# -def check_images(line, ln, stats_images_uniq): - global Post_Err - global stats_images_p - - # Create variable array - - try: image_name = line.split('image:')[1].lstrip().rsplit(' ')[0] - except: image_name = '' - try: image_uri = headers.rsplit('\n')[ln].lstrip() - except: image_uri = '' - try: image_alt = headers.rsplit('\n')[ln+1].lstrip() - except: image_alt = '' - - if not image_name: - msg_log = 'Line %s. Unused NAME for marker "image:"'%ln - log.append_f(post_logs,msg_log,1) - Post_Err = True - return(1) - - image_nbr = 'image_%s'%stats_images_uniq - # Check 2nd line - check_new_marker(image_uri) - if new_marker: image_uri = '' - - # Check 3rd line - check_new_marker(image_alt) - if new_marker: image_alt = '' - - image = ( - ln, - image_name, - image_uri, - image_alt - ) - - # Set/Check values to check in header - globals()[image_nbr] = image - if_option_marker('image:', globals()[image_nbr]) - - # Check value in article - image_page = '_image:%s'%image_name - if not image_page in article: - msg_log = 'Unused "%s" for marker "image:" in article"'%image_page - log.append_f(post_logs, msg_log, 1) - Post_Err = True - - # Check URI value (exists and where) - # Set HTML value in DB - if image_uri.startswith('@'): - image_uri = image_uri.replace('@','') - gen_image = '%s%s'%(domain.domain_images, image_uri) - if not os.path.exists(gen_image): - msg_log = 'Unused file for marker "imagee:" in %s'%gen_image - log.append_f(post_logs, msg_log, 1) - Post_Err = True - else: - image_uri = '/images/%s'%image_uri - - # From Root articles (www/ in web) - elif image_uri.startswith('/'): - image_uri = image_uri[1:len(image_uri)] # No need first / to check - usr_file = '%s%s'%(domain.domain_articles, image_uri) - if not os.path.exists(usr_file): - msg_log = 'Unused file for marker "image:" in %s'%usr_file - log.append_f(post_logs, msg_log, 1) - Post_Err = True - else: - image_uri = '/%s'%image_uri - - # Current or custom URI - else: - usr_file = '%s%s%s'%(domain.domain_articles, post_dir, image_uri) - if not os.path.exists(usr_file): - msg_log = 'Unused file for marker "image:" in %s'%usr_file - log.append_f(post_logs, msg_log, 1) - Post_Err = True - - if Post_Err: return - #-------------------- - # Set final marker_N - #-------------------- - image = ( - '%s'%image_name, - image_uri, - image_alt - ) - globals()[image_nbr] = image - - # Stats: count occurence - stats_images_p = stats_counter(image_page) - -#=================================# -# Check every marker "abbr:" # -# For line, from loop header file # -# Also, create Stats # -#---------------------------------# -def check_abbrs(line, ln, stats_abbrs_uniq): - global Post_Err - global stats_abbrs_p - - # Create variable array - try: abbr_name = line.split('abbr:')[1].lstrip() - except: abbr_name = '' - try: abbr_alt = headers.rsplit('\n')[ln].lstrip() - except: abbr_alt = '' - try: abbr_rep = headers.rsplit('\n')[ln+1].lstrip() - except: abbr_rep = '' - - # Set/Check values to check in header - if not abbr_name: - msg_log = 'Line %s. Unused NAME for marker "abbr:"'%ln - log.append_f(post_logs,msg_log,1) - Post_Err = True - return(1) - elif abbr_name.isupper() is False: - msg_log = 'Line %s. NAME not in CAPITAL for marker "abbr:"'%ln - log.append_f(post_logs,msg_log,1) - Post_Err = True - - # Check 2rd line - check_new_marker(abbr_alt) - if new_marker: abbr_name = '' - # Set/Check values to check in header - if not abbr_alt: - msg_log = 'Line %s. Unused alt-text for marker "abbr:"'%ln + 1 - log.append_f(post_logs,msg_log,1) - Post_Err = True - - # Check 3rd line - check_new_marker(abbr_rep) - if new_marker or not abbr_rep: abbr_rep = abbr_name - - # Check NAME in article - if not abbr_name in article: - msg_log = 'Unused "%s" for marker "abbr:" in article"'%abbr_name - log.append_f(post_logs,msg_log,1) - Post_Err = True - return(1) - - # Statistics for all ABBR in article - stats_abbrs_p = stats_abbrs_p + stats_counter(abbr_name) - - abbr_nbr = 'abbr_%s'%stats_abbrs_uniq - abbr = ( - abbr_name, - abbr_alt, - abbr_rep - ) - globals()[abbr_nbr] = abbr - -#============================# -# Check marker's 3rd line # -# if new marker, or empty # -# for every optional markers # -#----------------------------# -def check_new_marker(line3): - global new_marker - - new_marker = False - - for marker in markers_opt: - if line3.startswith(marker) or line3.startswith('#'): - new_marker = True - -#=================# -# ARTICLE CONTENT # -#=================# -#=====================================# -# Main for all markers to check # -# Loop into header post, till '-----' # -#-------------------------------------# -def check_article_markers(article): - global Post_Err - global stats_p, stats_bcodes, stats_anchors, stats_quotes - global stats_lists, stats_lists_u, stats_lists_o - global stats_titles, stats_comments - - stats_p = stats_pe = stats_qe = stats_le = 0 - stats_lists = stats_lists_u = stats_lists_o = 0 - stats_anchors = stats_quotes = 0 - precode = False # Do not treat line if in precode: (( - - #------------------------ - # Loop lines from article - #------------------------ - for ln, line in enumerate(article.rsplit('\n'), 1): - - # Do not check line if in precode: [[ and ]] - if re.match(markers_reg[2][0], line): precode = True - elif re.match(markers_reg[2][1], line): precode = False - if precode: continue - - #------------------------- - # Markers at begining line - #------------------------- - # Paragraphs: ( and ) - if re.match(markers_reg[0][0], line): stats_p += 1 - elif re.match(markers_reg[0][1], line): stats_pe += 1 - - # Lists: (- and -) ; count items with = and + at begining - elif re.match(markers_reg[3][0], line): stats_lists += 1 - elif re.match(markers_reg[3][1], line): stats_le += 1 - elif line.startswith('='): stats_lists_u +=1 - elif line.startswith('+'): stats_lists_o +=1 - - # Anchors: <: - elif re.match(m_anchor, line): - try : css = line.split(' ')[1] - except: css = '' - if not css: - msg_log = 'Line %s. Unused anchor ID: ">> ID"'%(ln+headers_ln) - log.append_f(post_logs,msg_log,1) - Post_Err = True - else: - stats_anchors += 1 - - # Quotes - elif re.match(markers_reg[1][0], line): stats_quotes += 1 - elif re.match(markers_reg[1][1], line): stats_qe += 1 - - # Check if referenced in header for markers - for marker in '_image:', '_code:', '_brut:': - if re.match(r'^%s'%marker, line): - m_name = line.split(':')[1].split(' ')[0] - marker_h = marker[1:len(marker)] - if not re.findall(r'\b%s\s+%s\b'%(marker_h, m_name), headers): - msg_log = 'Line %s. Unused marker "%s %s" in header'%( - ln+headers_ln, marker_h, m_name - ) - log.append_f(post_logs, msg_log, 1) - Post_Err = True - - #------------------------------ - # Check valid contents markers - #------------------------------ - # Paragraphs - if stats_p != stats_pe: - msg_log = 'Unpaired paragraph markers: %s "(" and %s ")"'%( - stats_p, stats_pe - ) - log.append_f(post_logs,msg_log,1) - Post_Err = True - - # Precodes - if stats_bcodes != stats_ce: - msg_log = 'Unpaired precode markers: %s "[[" and %s "]]"'%( - stats_bcodes, stats_ce - ) - log.append_f(post_logs,msg_log,1) - Post_Err = True - - # lists - if stats_lists != stats_le: - msg_log = 'Unpaired list markers: %s "-(" and %s "-)"'%( - stats_lists, stats_le - ) - log.append_f(post_logs,msg_log,1) - Post_Err = True - - # Quotes - if stats_quotes != stats_qe: - msg_log = 'Unpaired quote markers: %s "((" and %s "))"'%( - stats_quotes, stats_qe - ) - log.append_f(post_logs,msg_log,1) - Post_Err = True - - #------------------------------------ - # Markers in text (strongs, bolds...) - #------------------------------------ - global m_stats - # Markers around words - m_words = ('*_', '_*', - '+_', '_+', - '/_', '_/', - '~_', '_~', - '×_', '_×', - '-_', '_-', - '(_', '_)', - '<_', '_>', - '\\_', '_\\', - '=_', '_=', - '>_', '_<' - ) - # Init words markers statistics - m_stats = ['0', '0', - '0', '0', - '0', '0', - '0', '0', - '0', '0', - '0', '0', - '0', '0', - '0', '0', - '0', '0', - '0', '0', - '0', '0' - ] - # markers Names (Only used for logs) - m_names = ('strong', - 'bold', - 'emphasis', - 'deletion', - 'custom', - 'underline', - 'iCode', - 'iCode', - 'italics', - 'cite', - 'link anchor' - ) - - # Count markers, get, check and set stats. - pos = pos_name = 0 - for marker in m_words: - m_stats[pos] = article.count(marker) - #print(marker, m_stats) - if pos % 2 != 0: - if m_stats[pos-1] != m_stats[pos]: - msg_log = 'Unpaired %s markers %s "%s" and %s "%s"'%( - m_names[pos_name], - m_stats[pos-1], m_words[pos-1], - m_stats[pos], m_words[pos] - ) - log.append_f(post_logs,msg_log,1) - Post_Err = True - pos_name += 1 - pos += 1 - # Add specific alternative iCode '<_','_>' to legacy iCode stats - m_stats[12] = m_stats[12] + m_stats[14] - -#======================================================# -# Thses markers needs ref line, in case invalid # -# As bCodes needs convertion, they must be check first # -# Done after post_to_strings # -# Also count stats: bCodes, titles, comments # -#------------------------------------------------------# -def check_article_titles(article): - global Post_Err - global stats_bcodes, stats_ce - global stats_comments, stats_titles - - stats_bcodes = stats_ce = 0 - stats_comments = stats_titles = 0 - precode = False - - #------------------------ - # Loop lines from article - #------------------------ - for ln, line in enumerate(article, 1): - - # Do not check line if in precode: [[ and ]] - if re.match(markers_reg[2][0], line): - precode = True - stats_bcodes += 1 - elif re.match(markers_reg[2][1], line): - precode = False - stats_ce += 1 - if precode: continue - - # Titles - if line.startswith(r'#'): - Title_Err = False - title = line.split(' ', 1) - ht = line[1] - - # Check title marker #[1-6] - if ht == ' ' or ht == '#': - stats_comments += 1 - continue - - # Title number not in range - elif ht.isdigit(): - if not int(ht) in range(1,7): - msg_log = 'Line %s. Mismatch title number "%s" (1-6)'%( - ln + headers_ln, ht) - log.append_f(post_logs,msg_log,1) - Post_Err = True - continue - - # Not a digit in marker title - else: - msg_log = 'Line %s. Mismatch title number "%s" (1-6)'%( - ln + headers_ln, ht) - log.append_f(post_logs,msg_log,1) - Post_Err = True - continue - - # Check description's title - try: - title[1] - if not title[1] or title[1] == ' ': Title_Err = True - else : stats_titles += 1 - except: - Title_Err = True - - if Title_Err: - msg_log = 'Line %s. Unused title description "%s ??"'%( - ln + headers_ln, title[0] - ) - log.append_f(post_logs,msg_log,1) - Post_Err = True + web_uri = '/' + fileuri.replace(domain_articles, "") #===========================# -# Check links anchors # -# (if '>> ID' is registred) # +# Check tags in post_bottom # #---------------------------# -def check_links_anchors(article): - global Post_Err - - anchors_link = re.findall(r'\>_(.*?)_\<', article) - for anchor in anchors_link: - anchor_id = anchor.rsplit(':',1)[0] - if not re.search(r'\>\> %s'%anchor_id, article): - msg_log = 'Unused anchor ID ">> %s" from link "%s"'%( - anchor_id, anchor - ) - log.append_f(post_logs,msg_log,1) - Post_Err = True - -#====================================# -# Check inside list for only + and = # -# Multilines for one marker list # -# MUST have at leat one space (\s) # -#------------------------------------# -def check_lists_contents(article): - global Post_Err +def check_content(post_bottom): + global post_err + global article_bottom + # Check tags for words (strongs, italics...) + # Set stats for each one + #------------------------------------------- + for tag in tyto.words_tags: + c_opened = c_closed = 0 + + if tag[5] == 'w': + c_opened = article_bottom.count(tag[0]) + c_closed = article_bottom.count(tag[1]) + # Useless tag now, replace + article_bottom = article_bottom.replace(tag[0], '') + article_bottom = article_bottom.replace(tag[1], '') + elif tag[5] == 't': + for line in post_bottom: + if line.startswith(tag[0]): c_opened += 1 + if line.startswith(tag[1]): c_closed += 1 + + if c_opened != c_closed: + tyto.exiting("8", '%s: %s %s'%(tag[4], tag[0], tag[1]), False) + post_err = True + return # Useless and could code errors to check nexts + else: + globals()['post_%s'%tag[4]] = int(c_opened) + + + # Check if anchor has target + # Count anchors target + #--------------------------- + global stat_ancs + stat_ancs = 0 + + for line in post_bottom: + if line.startswith(tyto.single_tags[1][0]): stat_ancs += 1 + if tyto.words_tags[0][0] and tyto.words_tags[0][1] in line: + anchors = re.findall(r">_(.*?)_<", line) + for anchor in anchors: + css_anchor = anchor.rsplit(':')[0] + tag = '%s %s'%(tyto.single_tags[1][0], css_anchor) + if not tag in post_bottom: + tyto.exiting("6", 'anchor, %s'%tag, False) + post_err = True + + + # Check if content list is valid + #------------------------------- inlist = False - - for line in article: + markers_lists = '%s, %s, or space'%( + tyto.markers_lists[0], + tyto.markers_lists[1] + ) + for ln, line in enumerate(article.rsplit('\n'), 1): + if line.startswith('-('): inlist = True;continue + elif line.startswith('-)'): inlist = False + if not inlist: continue - if re.match(markers_reg[3][0], line): - inlist = True - continue - elif re.match(markers_reg[3][1], line): - inlist = False - - if inlist and not re.match(r'^\+|^\=|\s', line): - msg_log = 'Content list not "+" or "=": %s'%line - log.append_f(post_logs, msg_log, 1) - Post_Err = True - -#====================================# -# Create Database file for this Post # -#------------------------------------# -def create_DB(post_db): - # Create NEW database for article - file = open(post_db, "w") - file.write('') - file.close() + if not line[0] in tyto.markers_lists: + tyto.exiting("3", 'line %s must start with %s'%( + ln, markers_lists + ), False) + post_err = True + - # time of check at creating DB - global time_chk - time_chk = log.nowdate() +#===============================================# +# Create new article's database at each check ! # +#-----------------------------------------------# +def create_database(): + web_uri = tyto.web_uri[1: len(tyto.web_uri)] + if tyto.web_uri.endswith('index.html'): tyto.web_uri = '/' + database = '# Post Configuration for Tyto\n' + \ + 'post_id = "%s"\n'%tyto.uri_id + \ + 'root_uri = "%s"\n'%tyto.uri_root + \ + 'wip_uri = "%s%s"\n'%(srv_wip, web_uri) + \ + 'www_uri = "%s%s"\n'%(srv_www, web_uri) + \ + 'http_uri = "%s"\n'%tyto.web_uri + \ + 'hash_wip = ""\n' + \ + 'date_www = ""\n' + \ + 'hash_www = ""\n' + \ + 'date_chk = "%s"\n'%tyto.nowdate() + \ + 'hash_chk = "%s"\n'%tyto.hash_post + \ + 'date_wip = ""\n' + \ + '\n# Post configuration from needed tags\n' + \ + 'title = "%s"\n'%title + \ + 'about = "%s"\n'%about + \ + 'author = "%s"\n'%author + \ + 'tags = "%s"\n'%tags + \ + 'date = %s\n'%str(date) + \ + '\n# Post configuration from optional tags' + + if stat_abbrs > 0: + for i in range(1, stat_abbrs + 1): + database = '%sabbr_%s = %s'%( + database, i, globals()['abbr_%s'%i] + ) - # Specific statistics for links (add all) - stats_links = stats_links_p + stats_files_p + stats_images_p + if stat_links > 0: + for i in range(1, stat_links + 1): + database = '%s\nlink_%s = %s'%( + database, i, globals()['link_%s'%i] + ) - # log - msg_log = 'Create Database: %s'%post_db - log.append_f(post_logs, msg_log, 0) + if stat_images > 0: + for i in range(1, stat_images + 1): + database = '%s\nimage_%s = %s'%( + database, i, globals()['image_%s'%i] + ) - # Main Post Conf - lines_conf = ( - '# Domain', - 'post_domain = "%s"'%domain.domain_name, - '\n# Metas & URIs', - 'post_file = "%s"'%post_uri, - 'post_ID = "%s"'%curr_post_ID, - 'post_db = "%s"'%post_db, - 'post_tmp = "%s"'%post_tmp, - 'post_dir = "%s"'%post_dir, - 'post_url = "%s"'%post_url, - 'post_srv = "%s"'%post_srv, - 'web_uri = "%s"'%weburi, - '\n# Article Status', - 'post_chk = (\'%s\', \'%s\')'%(hash_chk,time_chk), - 'post_wip = (\'%s\', \'%s\')'%(hash_wip,time_wip), - 'post_www = (\'%s\', \'%s\')'%(hash_www,time_www), - '\n# Mandatory Headers', - 'post_title = "%s"'%title[2], - 'post_about = "%s"'%about[2], - 'post_tags = "%s"'%tags[2], - 'post_date = "%s"'%date[2], - 'post_check = "%s" # └+CheckTime'%date_check, - 'post_author = "%s"'%author[2], - '\n# Optional Headers' - ) - for line_conf in lines_conf: - domain.append_f(post_db, line_conf) + if stat_files > 0: + for i in range(1, stat_files + 1): + database = '%s\nfile_%s = %s'%( + database, i, globals()['file_%s'%i] + ) - # Optional headers to Post conf - # Add every "link:" array found to DB, one per line - if stats_links_uniq > 0: - for n in range(1,stats_links_uniq+1): - m = 'link_%s'%n - domain.append_f(post_db,'%s = %s'%(m,globals()[m])) + if stat_bruts > 0: + for i in range(1, stat_bruts + 1): + database = '%s\nbrut_%s = %s'%( + database, i, globals()['brut_%s'%i] + ) - # Add every "file:" array found to DB, one per line - if stats_files_uniq > 0: - for n in range(1, stats_files_uniq+1): - m = 'file_%s'%n - domain.append_f(post_db, '%s = %s'%(m,globals()[m])) - - # Add every "image:" array found to DB, one per line - if stats_images_uniq > 0: - for n in range(1, stats_images_uniq+1): - m = 'image_%s'%n - domain.append_f(post_db, '%s = %s'%(m,globals()[m])) - - # Add every "image:" array found to DB, one per line - if stats_bruts_uniq > 0: - for n in range(1, stats_bruts_uniq+1): - m = 'brut_%s'%n - domain.append_f(post_db, '%s = %s'%(m,globals()[m])) - - # Add every "abbr:" array found to DB, one per line - if stats_abbrs_uniq > 0: - for n in range(1, stats_abbrs_uniq+1): - m = 'abbr_%s'%n - domain.append_f(post_db, '%s = %s'%(m,globals()[m])) - - # Statistics Post conf - lines_conf = '' - lines_conf = ( - '\n# Statistics (Uniq)', - 'links_u = %d'%stats_links_uniq, - 'files_u = %d'%stats_files_uniq, - 'images_u = %d'%stats_images_uniq, - 'bruts_u = %d'%stats_bruts_uniq, - 'abbrs_u = %d'%stats_abbrs_uniq, - '\n# Statistics (Wordings)', - 'strongs = %d'%m_stats[0], - 'bolds = %d'%m_stats[2], - 'emphasis = %d'%m_stats[4], - 'italics = %d'%m_stats[16], - 'cites = %d'%m_stats[18], - 'deletions = %d'%m_stats[6], - 'customs = %d'%m_stats[8], - 'underlines = %d'%m_stats[10], - 'icodes = %d'%m_stats[12], - '\n# Statistics (Links)', - 'links = %d'%stats_links, - 'links_p = %d'%stats_links_p, - 'files_p = %d'%stats_files_p, - 'images_p = %d'%stats_images_p, - 'bruts_p = %d'%stats_bruts_p, - 'abbrs_p = %d'%stats_abbrs_p, - '\n# Statistics (Templates)', - 'titles = %d'%stats_titles, - 'anchors = %d'%stats_anchors, - 'paragraphs = %d'%stats_p, - 'quotes = %d'%stats_quotes, - 'lists = %d'%stats_lists, - 'lists_u = %d'%stats_lists_u, - 'lists_o = %d'%stats_lists_o, - 'precodes = %d'%stats_bcodes, - 'comments = %d'%stats_comments - ) - for line_conf in lines_conf: - domain.append_f(post_db, line_conf) + db_stats = '\n# Statistics from optional tags\n' + \ + 'uniq_anchors = %s\n'%(int(stat_ancs)) + \ + 'uniq_abbrs = %s\n'%(int(stat_abbrs)) + \ + 'uniq_links = %s\n'%(int(stat_links)) + \ + 'uniq_images = %s\n'%(int(stat_images)) + \ + 'uniq_files = %s\n'%(int(stat_files)) + \ + 'uniq_bruts = %s\n'%(int(stat_bruts)) + \ + '\n# Statistics from post content\n' + \ + 'stat_tags = %s\n'%(int(post_tags)) + \ + 'stat_words = %s\n'%(int(post_words)) + \ + 'stat_titles = %s\n'%(int(tyto.nbr_titles)) + \ + 'stat_paragraphs = %s\n'%(int(post_paragraphs)) + \ + 'stat_anchors = %s\n'%(int(post_anchors)) + \ + 'stat_strongs = %s\n'%(int(post_strongs)) + \ + 'stat_bolds = %s\n'%(int(post_bolds)) + \ + 'stat_emphasis = %s\n'%(int(post_emphasis)) + \ + 'stat_italics = %s\n'%(int(post_italics)) + \ + 'stat_dels = %s\n'%(int(post_dels)) + \ + 'stat_underlines = %s\n'%(int(post_underlines)) + \ + 'stat_cites = %s\n'%(int(post_cites)) + \ + 'stat_customs = %s\n'%(int(post_customs)) + \ + 'stat_codes = %s\n'%(int(tyto.nbr_codes)) + \ + 'stat_bcodes = %s\n'%(int(tyto.nbr_bcodes)) + \ + 'stat_quotes = %s\n'%(int(tyto.nbr_quotes)) + \ + 'stat_lists = %s\n'%(int(post_lists)) + + database = '%s\n%s'%(database, db_stats) + tyto.set_file(tyto.post_db, 'new', database) + tyto.exiting("21", '', True) diff --git a/src/var/lib/tyto/program/domain.py b/src/var/lib/tyto/program/domain.py index 6a65828..723dee6 100644 --- a/src/var/lib/tyto/program/domain.py +++ b/src/var/lib/tyto/program/domain.py @@ -1,9 +1,9 @@ #!/usr/bin/env python3 # Name: Tyto - Littérateur # Type: Global functions for domain -# Description: Add new domain, check domain dir... +# Description: Create/edit a domain # file: domain.py -# Folder: /var/lib/tyto/scripts/ +# Folder: /var/lib/tyto/program/ # By echolib (XMPP: im@echolib.re) # License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 @@ -17,139 +17,44 @@ #********************************************************************** -#======# -# MAIN # -#======# -import sys, os, subprocess, datetime -import check, log - -# Get user dir -home_dir = os.path.expanduser('~') - -# In Tyto DB dir -tyto_db = '%s/.local/tyto'%home_dir -tyto_domains = '%sdomains.conf'%tyto_db - -# In Tyto log dir -tyto_logs_dir = '/var/log/tyto/' -tyto_logs = '%styto.log'%tyto_logs_dir - -# Current dir -curr_dir = domain_articles = domain_logs = os.getcwd() - -# set domain configuration file from current directory -conf_domain = '%s/tyto_domain.conf'%curr_dir - -# Activation domain -domain_active = domain_conf = False - -# Set needed directories - -# Create Tyto logs -if not os.path.exists(tyto_logs): - file = open(tyto_logs, "w") - file.write('') - file.close() - msg_log = 'Log > Create logs file for Tyto in %s\n'%tyto_logs - log.append_f(tyto_logs, msg_log, 0) - -# Get database domains -# If not exists, create the file conf -# Will receive all domain registred -try: - exec(open(tyto_domains).read()) -except: - domains_file = open(tyto_domains, 'w') - domains_file.write("# Tyto's file with all activated domains\n") - domains_file.close() - -domains_db = open(tyto_domains,'r').read() - -# Get user domain configuration file -# If exists, set to True, and exec -try: # os.path.exists(conf_domain): - exec(open(conf_domain).read()) - datas_domain = open(conf_domain, "r").read() - if domain_active: print(':D Activated domain: "%s"'%domain_name) - else : print(':/ Not activated domain in',conf_domain) -except: - print(':< Unused domain file:', conf_domain) - -#=======# -# Tools # -#=======#-------------------------------------------------------------- -#===========================# -# Append new line to a file # -#---------------------------# -def append_f(f, line_val): - file = open(f, "a") - file.write('%s\n'%line_val) - file.close() - -#======================================# -# Just a generic exit # -# out defines message, not exit status # -# for process form: " -# - rename temp domain conf to legacy # -#--------------------------------------# -def exiting(process, out, msg): - msgs = [ - ':D All done !', - ':/ Maybe next time...', - '%s'%msg - ] - - if process == 'form': - os.rename(temp_domain, conf_domain) - - print(msgs[out]) - sys.exit(0) - +import os, locale +import tyto #==========================# # Manage Argument 'domain' # -#==========================#------------------------------------------- -def manage_domain(Domain, Opt): - if not Opt: - try: print('\n',datas_domain) # No option: get domain and print it - except: sys.exit(0) - - elif Opt == 'New': - try: set_domain = Domain # Domain NAME is defined in CLI - except: set_domain = '' - - add_domain(set_domain) +#--------------------------# +def manage_domain(target, option): + if option == 'Edit': + if tyto.domain_exists: + print(":D Edit domain configuration file:", tyto.domain_conf) + tyto.edit_file(tyto.domain_conf) - elif Opt == 'Edit': - if domain_conf: - print(':> Editing',domain_conf) - old_conf_ID = check.get_filesum(domain_conf, True) - edit_domain = subprocess.run(['/usr/bin/nano', - '--linenumbers', - domain_conf]) - - # Compare before and after domain conf file - new_conf_ID = check.get_filesum(domain_conf,True) - if not old_conf_ID == new_conf_ID: - exiting('root', 2, ':D Updated domain configuration file.') - else: - exiting('root', 2, ':D Unchanged domain configuration file.') + if option == 'New': + if not tyto.domain_exists: + create_domain(target) else: - sys.exit(0) + print(':) A domain exists in this directory') + ask = input('-> Edit it with the form ? ') + if ask in ['y', 'Y']: create_domain(target) + else: tyto.exiting("255", '', True) + + +#=====================# +# Check target if URL # +#---------------------# +def isurl(target): + global url + if target.startswith('http'): + url = target + else: + tyto.exiting("2", target, True) + +#=====================# +# Create a new domain # +#---------------------# +def create_domain(target): + if target: isurl(target) -#===================================# -# Main fonction to add a new domain # -# Check first, if it already exists # -# Domain not activated: # -# - Show registred values in form # -#-----------------------------------#---------------------------------- -def add_domain(set_domain): - # Exit if a domain already exists - if domain_active: sys.exit(0) - - global temp_domain - temp_domain = '%s/tyto_domain.tmp'%curr_dir - print('\n' ' ┌──────────────────────────────────────────────┐\n' ' │ Configure a new domain for current directory │\n' @@ -160,406 +65,349 @@ def add_domain(set_domain): ' ├──────────────────────────────────────────────┘' ) - # Create new temp conf file - # Used to prepare values, leaving legacy conf file - file = open(temp_domain, "w") - file.write('# Tyto Configuration Domain\n') - file.close() - # Domain is or not given in CLI. - # Start form - if set_domain: - domain_input_confirn(set_domain) - domain_form() - else: - domain_input() - domain_form() - - # End of form. - # Show resume's domain configuration from temp conf file - print('\n' - ' ┌─────────────────────────────┐\n' - ' │ Please check domain datas...│\n' - ' ├─────────────────────────────┘' - ) - with open(temp_domain, "r") as file: - post_temp = file.read() - for line in post_temp.split('\n'): - print(' │ %s'%line) - file.close() - - # Ask to confirm to write activation domain - print(' ├─────────────────────────────') - confirm = input(' └ Activate domain configuration ? ') - if confirm in ['y', 'Y']: create_domain() - else : exiting('form', 1, '') - -#==============# -# Get protocol # -#--------------# -def get_protocol(set_domain): - global domain_protocol - domain_protocol = '' + # Get complete URL from target or ask + #------------------------------------ + try: domain_url = tyto.domain_url + except: domain_url = '' - # check protocol https, http - if set_domain.startswith('https://'): domain_protocol = 'https://' - elif set_domain.startswith('http://') : domain_protocol = 'http://' + ask = '' + ask = input(' ├ [HTTP...] URL to website ? ("%s") '%domain_url) + if ask: + isurl(ask) + domain_url = url + elif not domain_url: + tyto.exiting("255", '', True) - if domain_protocol: - set_domain = set_domain.replace(domain_protocol,"") - else: - confirm = input(' ├ Use "https" ? ') - if confirm in ['y', 'Y']: domain_protocol = 'https://' - else : domain_protocol = 'http://' - -#==============================# -# If domain name is set in CLI # -# Confirm process # -#------------------------------# -def domain_input_confirn(set_domain): - global domain_name + domain_short = domain_url.rsplit('://')[1] - get_protocol(set_domain) - - confirm = input(' ├ Add Domain (%s) here ? '%set_domain) - if confirm in ['y', 'Y']: - # Check if domain already registred - isdomain = set_domain.replace('.','_') - if isdomain in domains_db: - dom_folder = globals().get(isdomain,False) - if dom_folder and not dom_folder == curr_dir: - exiting('root', 2, '\n:/ Domain exists in %s'%dom_folder) - domain_name = set_domain - else: - exiting('root', 1, '') - -#=====================# -# Add new domain_name # -#---------------------# -def domain_input(): - global domain_name, domain_protocol - set_domain = input(' ├ Enter Domain Name: ') - - if not set_domain: exiting('root', 1, '') - else : domain_name = set_domain - - domain_protocol = '' - get_protocol(set_domain) - - -#====================# -# Domain FORM # -# domain_name is set # -# Configure domain # -#--------------------# -def domain_form(): - - # First settings to put in temp_domain config file - domain_db = '%s/%s/articles/'%(tyto_db,domain_name) - domain_logs = '%s%s/'%(tyto_logs_dir,domain_name) - domain_articles = '%s/articles/'%curr_dir - domain_images = '%simages/'%domain_articles - domain_files = '%sfiles/'%domain_articles - domain_url = '%s%s'%(domain_protocol, domain_name) - - append_f(temp_domain,'domain_conf = "%s"'%conf_domain) - append_f(temp_domain,'domain_db = "%s"'%domain_db) - append_f(temp_domain,'domain_logs = "%s"'%domain_logs) - append_f(temp_domain,'\n# Article directories') - append_f(temp_domain,'domain_dir = "%s"'%curr_dir) - append_f(temp_domain,'domain_articles = "%s"'%domain_articles) - append_f(temp_domain,'domain_files = "%s"'%domain_files) - append_f(temp_domain,'domain_images = "%s"'%domain_images) - - # ----------------------- # - # Starting Form # - # Some values are defaut # - # Values can be registred # - # from legacy conf file # - # ----------------------- # - - # Local server Directory - # ---------------------- - global srv, srv_wip, srv_wip_files, srv_wip_images, srv_wip_template - global srv_www, srv_www_files, srv_www_images, srv_wip_template - - try: srv - except: srv = '/var/www' - - set_srv = input(' ├ Local server directory (%s) ? '%srv) - if not set_srv and not srv: - exiting('form',1,'') - if set_srv and set_srv[-1] == '/': - srv = set_srv[:-1] - - if not os.path.exists(srv): - exiting('form',2,'\n:< Unsed directory "%s"'%srv) - - # Settings for server - srv_domain = '%s/%s/'%(srv,domain_name) - srv_wip = '%s/%s/wip/'%(srv,domain_name) - srv_wip_files = '%s/%s/wip/files/'%(srv,domain_name) - srv_wip_images = '%s/%s/wip/images/'%(srv,domain_name) - srv_wip_template = '%s/%s/wip/template/'%(srv,domain_name) - srv_www = '%s/%s/www/'%(srv,domain_name) - srv_www_files = '%s/%s/www/files/'%(srv,domain_name) - srv_www_images = '%s/%s/www/images/'%(srv,domain_name) - srv_www_template = '%s/%s/www/template/'%(srv,domain_name) - - # Write settings to temp_omain - append_f(temp_domain,'\n# Server directories') - append_f(temp_domain,'srv = "%s"'%srv) - append_f(temp_domain,'srv_domain = "%s"'%srv_domain) - append_f(temp_domain,'srv_wip = "%s"'%srv_wip) - append_f(temp_domain,'srv_wip_files = "%s"'%srv_wip_files) - append_f(temp_domain,'srv_wip_images = "%s"'%srv_wip_images) - append_f(temp_domain,'srv_wip_template = "%s"'%srv_wip_template) - append_f(temp_domain,'srv_www = "%s"'%srv_www) - append_f(temp_domain,'srv_www_files = "%s"'%srv_www_files) - append_f(temp_domain,'srv_www_images = "%s"'%srv_www_images) - append_f(temp_domain,'srv_www_template = "%s"'%srv_www_template) - - # Domain Title for website - # ------------------------ - global domain_title + # Prefix wip + #----------- try: - domain_title - show_title = domain_title[:14] + '...' + try_wipurl = target.rsplit('.') + try_wipurl = 'https://www-wip.%s.%s'%(try_wipurl[1], try_wipurl[2]) except: - domain_title = show_title = '' - - set_title = input(' ├ Domain Title (%s) ? '%show_title) - if not set_title and not domain_title: - exiting('form',1,'') - if set_title: - domain_title = set_title - if '"' in domain_title: - domain_title = domain_title.replace('"','\\"') + try_wipurl = 'https://www-wip.%s'%target - append_f(temp_domain,'\n# Domain datas for web pages') - append_f(temp_domain,'domain_name = "%s"'%domain_name) - append_f(temp_domain,'domain_protocol = "%s"'%domain_protocol) - append_f(temp_domain,'domain_url = "%s"'%domain_url) - append_f(temp_domain,'domain_title = "%s"'%domain_title) + try: domain_wipurl = tyto.domain_wipurl + except: domain_wipurl = try_wipurl - # Separator Pages Titles (default '-') - # ------------------------------------ - global sep_titles - try: sep_titles - except: sep_titles = '-' + ask = '' + ask = input(' ├ URL to wip ? ("%s") '%domain_wipurl) + if ask: + isurl(ask) + domain_wipurl = ask - set_sep = input(' ├ Website pages separator (%s) ? '%sep_titles) - if set_sep: - if len(set_sep) > 2: - exiting('form', 2, '\n:< Seperator is 2 characters max') - sep_titles = set_sep + + db_dir = '%s/.local/tyto/'%tyto.home_dir + conf_domain = 'domain_conf = "%s"\n'%tyto.domain_conf + \ + 'domain_db = "%s/%s/articles/"\n'%(db_dir, target) + \ + 'domain_dir = "%s/"\n'%tyto.in_dir + \ + 'domain_articles = "%s/articles/"\n'%tyto.in_dir + \ + 'domain_files = "%s/articles/files/"\n'%tyto.in_dir + \ + 'domain_images = "%s/articles/images/"\n'%tyto.in_dir + \ + '\ndomain_short = "%s"\n'%domain_short + \ + 'domain_url = "%s"\n'%domain_url + \ + 'domain_wipurl = "%s"\n'%domain_wipurl + + tyto.set_file(tyto.domain_conf, True, conf_domain) + - append_f(temp_domain,'sep_titles = "%s"'%sep_titles) - - # Domain description - # ------------------ - global domain_about - try: - domain_about - show_about = domain_about[:14] + '...' - except: - domain_about = show_about = '' - - set_about = input(' ├ Domain description (%s) ? '%show_about) - if not set_about and not domain_about: exiting('form',1,'') - if set_about: domain_about = set_about - if '"' in domain_about: domain_about = domain_about.replace('"','\\"') + # Get title domain + #----------------- + try: domain_title = tyto.domain_title + except: domain_title = '' - append_f(temp_domain,'domain_about = "%s"'%domain_about) + ask = '' + ask = input(' ├ Domain title ? ("%s") '%domain_title) + if ask: domain_title = ask + elif not domain_title: tyto.exit("255") + if '"' in domain_title: domain_title=domain_title.replace('"', '\\"') - # Lang for HTML Pages - # ------------------- - global domain_lang - try: - domain_lang - except: - # Get default system language (2/3 chars for HTML) - import locale - domain_lang = locale.getdefaultlocale()[0].split('_')[0] + tyto.set_file(tyto.domain_conf, False, + 'domain_title = "%s"'%domain_title) + + + # Get Description domain + #----------------------- + try: domain_about = tyto.domain_about + except: domain_about = '' - set_lang = input(' ├ Website HTML lang (%s) ? '%domain_lang) - if set_lang: - if len(set_lang) > 3: - exiting('form',2,'\n:< HTML Lang is 3 characters max') - domain_lang = set_lang + ask = '' + ask = input(' ├ Domain Description ? ("%s") '%domain_about) + if ask: domain_about = ask + elif not domain_about: tyto.exit("255") + if '"' in domain_about: domain_about=domain_about.replace('"', '\\"') - append_f(temp_domain,'domain_lang = "%s"'%domain_lang) + tyto.set_file(tyto.domain_conf, False, + 'domain_about = "%s"'%domain_about) - # Domain CSS (prefix class). alphanum only - # ---------------------------------------- - global domain_css - try: - domain_css - except: - domain_css = 'tyto' + + # Get Lang domain + #---------------- + try: domain_lang = tyto.domain_lang + except: domain_lang = locale.getdefaultlocale()[0].split('_')[0] - set_css = input(' ├ Generic CSS class (%s) ? '%domain_css) - if set_css: - domain_css = set_css - if not domain_css.isalnum(): - css_alnum = ''.join(c for c in domain_css if c.isalnum()) - domain_css = css_alnum - - append_f(temp_domain,'domain_css = "%s"'%domain_css) - - # Domain mail - # ----------- - global domain_mail - try: - domain_mail - show_mail = domain_mail[:14] + '...' - except: - domain_mail = show_mail = '' - - set_mail = input(' ├ Contact admin mail (%s) ? '%show_mail) - if not set_mail and not domain_mail: exiting('form', 1, '') - if set_mail: - if not '@' and not '.' in set_mail: - exiting('form', 2, '\n:< Invalid mail format (x@x.x)') - domain_mail = set_mail - elif not domain_mail: - exiting('form', 2, '\n:< Mail is required.') - - append_f(temp_domain,'domain_mail = "%s"'%domain_mail) - - # Domain Tags - # ----------- - global domain_tags - try: - domain_tags - show_tags = domain_tags[:14] + '...' - except: - domain_tags = show_tags = '' - - set_tags = input(' ├ Domain Tags [x,y] (%s) ? '%show_tags) - if not set_tags and not domain_tags: exiting('form', 1, '') - if set_tags: domain_tags = set_tags - - append_f(temp_domain,'domain_tags = "%s"'%domain_tags) - - # Webpages Copyright - # ------------------ - global domain_license - try: - domain_license - show_license = domain_license[:14] + '...' - except: - domain_license = show_license = 'CC BY-NC-SA' + ask = '' + ask = input(' ├ [2 characters] Website language ? ("%s") '%domain_lang) + if ask: + if len(ask) == 2: domain_lang = ask + else: tyto.exiting("3", ask, True) + elif not domain_lang: tyto.exiting("255", '', True) - set_license = input(' ├ Website copyright (%s) ? '%show_license) - if set_license: domain_license = set_license + tyto.set_file(tyto.domain_conf, False, + 'domain_lang = "%s"'%domain_lang) + + + # Get mail domain + #---------------- + try: domain_mail = tyto.domain_mail + except: domain_mail = '' + + ask = '' + ask = input(' ├ Webmaster\'s mail ? ("%s") '%domain_mail) + if ask: + if not "@" in ask and not "." in ask: tyto.exiting("3", ask, True) + domain_mail = ask + elif not domain_mail: tyto.exiting("255", '', True) + + tyto.set_file(tyto.domain_conf, False, + 'domain_mail = "%s"'%domain_mail) + + + # Get Tags domain + #---------------- + try: domain_tags = tyto.domain_tags + except: domain_tags = '' + + ask = '' + ask = input(' ├ [comma separated] Domain tags ? ("%s") '%domain_tags) + if ask: domain_tags = ask + elif not domain_tags: tyto.exiting("255", '', True) + + tyto.set_file(tyto.domain_conf, False, + 'domain_tags = "%s"'%domain_tags) + + + # Get License domain + #------------------- + try: domain_license = tyto.domain_license + except: domain_license = 'CC BY-NC-SA' + + ask = '' + ask = input(' ├ Domain License ? ("%s") '%domain_license) + if ask: domain_license = ask + elif not domain_license: tyto.exiting("255", '', True) if '"' in domain_license: - domain_license = domain_license.replace('"','\\"') - - append_f(temp_domain,'domain_license = "%s"'%domain_license) - - # Copyright URL - #-------------- - global domain_lic_url + domain_license=domain_license.replace('"', '\\"') - try: - domain_lic_url - show_license = domain_lic_url[:14] + '...' - except: - domain_lic_url = '' + tyto.set_file(tyto.domain_conf, False, + 'domain_license = "%s"'%domain_license) - set_lic_url = input(' ├ Copyright URL (%s) ? '%show_license) - if not set_lic_url and not domain_lic_url: - exiting('form', 2, '\n:< Copyright URL is required.') - elif set_lic_url: - set_lic_url: domain_lic_url = set_lic_url - append_f(temp_domain,'domain_lic_url = "%s"'%domain_lic_url) + # Get License URL + #---------------- + try: domain_licurl = tyto.domain_licurl + except: domain_licurl = '' + + ask = '' + ask = input(' ├ Optional. License URL ? ("%s") '%domain_licurl) + if ask: + if not ask.startswith('http'): tyto.exiting("3", ask, True) + domain_licurl = ask + + tyto.set_file(tyto.domain_conf, False, + 'domain_licurl = "%s"'%domain_licurl) + + + # CSS Prefix + #----------- + try: domain_css = tyto.domain_css + except: domain_css = 'tyto' + + ask = '' + ask = input(' ├ [alnum] Prefix CSS ? ("%s") '%domain_css) + if ask: + if not ask.isalnum(): tyto.exiting("3", ask, True) + domain_css = ask.lower() + + tyto.set_file(tyto.domain_conf, False, + 'domain_css = "%s"'%domain_css) + + + # Titles webpage separator + #------------------------- + try: domain_sep = tyto.domain_sep + except: domain_sep = "-" + + ask = '' + ask = input(' ├ [1 character] Pages titles separator ? ("%s") '%domain_sep) + if ask: + if not len(ask) == 1: tyto.exiting("3", ask, True) + domain_sep = ask + + tyto.set_file(tyto.domain_conf, False, + 'domain_sep = "%s"'%domain_sep) + # Sidebar Title - # ------------- - global sidebar_title - try: - sidebar_title - show_st = sidebar_title[:14] + '...' - except: - if 'fr' in domain_lang: sidebar_title = show_st = "À l'affiche !" - else : sidebar_title = show_st = "Featured !" - - set_st = input(' ├ Sidebar title (%s) ? '%show_st) - if set_st: sidebar_title = set_st + #-------------- + try: sidebar_title = tyto.sidebar_title + except: sidebar_title = tyto.trans[0][tyto.n] + + ask = '' + ask = input(' ├ Sidebar title ? ("%s") '%sidebar_title) + if ask: sidebar_title = ask if '"' in sidebar_title: - sidebar_title = sidebar_title.replace('"','\\"') + sidebar_title = sidebar_title.replace('"', '\\"') + + sidebar_conf = '%s/articles/sidebar/'%tyto.in_dir + sidebar_datas = '\nsidebar_dir = "%s"\n'%sidebar_conf + \ + 'sidebar_load = "%styto.sidebar"\n'%sidebar_conf + \ + 'sidebar_title = "%s"'%sidebar_title + + tyto.set_file(tyto.domain_conf, False, sidebar_datas) + + + # Sidebar Items + #-------------- + try: sidebar_items = tyto.sidebar_items + except: sidebar_items = "6" + + ask = '' + ask = input(' ├ [max=16] Sidebar Items ? ("%s") '%sidebar_items) + if ask: + if not ask.isdigit(): tyto.exiting("3", ask, True) + elif int(ask) in range(1,17): sidebar_items = int(ask) + + tyto.set_file(tyto.domain_conf, False, + 'sidebar_items = "%s"'%int(sidebar_items)) + + + + # Get srv root + #------------- + try: domain_srv = tyto.domain_srv + except: domain_srv = '/var/www' - # Sidbar items number. Default: 12 - # ------------------- - global sidebar_items - try: - sidebar_items - except: - sidebar_items = 8 + ask = '' + ask = input(' ├ System server ? ("%s") '%domain_srv) + if ask: + if not os.path.exists(srv): tyto.exiting("1", ask, True) + elif not domain_srv: tyto.exiting("255", '', True) - set_si = input(' ├ Sidebar max items [1-16] (%s) ? '%sidebar_items) - if set_si and set_si.isdigit(): - if set_si in range(1,16): - exiting('form',2,'\n:< Items number: 1-16') - sidebar_items = set_si - - # Domain LOGO (optional) - # ---------------------- - global domain_logo - try: - domain_logo - show_logo = domain_logo[:14] + '...' - except: - domain_logo = show_logo = '' + root_srv_dom = '%s/%s'%(domain_srv, domain_short) + srvs = '\nsrv_root = "%s/"\n'%domain_srv + \ + 'srv_domain = "%s/"\n'%root_srv_dom + \ + 'srv_wip = "%s/wip/"\n'%root_srv_dom + \ + 'srv_wip_tpl = "%s/wip/template/"\n'%root_srv_dom + \ + 'srv_wip_images = "%s/wip/images/"\n'%root_srv_dom + \ + 'srv_wip_files = "%s/wip/files/"\n'%root_srv_dom + \ + 'srv_www = "%s/www/"\n'%root_srv_dom + \ + 'srv_www_tpl = "%s/www/template/"\n'%root_srv_dom + \ + 'srv_www_images = "%s/www/images/"\n'%root_srv_dom + \ + 'srv_www_files = "%s/www/files/"'%root_srv_dom + tyto.set_file(tyto.domain_conf, False, srvs) - set_logo = input(' ├ Optional. Logo filename (%s) ? '%show_logo) - if set_logo: domain_logo = set_logo - append_f(temp_domain,'domain_logo = "%s"'%domain_logo) - # External URL profile (optional) - # ------------------------------- - global domain_exturl - try: - domain_exturl - show_e= domain_exturl[:14] + '...' - except: - domain_exturl = show_e = '' + # Activate Domain after Resumed configuration ? + #---------------------------------------------- + try: domain_active = tyto.domain_active + except: domain_active = False - set_e = input(' └ Optionnal. URL to a social network (%s) ? '%show_e) - if set_e: domain_exturl = set_e + file = open(tyto.domain_conf, 'r').read() + resume = ' │\n' + \ + ' ├──────────────────────────────────────┐\n' + \ + ' │ Please, READ the configuration datas │\n' + \ + ' ├──────────────────────────────────────┘' - append_f(temp_domain,'domain_exturl = "%s"'%domain_exturl) + print(resume) + + for line in file.rsplit('\n'): + print(' │', line) - # Adding sidebar conf - sidebar_dir = '%s/articles/sidebar/'%curr_dir - sidebar_load = '%styto.sidebar'%sidebar_dir - append_f(temp_domain,'\n# Sidebar') - append_f(temp_domain,'domain_sdb_dir = "%s"'%sidebar_dir) - append_f(temp_domain,'domain_sdb_load = "%s"'%sidebar_load) - append_f(temp_domain,'domain_sdb_title = "%s"'%sidebar_title) - append_f(temp_domain,'domain_sdb_items = "%s"'%sidebar_items) - -#==========================# -# If confirm activation # -# Add value to domain conf # -# Create all directories # -#--------------------------# -def create_domain(): - # Add activation var to temp domain conf - append_f(temp_domain,'\n# Domain activation') - append_f(temp_domain,'domain_active = True') + ask = input(' ├ Activate and prepare domain ? ') + if not ask in ['y', 'Y']: + tyto.set_file(tyto.domain_conf, False, + '\ndomain_active = False') + tyto.exiting("255", '', True) - # Add var domain_name to tyto_domains file, if not exists - domain_var = domain_name.replace('.','_') - if not domain_var in domains_db: - append_f(tyto_domains,'%s = "%s"'%(domain_var,curr_dir)) + # Activate Domain + #---------------- + tyto.set_file(tyto.domain_conf, False, + '\ndomain_active = True') - # Create all directories for this domain - check.create_domain_dirs('all') + # Load config + exec(open(tyto.domain_conf).read(),globals()) - # Will rename temp_domain conf to legacy domain conf file - exiting('form',2,'\n:D Activated domain: "%s"'%domain_name) + # Create sidebar + create_sidebar(opt, sidebar_dir) + + # Create folders from configuration file + folders = ( + srv_wip_tpl, srv_wip_images, srv_wip_files, + srv_www_tpl, srv_www_images, srv_www_files, + domain_files, domain_images, sidebar_dir, + domain_db, + ) + + print(' │') + for folder in folders: + if not os.path.exists(folder): + print(' ├ Create directory: %s'%folder) + if not os.makedirs(folder, exist_ok=True): + print(' │ Exists directory: %s'%folder) + + print(' │') + print(' ├──────────────────────────────────────┐') + print(' │ Domain is ready. Have fun, writers ! │') + print(' └──────────────────────────────────────┘') +#==============================# +# sidebar load file translated # +#------------------------------# +def create_sidebar(opt, sidebar_dir): + try: sidebar_load + except: sidebar_load = "%styto.sidebar"%sidebar_dir + + sdb_load_fr = '# Pour : Tyto - Littérateur\n' + \ + '# Type : fichier texte\n' + \ + '# Description : Fichier appelé par : tyto sidebar\n' + \ + '# Fichier : tyto.sidebar\n' + \ + '# Dossier : %s\n'%sidebar_dir + \ + '# Comment : 1 URI de l\'article par ligne\n' + \ + '# Ne commence pas par "/"\n' + \ + '# L\'ordre définit la position\n' + \ + '\n# %s\n'%(15 * "-") +\ + '# Exemples :\n' + \ + '# index.tyto\n' + \ + '# dir1/index.tyto\n' + \ + '# %s\n\n'%(15 * "-") + + sdb_load_en = '# For: Tyto - Littérateur\n' + \ + '# Type: Text file\n' + \ + '# Description: file called with: tyto sidebar\n' + \ + '# File: tyto.sidebar\n' + \ + '# Directory: %s\n'%sidebar_dir + \ + '# Comment: 1 article URI per line\n' + \ + '# not begining with "/"\n' + \ + '# Order in sidebar position\n' + \ + '\n# %s\n'%(15 * "-") +\ + '# Examples :\n' + \ + '# index.tyto\n' + \ + '# dir1/index.tyto\n' + \ + '# %s\n\n'%(15 * "-") + + if tyto.n == 0: sdb_load = sdb_load_fr + elif tyto.n == 1: sdb_load = sdb_load_en + + if not opt == 'Remove' and os.path.exists(sidebar_load): + ask = '' + ask = input(' ├ Initialize new sidebar ? ') + if not ask in ['y', 'Y']: + return + + tyto.set_file(sidebar_load, 'new', sdb_load) + + print(' ├ Create new file: %s'%sidebar_load) diff --git a/src/var/lib/tyto/program/html.py b/src/var/lib/tyto/program/html.py deleted file mode 100644 index 138d257..0000000 --- a/src/var/lib/tyto/program/html.py +++ /dev/null @@ -1,331 +0,0 @@ -#!/usr/bin/env python3 -# Name: Tyto - Littérateur -# Type: Global functions for HTML page -# Description: Create final HTML Page -# file: html.py -# Folder: /var/lib/tyto/programs/ -# By echolib (XMPP: im@echolib.re) -# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 - -#------------ -# funny stats -#------------ -# lines: -# functions: -# comments: -#---------------------------------------------------------------------- - -#********************************************************************** - -import re, os -import check, log, domain - -page = '' -Tyto = 'Tyto - Littérateur' -tytogen = 'https://git.a-lec.org/echolib/tyto-litterateur' -tytourl = 'https://tyto.echolib.re' -trans = [ - [ 'Licence', 'License' ], # 0 - [ 'Générateur', 'Generator' ], # 1 - [ 'À propos de', 'About' ], # 2 - [ 'Envoyer un courriel à', 'Send a mail to' ], # 3 - [ 'Détails de la licence', 'License\'s details'], # 4 - [ 'Courriel', 'Mail' ], # 5 - [ 'Site web généré par %s'%Tyto, 'Website generated by %s'%Tyto ], # 6 - [ 'Syndication de', 'Syndication of' ], # 7 - [ 'Dépôt officiel de %s'%Tyto, 'Official repository of %s'%Tyto ], # 8 - [ 'Écrit par', 'Written by' ], # 9 - [ 'le ', 'on '], # 10 - [ 'Description de', 'Description of '], # 11 - [ 'sur', 'on'], # 12 - [ 'est l\'auteur de l\'article :', 'is the author of post:'] # 13 - ] - -#=======================================# -# Translations terms # -# Only FR (default) and Other (english) # -#---------------------------------------# -def translations(post_date): - global fl # fl = field lang - global sdb_date - - # Default FR/fr - if re.match('fr', domain.domain_lang, re.IGNORECASE): fl = 0 - else : fl = 1 - - # Change date format for FR - if fl == 0: - fr_date = post_date.rsplit('-') - post_date = fr_date[2] + '/' + fr_date[1] + '/' + fr_date[0] - sdb_date = post_date - -#========================# -# Create FULL HTML5 Page # -# includes wip.html # -#------------------------# -def html_main_page(wip_html): - global post_date, page - - # Source DB variables - post_db = exec(open(check.curr_post_db).read(),globals()) - - # Metas in HTML page - #------------------- - scale = 'width=device-width, initial-scale=1.0' - visit = '3 days' - title = '%s %s %s'%(post_title, domain.sep_titles, domain.domain_title) - tags = '%s,%s'%(domain.domain_tags, post_tags) - icon = '/template/favicon.png' - logo = '/template/%s'%domain.domain_logo - f_css = '%stemplate/styles.css'%web_uri - f_rss = '/rss.xml' - i_rss = 'RSS 2.0. %s %s %s'%( - domain.domain_title, domain.sep_titles, domain.domain_name - ) - - # If no logo - if not domain.domain_logo: - msg_log = 'Unregistred logo in configuration domain' - log.append_f(check.post_logs, msg_log, 1) - - # Check for template files (styles, logo...) - files_uri = ( - '%s%s'%(domain.srv_wip, icon[1:len(icon)]), - '%s%s'%(domain.srv_wip, f_css[1:len(f_css)]), - '%s%s'%(domain.srv_wip, logo[1:len(logo)]) - ) - for file_uri in files_uri: - if not os.path.exists(file_uri): - msg_log = 'Unused template file: %s'%file_uri - log.append_f(check.post_logs, msg_log, 1) - - # Set some terms from lang domain - translations(post_date) - - # External URL in metas (if exists in config domain) - if domain.domain_exturl: - relme = '\n'%( - domain.domain_exturl - ) - else: - relme = '' - - # Metas in HTML page - #------------------- - metas = '\n' + \ - '\n'%scale + \ - '\n' + \ - '\n' + \ - '\n'%visit + \ - '\n'%domain.domain_lang + \ - '\n'%domain.domain_mail + \ - '\n'%domain.domain_license + \ - '\n'%Tyto + \ - '\n'%title + \ - '\n'%post_author + \ - '\n'%post_about + \ - '\n'%tags + \ - '\n'%post_date + \ - '\n'%post_url + \ - '\n'%(f_rss, i_rss) + \ - '\n'%f_css + \ - '\n'%icon + \ - '%s'%relme + \ - '%s'%title - - - # header in HTML page - #-------------------- - headers = '
\n'%domain.domain_css + \ - ' \n' + \ - '
\n' + \ - '

\n' + \ - ' %s\n'%( - domain.domain_title, - domain.sep_titles, - domain.domain_name, - domain.domain_title - ) + \ - '

\n' + \ - '

%s\n'%( - trans[11][fl], - domain.domain_title, - trans[12][fl], - domain.domain_url, - domain.domain_about - ) + \ - '

\n' + \ - '
\n' + \ - '
\n' - - - # Article (in section) - #-------------------------------------- - articles = '
\n' + \ - '
\n'%( - post_ID, domain.domain_css - ) + \ - '
\n' + \ - '

\n' + \ - ' %s %s\n'%( - post_author, trans[13][fl], post_title, - trans[9][fl], post_author - ) + \ - ' , %s\n'%trans[10][fl] + \ - ' %s\n'%sdb_date + \ - '

\n' + \ - '
\n' - - - # Aside after article - #-------------------- - asides = '' - - - # Footer, and of page - #-------------------- - footers = '
\n' + \ - '

%s %s

\n'%( - trans[2][fl], domain.domain_title) + \ - ' \n' + \ - ' \n' + \ - '
' - - - # Create file if not exists - #-------------------------- - files_tpl = [ - [ '%sheader.html'%domain.srv_wip_template, headers ], - [ '%sfooter.html'%domain.srv_wip_template, footers ] - ] - - for file_tpl in files_tpl: - if not os.path.exists(file_tpl[0]): - datas = open(file_tpl[0], 'w') - datas.write(file_tpl[1]) - datas.close() - msg_log = 'Create default file: %s'%file_tpl[0] - log.append_f(check.post_logs, msg_log, 0) - - #------------------# - # Create full page # - #------------------# - page = '\n' + \ - ' \n'%domain.domain_lang + \ - ' ' - - # Add tab metas in page - #---------------------- - # No file: use this default - for meta in metas.rsplit('\n'): - page = '%s\n%s%s'%(page, 6*' ', meta) - - page = '%s\n%s\n'%(page, 4*' ') + \ - '\n%s'%( - 4*' ', post_ID, domain.domain_css - ) - - # Add tab header in page - #----------------------- - if os.path.exists(files_tpl[0][0]): - headers_datas = open(files_tpl[0][0], 'r').read() - for header_line in headers_datas.rsplit('\n'): - page = '%s\n%s%s'%(page, 6*' ', header_line) - else: - # No file: use this default - for header in headers.rsplit('\n'): - page = '%s\n%s%s'%(page, 6*' ', header) - - msg_log = 'Use default header in page. Unused file: %s'%files_tpl[0][0] - log.append_f(check.post_logs, msg_log, 0) - - # Add tab article in page - for article in articles.rsplit('\n'): - page = '%s\n%s%s'%(page, 6*' ', article) - - # Add post from wip.html - #----------------------- - for line in wip_html: - page = '%s\n%s%s'%(page, 4*' ', line) - page = '%s\n%s
\n'%(page, 8*' ') - - # Add latest-posts in page - #------------------------- - # No file: use this default - for aside in asides.rsplit('\n'): - page = '%s\n%s%s'%(page, 8*' ', aside) - - page = '%s\n%s
'%(page, 6*' ') - - # Add footer in page - #------------------- - if os.path.exists(files_tpl[1][0]): - footers_datas = open(files_tpl[1][0], 'r').read() - for footer_line in footers_datas.rsplit('\n'): - page = '%s\n%s%s'%(page, 4*' ', footer_line) - else: - # No file: use this default - for footer in footers.rsplit('\n'): - page = '%s\n%s%s'%(page, 4*' ', footer) - msg_log = 'Use default footer in page. Unused file: %s'%files_tpl[1][0] - log.append_f(check.post_logs, msg_log, 0) diff --git a/src/var/lib/tyto/program/log.py b/src/var/lib/tyto/program/log.py deleted file mode 100644 index cd92783..0000000 --- a/src/var/lib/tyto/program/log.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python3 -# Name: Tyto - Littérateur -# Type: Global functions for logs -# Description: Print data to specific log file -# file: log.py -# Folder: /var/lib/tyto/scripts/ -# By echolib (XMPP: im@echolib.re) -# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 - -#------------ -# funny stats -#------------ -# lines: -# functions: -# comments: -#---------------------------------------------------------------------- - -#********************************************************************** -import check, domain - -#=======================# -# Manage Argument 'log' # -# Read, remove log file # -#-----------------------# -def manage_log(file_post, Opt): - import os, sys - - if file_post: - # No domain set, but ask for article : exit - if not domain.domain_conf: - sys.exit(1) - - # Get complete URI for post - post_uri = '%s%s'%(domain.domain_articles, file_post) - - # Get ID from URI - post_ID = check.get_filesum(post_uri,False) - - # Set log file for article - post_logs = '%s%s.log'%(domain.domain_logs,post_ID) - else: - post_logs = domain.tyto_logs - - if os.path.exists(post_logs): - if Opt == 'Remove' : - os.remove(post_logs) - msg_log = 'Log > Removed file: %s'%post_logs - if file_post: - append_f(domain.tyto_logs,msg_log,0) - else: - print(':) %s'%msg_log) - else: - file = open(post_logs,'r').read() - print(file) - else: - print(':| Unsed file yet: %s'%post_logs) - -#==============================# -# Set and return date and time # -# (especially for logs) # -#------------------------------# -def nowdate(): - import datetime - - now = datetime.datetime.now() - return(now.strftime('%Y-%m-%d %H:%M:%S')) - -#==================================# -# Append line to specific log file # -#----------------------------------# -def append_f(f,line,n): - smiley = [':D',':<\033[1;31m','\033[1;33m:|'] - now = nowdate() - - # Open file to append line - file = open(f, "a") - file.write('%s %s\n'%(now,line)) - file.close() - - if not line.endswith('\n'): - print('%s %s\033[0;0m'%(smiley[n],line)) diff --git a/src/var/lib/tyto/program/publish.py b/src/var/lib/tyto/program/publish.py deleted file mode 100644 index c8ce4cf..0000000 --- a/src/var/lib/tyto/program/publish.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python3 - -import rss, domain - -def manage_publish(file_post, Force): - - # At ending process.. - # Create rss.xml for www - rss.find_www(domain.srv_www, 'www') diff --git a/src/var/lib/tyto/program/rss.py b/src/var/lib/tyto/program/rss.py deleted file mode 100644 index 36c9181..0000000 --- a/src/var/lib/tyto/program/rss.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 -# Name: Tyto - Littérateur -# Type: Global functions for HTML page -# Description: Create RSS for wip, publish -# file: rss.py -# Folder: /var/lib/tyto/programs/ -# By echolib (XMPP: im@echolib.re) -# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 - -#------------ -# funny stats -#------------ -# lines: -# functions: -# comments: -#---------------------------------------------------------------------- - -#********************************************************************** - -import os, glob -import domain, html, log - -rss_headers = '\n' + \ - '\n' + \ - ' \n' + \ - ' %s %s %s %s Flux RSS 2.0\n'%( - domain.domain_title, - domain.sep_titles, - domain.domain_name, - domain.sep_titles - ) + \ - ' %s\n'%domain.domain_url + \ - ' %s\n'%domain.domain_about + \ - ' %s\n'%domain.domain_lang + \ - ' %s\n'%log.nowdate() + \ - ' %s\n'%domain.domain_license + \ - ' %s\n'%domain.domain_mail + \ - ' Tyto - Littérateur\n' - - -#==================================# -# Create RSS.xmp at ending process # -# srv: srv_www or srv_wip # -#----------------------------------# -def find_www(srv, srv_type): - # Create sidebar.html - rss_file = srv + 'rss.xml' - file = open(rss_file, 'w') - file.write(rss_headers) - file.close() - - # Get conf file, sort by ctime, and reverse - files = glob.glob("%s*.conf"%domain.domain_db) - files.sort(key=lambda x: os.path.getctime(x)) - files.reverse() # last created first - - # Check db_file if article is in www - rss_item = 0 - for db_file in files: - exec(open(db_file).read(),globals()) - - # Check srv_type (www or wip) - if srv_type == 'www': hash_srv = post_www - elif srv_type == 'wip': hash_srv = post_wip - post_uri_www = '%s%s'%(srv, post_srv) - - if not hash_srv[0]: - continue - - if not os.path.exists('%s%s'%(srv, post_srv)): - msg_log = 'RSS > Unused Article in www: %s'%post_uri_www - log.append_f(domain.tyto_logs, msg_log, 1) - continue - - rss_item += 1 - rss_post = ' \n' + \ - ' %s\n'%post_title + \ - ' %s\n'%post_url + \ - ' %s\n'%post_url + \ - ' %s\n'%hash_srv[1] + \ - ' %s\n'%post_about + \ - ' %s\n' + \ - ' \n' - - file = open(rss_file, 'a') - file.write(rss_post) - file.close() - - # Close tags - file = open(rss_file, 'a') - file.write(' \n') - file.close() - - # Log - - msg_log = 'RSS > Create file with %s items in: %s'%( - rss_item, rss_file - ) - log.append_f(domain.tyto_logs, msg_log, 0) - - - diff --git a/src/var/lib/tyto/program/sidebar.py b/src/var/lib/tyto/program/sidebar.py index 59124b8..11808c1 100644 --- a/src/var/lib/tyto/program/sidebar.py +++ b/src/var/lib/tyto/program/sidebar.py @@ -1,9 +1,9 @@ #!/usr/bin/env python3 # Name: Tyto - Littérateur -# Type: Global functions for HTML page -# Description: Create sidebar from file tyto.sidebar +# Type: Global functions to manage sidebar +# Description: Create domain # file: sidebar.py -# Folder: /var/lib/tyto/programs/ +# Folder: /var/lib/tyto/program/ # By echolib (XMPP: im@echolib.re) # License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 @@ -16,182 +16,25 @@ #---------------------------------------------------------------------- #********************************************************************** +import sys +import tyto -import re, os, sys, subprocess -import log, domain, check, html +# Load domain configuration if exists +if tyto.domain_exists: exec(open(tyto.domain_conf).read()) -sidebar_file = '%ssidebar.html'%domain.srv_wip_template - -#========================# -# Manage sidebar command # -#------------------------# -def manage_sidebar(article, Opt): - create = False - - # Create tyto.sidebar - if not os.path.exists(domain.domain_sdb_load): - create_sdb_load() - create = True - - # Wan to edit (in nano) - # Then, ask to make HTML sidebar (if file changed) - if Opt == "Edit": - old_sdb_ID = check.get_filesum(domain.domain_sdb_load, True) - edit_sdb = subprocess.run(['/usr/bin/nano', - '--linenumbers', - domain.domain_sdb_load]) - new_sdb_ID = check.get_filesum(domain.domain_sdb_load, True) - if old_sdb_ID == new_sdb_ID: - sys.exit(0) - else: - ask_make_sdb = input('! Create new HTML sidebar ? ') - if not ask_make_sdb in ['y', 'Y']: domain.exiting('root', 1, '') - - loop_sidebar(create) +#==============================# +# Manage arguments for sidebar # +#------------------------------# +def manage_sidebar(target, option): + # Initialize new sidebar + if not target: + if option == "Remove": + import domain + domain.create_sidebar(opt, sidebar_dir) + if option == 'Edit': + print(":D Edit sidebar configuration file:", sidebar_load) + tyto.edit_file(sidebar_load) -#========================# -# Read tyto.sidebar file # -#------------------------# -def loop_sidebar(create): - Post_Err = False - sdb_posts = posts_uri = [] - max_items = int(domain.domain_sdb_items) + 1 - counter = 0 # To not set more than set in config - sdb_loaded = (open(domain.domain_sdb_load)).read() - - for line in sdb_loaded.rsplit('\n'): - if create : print(line) - elif line.startswith('#'): continue - elif len(line) == 0 : continue - else: - if line.startswith('/'): line = line[1:len(line)] # No need /... - - post_uri = '%s%s'%(domain.domain_articles, line) - posts_uri = posts_uri + [post_uri] - - if not os.path.exists(post_uri): - print(':< From URI: %s. Unused file: %s'%(line, post_uri)) - Post_Err = True - else: - counter += 1 - if counter == max_items: break - hash_post = check.get_filesum(post_uri, False) - sdb_posts = sdb_posts + [hash_post] - - if Post_Err: - msg_log = 'Sidebar > Not created. Mismatch some article\'s URI' - log.append_f(domain.tyto_logs, msg_log, 1) else: - - print('>', sdb_posts, posts_uri) - - # Create sidebar.html - file = open(sidebar_file, 'w') - file.close() - - i = 0 - for item in sdb_posts: - db_article = '%s%s.conf'%(domain.domain_db, item) - if os.path.exists(db_article): - print("OK for",item, posts_uri[i]) - create_sdb_item(db_article) - else: - msg_log = 'Sidebar > Article not yet ready: %s'%posts_uri[i] - log.append_f(domain.tyto_logs, msg_log, 1) - i += 1 - - -#==========================================# -# Create HTML item in sidebar from article # -#------------------------------------------# -def create_sdb_item(db_article): - # Load DB for specific article - exec(open(db_article).read(),globals()) - - # Get article URL from filepath - post_short_uri = post_file.replace(domain.domain_articles, '/') - post_short_uri = post_short_uri.replace(".tyto", ".html") - # URL do not need /index.html - if post_short_uri.endswith('index.html'): - post_short_uri = post_short_uri.replace('index.html', '') - - # Article must have same hash from chk and wip - if not post_wip[0] == post_chk[0]: - print(':< Article has changed and needs to be checked first') - return(1) - - # Create sidebar.html - html.translations(post_date) - - sdb_html_item = '' - - with open(sidebar_file, 'a') as file: - for line in sdb_html_item.rsplit('\n'): - file.write('%s%s\n'%(16*' ', line)) - - - -#=====================# -# Create sidebar file # -# from choosen lang # -#---------------------# -def create_sdb_load(): - sdb_file_fr = '# Nom: Tyto - Littérateur\n' + \ - '# Type: fichier texte\n' + \ - '# Description: Fichier appelé par : tyto sidebar\n' + \ - '# fichier: tyto.sidebar\n' + \ - '# Dossier: articles/sidebar/\n' + \ - '# (depuis le dossier du domaine)\n' + \ - '# Comment: 1 URI de l\'article par ligne\n' + \ - '# Ne commence pas par "/"\n' + \ - '# L\'ordre définit la position\n' + \ - '# exemples :\n' + \ - '# index.tyto\n' + \ - '# dir1/index.tyto\n' - - sdb_file_en = '# Name: Tyto - Littérateur\n' + \ - '# Type: Text file\n' + \ - '# Description: file called with: tyto sidebar\n' + \ - '# file: tyto.sidebar\n' + \ - '# Folder: articles/sidebar/\n' + \ - '# (from the domain folder)\n' + \ - '# Comment: 1 article URI per line\n' + \ - '# not begining with "/"\n' + \ - '# Order in sidebar position\n' + \ - '# examples :\n' + \ - '# index.tyto\n' + \ - '# dir1/index.tyto\n' - - if re.match('fr', domain.domain_lang, re.IGNORECASE): - sdb_file = sdb_file_fr - else: - sdb_file = sdb_file_en - - file = open(domain.domain_sdb_load, "w") - file.write(sdb_file) - file.close() - msg_log = 'Sidebar > Create new sidebar file in %s'%( - domain.domain_sdb_load - ) - log.append_f(domain.tyto_logs, msg_log, 0) - + db_exists = tyto.get_db_post(target) # Article exists + has DB ? + if not db_exists: tyto.exiting("4", '') # Needs database diff --git a/src/var/lib/tyto/program/tyto.py b/src/var/lib/tyto/program/tyto.py new file mode 100644 index 0000000..c95bf51 --- /dev/null +++ b/src/var/lib/tyto/program/tyto.py @@ -0,0 +1,403 @@ +#!/usr/bin/env python3 +# Name: Tyto - Littérateur +# Type: Global functions for Tyto +# Description: Settings, Tools and +# file: tyto.py +# Folder: /var/lib/tyto/program/ +# By echolib (XMPP: im@echolib.re) +# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 + +#------------ +# funny stats +#------------ +# lines: +# functions: +# comments: +#---------------------------------------------------------------------- + +#********************************************************************** + +import os, sys, subprocess, locale, base64, datetime +from hashlib import blake2b + +# Second argument in command +#--------------------------- +arguments = ( + '-a', 'add', + '-R', 'remove', + '-e', 'edit', + '-n', 'new', + '-F', 'force' + ) + + +# Settings +#--------- +domain_active = False +home_dir = os.path.expanduser('~') +in_dir = os.getcwd() + +# Set uri for configuration domain file +try: + sys.argv[2] + if not sys.argv[2] in arguments: + conf_dir = '%s/%s'%(in_dir,sys.argv[2]) + conf_dir = conf_dir.rsplit('articles')[0] + else: + conf_dir = in_dir.rsplit('articles')[0] + '/' +except: + conf_dir = in_dir.rsplit('articles')[0] + '/' + +domain_conf = '%styto_domain.conf'%conf_dir +db_dir = '%s/.local/tyto/'%home_dir + + +# Check if domain config file +#---------------------------- +stdout = '%s %s domain "%s" in %s' # Message to show domain status + +if os.path.exists(domain_conf): + exec(open(domain_conf).read()) + datas_domain = open(domain_conf, "r").read() + domain_exists = True + if domain_active: + smiley = ':D'; status = 'Active' + domain_active = True + else: + smiley = ':/'; status = 'Inactive' + domain_active = False + print(stdout%( + smiley, status, domain_short, domain_conf + ) + ) +else: + print(':| No domain configured in this directory: %s'%domain_conf) + domain_exists = domain_active = False + +if domain_exists: + db_dir = '%s%s/articles'%(db_dir, domain_short) + + +# Basic translations: french, english +#------------------------------------ +try: lang = domain_lang +except: lang = locale.getdefaultlocale()[0].split('_')[0] +if lang.lower() == 'fr': n = 0 +else: n = 1 + +# Translations French/English +trans = [ + ['À l\'affiche !', 'Featured !' ] + ] + +# Set all tags used in article's header +headers = ( + 'title:', + 'about:', + 'author:', + 'tags:', + 'date:', + 'link:', + 'image:', + 'file:', + 'abbr:', + 'brut:', + '#' + ) + +# Words and template Tags (paragraphs, lists, bold, strong...) +# Used to check, and replace (wip) tags +# As base64 is used, do NOT set marker: =_ _= +# [5] = name for stats and log. +# [6] = Check content differently. 't' = startswith +#------------------------------------------------------------- +words_tags = [ +('>_', '_<', '', 'anchors', 'w'), +('*_', '_*', '', '', 'strongs', 'w'), +('+_', '_+', '', '', 'bolds', 'w'), +('/_', '_/', '', '', 'emphasis', 'w'), +('[_', '_]', '', '', 'italics', 'w'), +('~_', '_~', '', '', 'dels', 'w'), +('._', '_.', '', '', 'underlines', 'w'), +(':_', '_:', '', '', 'cites', 'w'), +('%_', '_%', '', '', 'customs', 'w'), +('{_', '_}', '', '', 'codes', 'w'), +('((', '))', '

', '

', 'paragraphs', 't'), +('[[', ']]', '[[', ']]', 'quotes', 't'), +('{{', '}}', '{{', '}}', 'bcodes', 't'), +('-(', '-)', '-(', '-)', 'lists', 't') +] + + +# Tags that do not need to be paired +#----------------------------------- +single_tags = [ +('|', '
'), # New Line +('->', '
') # Anchors +] + +# Markers for lists, to check in list content +#-------------------------------------------- +markers_lists = ('+', '=', ' ') + +# Tags used for titles +titles_tags = ('#1 ', '#2 ', '#3 ', '#4 ', '#5 ', '#6 ') + + +#=======# +# TOOLS # +#=======#-------------------------------------------------------------- +#=======================# +# Return sum of srcfile # +# src: True = Content # +# False = URI # +#-----------------------# +def get_filesum(path, src): + file_sum = blake2b(digest_size=4) + + if src: file_sum.update(open(path, 'rb').read()) + else : file_sum.update(path.encode()) + return file_sum.hexdigest() + + +#==============================# +# Set and return date and time # +# (especially for logs) # +#------------------------------# +def nowdate(): + now = datetime.datetime.now() + return(now.strftime('%Y-%m-%d %H:%M:%S')) + + +#=======================# +# Check if article file # +# Check if article DB # +#-----------------------# +def get_db_post(target): + # Check if target file exists + global uri_post + uri_post = '%s/%s'%(in_dir, target) + if not os.path.exists(uri_post): + exiting("1", uri_post, True) + + global uri_root + uri_root = uri_post + + global uri_src + uri_src = '/' + uri_post.rsplit(domain_articles)[1] + + global hash_post + hash_post = get_filesum(uri_post, True) # From content file + + global web_uri + ext = os.path.splitext(uri_post) + new_ext = '.html' + uri_post = uri_post.replace(ext[1], new_ext) + + web_uri = '/' + uri_post.rsplit(domain_articles)[1] + + global post_filename, post_dir + post_filename = os.path.basename(uri_post) + post_dir = uri_post.replace(post_filename, '') + + global uri_id + uri_id = get_filesum(uri_post, False) # From URI file + + global post_db + post_db = '%s/%s.conf'%(db_dir, uri_id) + + if os.path.exists(post_db): db_exists = True + else : db_exists = False + + return(db_exists) + + +#======================# +# Open and edit a file # +#----------------------# +def edit_file(edit_file): + file_edit = subprocess.run( + [ + '/usr/bin/nano', + '--linenumbers', + edit_file + ] + ) + + +#================# +# Create a file # +# Or append text # +#----------------# +def set_file(path, new, text): + if new: opt = "w" + else: opt = "a" + + file = open(path, opt) + file.write(text + '\n') + file.close() + + +#==========================# +# Get CSS from line if set # +#--------------------------# +def get_css(line): + # Use this default, if not in conf + try: set_css = domain_css + except: domain_css = 'tyto' + + # Get CSS from line + try: set_css = line.rsplit(' ')[1] + except: set_css = domain_css + + return set_css + + +#=======================# +# Protec iCodes # +# Used in check and wip # +#-----------------------~ +def protect_icodes(post_bottom, article_bottom): + global protect_article + global nbr_codes + + nbr_codes = 0 # Stats here for DB as content will change + protect_article = article_bottom + incode = False + src_code = rep_code = '' + + # Get only lines that contains code + for ln, line in enumerate(post_bottom): + if '{_' and '_}' in line: + + # Iterate in line + for i, c in enumerate(line): + if c == '_': + c_b = line[i-1] # before + c_bb = line[i-2] # before + before + c_a = line[i+1] # after + + # incode if + if c_b == '{' and not c_bb == '\\': + incode = True + nbr_codes += 1 + code = words_tags[9][2] + continue + + # No more in code if + if c_a == '}' and not c_b == '\\': + incode = False + code = '%s%s%s'%(code, src_code, words_tags[9][3]) + b64_code = b64('Encode', code) + rep_code = "%s%s%s"%( + words_tags[9][0],rep_code,words_tags[9][1] + ) + temp_post = protect_article.replace(rep_code, b64_code) + protect_article = temp_post + + src_code = rep_code = b64_code = '' + continue + + # Construct original replacement code and source code + if incode: + rep_code = '%s%s'%(rep_code, c) + if c == '\\': continue + src_code = '%s%s'%(src_code, c) + + +#=============================================# +# Protect block-Codes, quotes # +# Also remove commented lines # +# Used in check and wip # +# For check, create new article without bcode # +# For wip, remplace content with base64 # +#---------------------------------------------# +def protect_bcodes_quotes(process, post_bottom): + + global protect_article + in_bcode = in_quote = False + protect_article = '' + + if process == 'check': + global nbr_titles, nbr_bcodes, nbr_quotes # Stats for DB + nbr_titles = nbr_bcodes = nbr_quotes = 0 + + for line in post_bottom: + if line.startswith(words_tags[12][0]): + in_bcode = True + nbr_bcodes += 1 + continue + elif line.startswith(words_tags[12][1]): + in_bcode = False + continue + elif line.startswith('#'): # As convention + if line.startswith(titles_tags): nbr_titles += 1 + else: continue + + if in_bcode: continue + elif line.startswith(words_tags[11][0]): + in_quote = True + nbr_quotes += 1 + continue + elif line.startswith(words_tags[11][1]): + in_quote = False + continue + + if in_quote: + if not line in (words_tags[10][0], words_tags[10][1]): + continue + + if not protect_article: protect_article = line + else: protect_article = '%s\n%s'%(protect_article, line) + + +#=====================================# +# Encode/Decode string to/from base64 # +# Data protection # +#-------------------------------------# +def b64(action, content): + if action == 'Encode': + global b64_content + b64_base64 = '' + content_bytes = content.encode("ascii") + base64_bytes = base64.b64encode(content_bytes) + b64_content = 'B64_' + base64_bytes.decode("ascii") + '_B64' + return b64_content + + elif action == 'Decode': + global src_content + src_content = '' + content_bytes = post_content.encode("ascii") + base64_bytes = base64.b64decode(content_bytes) + src_content = base64_bytes.decode("ascii") + return src_content + + else: + print("Options: 'Encode', 'Decode'") + sys.exit(1) + + +#================================# +# Exit from program with message # +#--------------------------------# +def exiting(nbr, value, out): + nbrs = { + '1' : ':< \033[1;31mUnused ressource\033[0;0m: "%s"'%value, + '2' : ':< \033[1;31mIncomplete data\033[0;0m: "%s"'%value, + '3' : ':< \033[1;31mInvalid data\033[0;0m: "%s"'%value, + '4' : ':< \033[1;31mNo database yet\033[0;0m. Check article first.', + '5' : ':< \033[1;31mUnused argument\033[0;0m file', + '6' : ':< \033[1;31mUnused "%s"\033[0;0m in article'%value, + '7' : ':< Article is \033[1;31mnot valid yet\033[0;0m', + '8' : ':< tags "%s" \033[1;31mnot paired\033[0;0m'%value, + '9' : ':D Article has changed (wip is old)', + '20' : ':D Article already up-to-date on: %s'%value, + '21' : ':D Article is valid and ready to wip', + '255' : ':| Maybe later...' + } + + msg = nbrs[nbr] + print(msg) + + if int(nbr) >= 20: nbr = 0 + if out: sys.exit(int(nbr)) diff --git a/src/var/lib/tyto/program/wip.old.py b/src/var/lib/tyto/program/wip.old.py deleted file mode 100644 index 17cd287..0000000 --- a/src/var/lib/tyto/program/wip.old.py +++ /dev/null @@ -1,412 +0,0 @@ -#!/usr/bin/python -# Name: Tyto - Littérateur -# Type: Global functions for wip -# Description: Converters from Source to HTML -# file: wip.py -# Folder: /var/lib/tyto/scripts/ -# By echolib (XMPP: im@echolib.re) -# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 - -#------------ -# funny stats -#------------ -# lines: -# functions: -# comments: -#---------------------------------------------------------------------- - -#********************************************************************** - -import os, sys -import check,log,domain - -Tyto_Err = False -post_uri = '' -# -# Manage WIP argument -# -def manage_wip(file_post, Force): - # Check if argument's file (.tyto) - if not file_post: - print(':( Unused argument file') - sys.exit(1) - - # Check if file exists - post_uri = '%s%s'%(domain.domain_articles,file_post) - if not os.path.exists(post_uri): - print(':( Unused file: %s'%post_uri) - sys.exit(1) - - # Get ID from URI (to get DB file) - post_ID = check.get_filesum(post_uri,False) - - # Set database file for this article - # Check if DB exists - post_db = '%s%s.db'%(domain.domain_db, post_ID) - if not os.path.exists(post_db): - print(':( Use "check" before "wip".') - sys.exit(1) - - # Set and check/create logs file for this article - post_logs = '%s%s.log'%(domain.domain_logs,post_ID) - - -#========# -# # -# Basics # -# # -#========#------------------------------------------------------------- -#===========================# -# Convert file to post_temp # -#---------------------------# -def post_to_string(file_path): - global post_temp - post_temp = '' - post_html = '' - with open(file_path, "r") as file: - post_temp = file.read() - - remove_empty_lines(post_temp.split('\n')) - post_html = post_temp - -#===========================# -# Convert content TO base64 # -#---------------------------# -def convert_to_b64(post_content): - import base64 - global b64_content - post_content_base64 = '' - content_bytes = post_content.encode("ascii") - base64_bytes = base64.b64encode(content_bytes) - b64_content = 'B64_' + base64_bytes.decode("ascii") + '_B64' - -#================================# -# Convert FROM base64 to content # -#--------------------------------# -def convert_from_b64(post_content): - import base64 - global src_content - post_content_src = '' - content_bytes = post_content.encode("ascii") - base64_bytes = base64.b64decode(content_bytes) - src_content = base64_bytes.decode("ascii") - -#==========================# -# Get Writer's CSS config # -# For compatible's markers # -#--------------------------# -def get_css(css,css_gen): - global css_set - - try: - css_set = line.split(" ")[1] - except: - css_set = '%s%s'%(css,css_gen) - -#=============================# -# Get post, witout empty line # -#-----------------------------# -def remove_empty_lines(post): - global post_html, post_temp, line - post_temp = '' - post_html = '' - - for line in post: - c = len(line) - if c > 0: - #print(c,line) - if not post_temp: - post_temp = line - else: - post_temp = '%s\n%s'%(post_temp,line) - - post_html = post_temp - - -#============# -# # -# Converters # -# # -#============#--------------------------------------------------------- -#==========================# -# Convert bCodes to base64 # -#--------------------------# -def convert_bcodes(post,fm,lm,css): - import re - global post_html, line, css_set - post_temp = '' - span_nbr = ''%css - span_code = ''%css - span_end = '' - pre_end = '' - ln_nbr = 0 - bCode = False - blines = '' - - for line in post: - if line.startswith(fm): # Starting bcode marker - ln_nbr = 0 - bCode = True - get_css(css,'_bcode') - pre_start = '
'%css_set
-      blines    = '%s'%pre_start
-      css_set   = ''
-      continue
-    elif line.startswith(lm): # Ending bcode marker
-      bCode     = False
-      line      = ''
-      blines    = '%s\n%s'%(blines,pre_end)
-      convert_to_b64(blines)
-      post_temp = '%s\n%s'%(post_temp,b64_content)
-
-    if not bCode:
-      post_temp = '%s\n%s'%(post_temp,line)
-    else:
-      ln_nbr += 1
-      blines = '%s\n  %s%d%s%s%s%s'%\
-                (
-                blines,span_nbr,ln_nbr,span_end,span_code,line,span_end
-                )
-
-  remove_empty_lines(post_temp.split('\n'))
-  post_html = post_temp
-
-#============================================#
-# Convert Base64 strings to original content #
-#--------------------------------------------#
-def convert_b64_lines(post):
-  import re
-  global post_html,line
-  post_temp    = ''
-  post_html    = ''
-  b64_contents = ''
-  
-  for line in post:
-    if not 'B64_' in line:
-      post_temp = '%s\n%s'%(post_temp,line)
-    else:
-      b64_contents = re.findall(r"B64_(.*?)_B64", line)
-      for b64_content in b64_contents:
-        convert_from_b64(b64_content)
-        line = line.replace('B64_%s_B64'%b64_content, src_content)
-      post_temp = '%s\n%s'%(post_temp,line)
-
-  remove_empty_lines(post_temp)
-  post_html = post_temp
-
-#==========================#
-# Convert iCodes to base64 #
-# fm = FIRST Marker        #
-# lm = LAST Marker         #
-#--------------------------#
-def convert_icodes(post, fm, lm, css):
-  import re
-  global post_html
-  post_temp       = '' # Temp string to become post_html string page
-  icodes_contents = '' # strings containing icode
-  fm_html         = ''%css
-  lm_html         = ''
-  fm_spe          = '!%s'%(fm)  # Special for !<_
-  lm_spe          = '%s!'%lm    # Special for _>!
-  
-  for line in post:
-    # Special marker containting legacy one
-    if lm_spe and fm_spe in line:
-      icodes_contents = re.findall(r"%s(.*?)%s"%(fm_spe,lm_spe), line)
-      for icode in icodes_contents:
-        content_rep = '%s%s%s'%(fm_spe,icode,lm_spe)
-        icode = '%s'%(css,icode)
-        convert_to_b64(icode)
-        line = line.replace(content_rep,b64_content)
-    
-    # Legacy marker
-    if lm and fm in line:
-      icodes_contents = re.findall(r"%s(.*?)%s"%(fm,lm), line)
-      for icode in icodes_contents:
-        content_rep = '%s%s%s'%(fm,icode,lm)
-        icode = '%s'%(css,icode)
-        convert_to_b64(icode)
-        line = line.replace(content_rep,b64_content)
-    
-    post_temp = '%s\n%s'%(post_temp,line)
-  post_html = post_temp
-
-#====================================#
-# Convert Quotes                     #
-# 2 types:                           #
-#   - Advanced, with author          #
-#   - Simple, with no author         #
-# mt = marker type (Should be 3 '-') #
-#------------------------------------#---------------------------------
-#=========================#
-# Return datas after term #
-#-------------------------#
-def get_quote_datas(term,line):
-  import re
-
-  term_data = re.compile('%s(.*)$'%term)
-  if term_data:
-    return term_data.search(line).group(1)
-
-#=====================#
-# Loop in Post        #
-# Convert quotes only #
-#---------------------#
-def convert_quotes(post,mt,css):
-  import re
-  global post_html,line,htmlquote, cite
-  post_temp = '' # Temp string to become post_html string page
-  Quote     = False
-  bquote    = htmlquote = htmllines = ''
-  cite      = ''
-  link      = cite_HTML = ''
-  lang      = lang_HTML = ''
-  book = year = title_HTML = ''
-  quote_nbr = 0
-
-  for line in post:
-    # Starting quote
-    if line.startswith(mt):
-      if not Quote:
-        Quote = True
-        get_css(css,'_quote')
-        quote_nbr += 1
-        line = '_QUOTE_%d'%quote_nbr
-        if post_temp:
-          post_temp = '%s\n%s'%(post_temp,line)
-        else:
-          post_temp = line
-        continue
-      # End of quote
-      # Create HTML and convert marker to Base64
-      else:
-        Quote = False
-        
-        # Create HTML datas
-        if cite and book and year:
-          title_HTML = ' title="%s - %s (%s)"'%(cite,book,year)
-        elif book and year:
-          title_HTML = ' title="%s (%s)"'%(book,year)
-        elif book:
-          title_HTML = ' title="%s"'%book
-        elif year:
-          title_HTML = ' title="%s"'%year
-        
-        htmlquote = '
>' # No close marker + # Article exists + has DB ? + db_exists = tyto.get_db_post(target) + if not db_exists: + tyto.exiting("4", '', True) -# 'Open' , 'Close' , 'Name' -markers_reg = [ - [ r'^\($|^\(\s' , r'^\)$' , 'paragraphs' ], - [ r'^\(\($|^\(\(\s', r'^\)\)$', 'quotes' ], - [ r'^\[\[$|^\[\[\s', r'^\]\]$', 'brut codes' ], - [ r'^-\($|^-\(\s' , r'^-\)$' , 'lists' ] - ] + # Has DB: conditions to process + is_wip = True + is_new = False + is_file = True + do_wip = False -#=====================# -# Manage WIP argument # -#---------------------# -def manage_wip(file_post, Force): - # Get IDs from Article - check.post_IDs(file_post) + # Load DB + exec(open(tyto.post_db).read(),globals()) - # Check DB - if not check.db_exist: - print(':( Article must be checked first.') - sys.exit(1) + # In any case, if Force + if option == 'Force': + wip_article() + return - # Check ID.wip - if not os.path.exists(check.post_tmp): - print(':( Article must be check again (unsed %s)'%( - check.post_tmp - ) - ) - sys.exit(1) - - # Current Article has changed (not same hash in DB for chk) - if check.hash_chk != check.post_chk[0]: - print(':| Article has changed. Check it first.') - sys.exit(0) - - # Article has same hash in DB for wip - if check.hash_chk == check.post_wip[0]: - # Check if file exists on the server - if check.srv_post_wip[0] and not Force: - print(':| Article was already converted on %s'%( - check.post_wip[1] - ) - ) - sys.exit(0) + # Compare and check file + if not hash_wip == hash_chk: is_wip = False ; do_wip = True + if not hash_wip == tyto.hash_post: is_new = True ; do_wip = True + if not os.path.exists(wip_uri): is_file = False ; do_wip = True - - # All is good, converting... - #--------------------------- - # Source DB variables - post_db = exec(open(check.curr_post_db).read(),globals()) - - # Send to log - msg_log = 'Wip > Article: %s. logs: %s'%( - check.post_uri, check.post_logs - ) - log.append_f(domain.tyto_logs, msg_log, 0) - - # Set file_string from post_tmp - file_string = open(check.post_tmp, 'r').read() - post_lines = file_string.rsplit('\n') - - # Set wip_html string. Will be the HTML part
- global wip_html - wip_html = '' - - for line in post_lines: - if len(line) == 0: continue - wip_html = '%s%s\n'%(wip_html, line) - - wip_begin_markers(wip_html.rsplit('\n')) - wip_titles( wip_html.rsplit('\n')) - wip_words_markers(wip_html) - - if files_u > 0: wip_files_links(wip_html) - if images_u > 0: wip_images( wip_html) - if anchors > 0: wip_anchors( wip_html) - if abbrs_u > 0: wip_abbrs( wip_html) - - # After all, convert protected contents - if links_u > 0: wip_links( wip_html) - if quotes > 0: wip_quotes( wip_html.rsplit('\n')) - - # brut files - if bruts_u > 0: wip_bruts( wip_html.rsplit('\n')) - - # Get Legacy contents from base64 markers - convert_all_b64(wip_html.rsplit('\n')) - - - #print('> Article with Tabs:') - tab_article(wip_html.rsplit('\n')) - - # Create full page - html.html_main_page(wip_html.rsplit('\n')) - - wip_html = html.page - print('> Article HTML:\n', wip_html) - - # Create file to wip srv (replace file, if exists) - wip_file = '%s%s'%(domain.srv_wip, check.post_srv) - if os.path.exists(wip_file): - os.remove(wip_file) - - # Create sub folder if needed - wip_dir = '%s%s'%(domain.srv_wip, check.post_dir) - os.makedirs(wip_dir, exist_ok=True) - - - page_file = open(wip_file, 'w') - page_file.write(wip_html) - page_file.close() - - time_wip = log.nowdate() - hash_wip = check.get_filesum(check.post_file, True) - - rep_post_wip = 'post_wip = (\'%s\', \'%s\')'%( - check.post_wip[0], check.post_wip[1]) - tmp_post_wip = (hash_wip, time_wip) - post_wip = 'post_wip = %s'%str(tmp_post_wip) - - # Replace post_wip in DB - with open(check.post_db, 'r') as file: - filedata = file.read() - filedata = filedata.replace(rep_post_wip, post_wip) - with open(check.post_db, 'w') as file: - file.write(filedata) - # log - msg_log = 'Edit Database: %s'%check.post_db - log.append_f(check.post_logs, msg_log, 0) - - # At ending process.. - # Create rss.xml for www - rss.find_www(domain.srv_wip, 'wip') - -#============================# -# HTML CONVERTERS # -# wip_tmp: new replacedlines # -#============================#----------------------------------------- -#============================# -# New line: | # -# Anchors: >> # -# Paragraphs: ( =

# -# bCodes: [[ = # -# Convert to HTML >> base64 # -#----------------------------# -def wip_begin_markers(wip_lines): - global wip_html - - wip_tmp = '' - # Set marker (regex to find), HTML, Need CSS - marks_html = [ - ['^\|$|^\|\s' , '
' , True ], - ['^>>\s' , '' , True ], - [r'^\($|\(\s' , '

' , True ], - ['^\)$|^\)\s' , '

' , False], - ['^\[\[$|^\[\[\s' , '',True ], - ['^\]\]$|^\]\]\s' , '' , False] - ] - - for line in wip_lines: - if len(line) == 0: continue - - # Find if line has marker and remplace - for marker in marks_html: - if re.match(marker[0], line): - if marker[2]: # Has CSS - get_css(line) - line = line.replace(line, marker[1]%css_set) - else: - line = line.replace(line, marker[1]) - convert_to_b64(line) - line = b64_content - wip_tmp = '%s%s\n'%(wip_tmp, line) - - wip_html = wip_tmp - -#===========================# -# Titles: #[1-6] = # -# Add a
# -# - if contents after title # -# (and not a new title) # -#---------------------------# -def wip_titles(wip_lines): - global wip_html - - wip_tmp = '' - has_div = False - - for ln, line in enumerate(wip_lines, 1): - if len(line) == 0: continue - - # Title found - if re.match('#\d\s', line): - tn = line[1] - ts = tn * 2 # Tab spaces - if has_div: # Before Title, if div was open, close it - wip_tmp = '%s
\n'%wip_tmp - has_div = False - - # Replace #[1-6] TITLE - wip_tmp = '%s%s\n'%( - wip_tmp, - line.replace('#%s '%tn, - ''%( - tn,domain.domain_css - ) - ), - tn - ) - - # Check next line - # Add div if contents after, and not a new title - if not re.match('#\d\s', wip_lines[ln]): # NOT a new title - wip_tmp = '%s
\n'%( - wip_tmp, domain.domain_css,tn - ) - has_div = True - else: - wip_tmp = '%s%s\n'%(wip_tmp, line) - - if has_div: # Close last div - wip_tmp = '%s
\n'%wip_tmp - has_div = False - - wip_html = wip_tmp - - -#================================================# -# Create Anchors (links) and convert to HTML # -# Target anchors are done with wip_begin_markers # -# Each are converted to Base64 # -#------------------------------------------------# -def wip_anchors(article): - global wip_html - - anchor_fmt = '%s' - anchors_link = re.findall(r'\>_(.*?)_\<', article) - - for anchor in anchors_link: - anchor_id = anchor.rsplit(':',1)[0] - anchor_name = anchor.rsplit(':',1)[1] - anchor_b64 = anchor_fmt%(anchor_id, anchor_name) - convert_to_b64(anchor_b64) - article = article.replace('>_%s_<'%anchor, b64_content) - - wip_html = article - -#==============================# -# Convert links to HTML # -# Each are converted to Base64 # -#------------------------------# -def wip_links(article): - global wip_html - - link_fmt = '%s' - all_vars = set(globals()) - - for var in all_vars: - if var.startswith('link_'): - link = globals()[var] - link_b64 = link_fmt%(domain.domain_css, link[1], - link[2], link[0] - ) - convert_to_b64(link_b64) - article = article.replace('_%s'%link[0], b64_content) - - wip_html = article - -#===========================================# -# Convert abbrs to HTML # -# each found are converted to Base64 # -# (avoid mismatch HTML if same word inside) # -#-------------------------------------------# -def wip_abbrs(article): - global wip_html - - abbr_fmt = '%s' - all_vars = set(globals()) - - for var in all_vars: - if var.startswith('abbr_'): - abbr = globals()[var] - abbr_b64 = abbr_fmt%(domain.domain_css, abbr[1], abbr[2]) - convert_to_b64(abbr_b64) - article = article.replace(abbr[0], b64_content) - - wip_html = article - -#======================================# -# Words Markers (strongs, emphasis...) # -#--------------------------------------# -def wip_words_markers(wip_tmp): - global wip_html - - # Set marker, and its HTML value - marks_html = [ - ['*_' , ''%domain.domain_css], - ['_*' , '' ], - ['+_' , ''%domain.domain_css ], - ['_+' , '' ], - ['-_' , ''%domain.domain_css ], - ['_-' , '' ], - ['~_' , ''%domain.domain_css ], - ['_~' , '' ], - ['/_' , ''%domain.domain_css ], - ['_/' , '' ], - ['\\_' , ''%domain.domain_css ], - ['_\\' , '' ], - ['=_' , ''%domain.domain_css ], - ['_=' , '' ], - ['×_' , '' ], - ['_×' , '' ], - ['(_' , ''%domain.domain_css ], - ['_)' , '' ], - ['<_' , ''%domain.domain_css ], - ['_>' , '' ] - ] - - # Replace marker in string's article (wip_html) - for marker in marks_html: - wip_tmp = wip_tmp.replace(marker[0], marker[1]) - - wip_html = wip_tmp - - -#========# -# Quotes # -#========# -#======================== # -# Loop lines in article # -# For each quote, convert # -# (Decode base64, HTML) # -#-------------------------# -def wip_quotes(wip_lines): - global wip_html, quote_css - - wip_html = '' - quote = False - - for line in wip_lines: - # Starting quote marker - if re.match(markers_reg[1][0], line): - get_css(line) - quote_css = css_set - quote = True - continue - - # Ending quote marker - elif re.match(markers_reg[1][1], line): - quote = False - continue - - # In quote, Should be base64 line containing quote - # Call convert_quote() to create quote_html - # Replace line, with html_quote - if quote: - if re.match('B64\|', line): - line = line.replace('B64|', '') - line = line.replace('|B64', '') - convert_from_b64(line) - bQuote = src_content - convert_quote(bQuote.rsplit('\n')) - line = quote_html - - # Create new HTML article - if wip_html: wip_html = '%s\n%s'%(wip_html, line) - else : wip_html = line - -#============================# -# Convert brut Quote to HTML # -#----------------------------# -def convert_quote(bQuote): - global quote_html - - quote_html = '' - cite = link = lang = year = book = '' - author_title = author_show = author_html = '' - cite_html = lang_html = figca_html = '' - year_show = book_show = '' - - # Set Datas (if exists) - for line in bQuote: - # Get Datas from markers in quote - if line.startswith('_cite:'): - cite = quote_data(line) - elif line.startswith('_link:'): - link = quote_data(line) - cite_html = ' cite="%s"'%link - elif line.startswith('_lang:'): - lang = quote_data(line) - lang_html = ' lang="%s"'%lang - elif line.startswith('_year:'): - year = quote_data(line) - year_show = ' (%s)'%year - elif line.startswith('_book:'): - book = quote_data(line) - book_show = ' - %s'%book - - # Only accepted marker: paragraphs - elif re.match(markers_reg[0][0], line): - get_css(line) - line = '

'%css_set - if quote_html: quote_html = '%s\n%s'%(quote_html, line) - else : quote_html = line - elif re.match(markers_reg[0][1], line): - line = '

' - quote_html = '%s\n%s'%(quote_html, line) - - # main quote content - else: - if quote_html: quote_html = '%s\n%s'%(quote_html, line) - else : quote_html = line - - if not cite : author_show = 'NC' - if year and book: author_show = '%s%s%s'%( - author_show, book_show, year_show - ) - - if cite or link: - author_show = '%s%s'%(cite, author_show) - author_title = ' title="%s"'%author_show - - # Create main blockquote - blockquote = '
\n%s
'%( - quote_css, author_title, cite_html, lang_html, - quote_html - ) - - if cite: - if link: author_html = '%s'%( - quote_css, link, author_show - ) - else : author_html = author_show - - if year: author_html = ''%( - year, author_html - ) - - figca_html = '
\n'%quote_css + \ - '\n%s\n\n'%( - quote_css, author_html - ) + \ - '
' - - quote_html = '
\n%s\n%s\n
'%( - quote_css, blockquote,figca_html - ) + if do_wip: + # Show message if wip was done + if hash_wip: + if not is_file: tyto.exiting("1", wip_uri, False) + if is_new: tyto.exiting("9", '', False) + wip_article() else: - if year: quote_html = ''%( - year, blockquote - ) - else : quote_html = blockquote + tyto.exiting("20", date_wip, True) -#=================================# -# Return datas in quote from line # -#---------------------------------# -def quote_data(line): - return line.split(' ', 1)[1].lstrip() +#===================# +# Start wip modules # +# Set Db # +#-------------------# +def wip_article(): + print('Convert') - -#=========================# -# Convert files_links # -# from header "file: xxx" # -#-------------------------# -def wip_files_links(article): - global wip_html - - flink_fmt = '%s' - all_vars = set(globals()) - - for var in all_vars: - if var.startswith('file_'): - flink = globals()[var] - flink_b64 = flink_fmt%(domain.domain_css, - flink[2], - flink[1], - flink[0] - ) - convert_to_b64(flink_b64) - article = article.replace('__%s'%flink[0], b64_content) - - wip_html = article - - -#==========================# -# Convert images # -# from header "image: xxx" # -# Get parameters from line # -#--------------------------# -def wip_images(article): - global wip_html - - regex_dw = r"([0-9]+)([a-z]+)" - wip_html = '' - image_fmt = '%s' - img_style = '%s' # %(wh_style) style="..." if width and/or height - - all_vars = set(globals()) - - for var in all_vars: - if var.startswith('image_'): - image = globals()[var] - - # Copy file in wip - image_src = '%s%s%s'%( - domain.domain_articles, check.post_dir, image[1] - ) - image_dst = '%s%s%s'%( - domain.srv_wip, check.post_dir, image[1] - ) - shutil.copy2(image_src, image_dst) - # log - msg_log = 'Wip > Image: %s > %s'%(image_src, image_dst) - log.append_f(check.post_logs, msg_log, 0) - - # Search in article lines for _image: - for line in article.rsplit('\n'): - if not line.startswith('_image:'): - if wip_html: wip_html = '%s\n%s'%(wip_html, line) - else : wip_html = line - - elif line.startswith('_image:%s'%image[0]): - width = height = set_css = target = '' - image_html = '' - wh_style = '' # width and/or height parameters - - # Get parameters and set values for this marker - image_params = (line.rsplit(' ')) - for param in image_params: - # CSS - if param.startswith('c='): - set_css = param.rsplit('=')[1] - - # Width - elif param.startswith('w='): - width = param.rsplit('=')[1] - if not width: width = '' - elif width.isdigit(): - width = 'width:%spx;'%width - else: - wspl = re.match(regex_dw, width, re.I).groups() - width = 'width:%s;'%width - - # Height - elif param.startswith('h='): - height = param.rsplit('=')[1] - if not height: height = '' - elif height.isdigit(): - height = 'height:%spx;'%height - else: - hspl = re.match(regex_dw, height, re.I).groups() - height = 'height:%s;'%height - - # Target - elif param.startswith('t='): - target = param.rsplit('=')[1] - if not target: target = image[1] - - # Check values and construct HTML - if not set_css: set_css = domain.domain_css - if width and height: wh_style = 'style="%s%s" '%(width,height) - elif width : wh_style = 'style="%s" '%width - elif height : wh_style = 'style="%s" '%height - - image_html = image_fmt%(set_css, - image[2], image[2], - img_style%wh_style, - image[1] - ) - - # Create Target link if t= - if target: - line = '%s'%( - set_css, target, image_html - ) - else: - line = image_html - - # Replace line - if wip_html: wip_html = '%s\n%s'%(wip_html, line) - else : wip_html = line - - -#=============================================# -# Convert line _brut: to pre HTML, like bCode # -#---------------------------------------------# -def wip_bruts(article): - global wip_html - - wip_html = '' - all_vars = set(globals()) - - for var in all_vars: - if var.startswith('brut_'): - brut = globals()[var] - - # Search in article lines for _image: - for line in article: - if not line.startswith('_brut:'): - if wip_html: wip_html = '%s\n%s'%(wip_html, line) - else : wip_html = line - - elif line.startswith('_brut:%s'%brut[0]): - # Open target file - brut_file = '' - brut_html = '' # brut file contents - brut_uri = brut[1][1:len(brut[1])] # No need first "/" - brut_file = '%s%s'%(domain.domain_articles, brut_uri) - brut_datas = open(brut_file, 'r').read() - - # Convert each lines to HTML, add to string - for ln, bline in enumerate(brut_datas.rsplit('\n'), 1): - brut_line_html = '
%s
'%( - ln, bline, bline - ) - if brut_html: brut_html = '%s\n%s'%(brut_html,brut_line_html) - else : brut_html = brut_line_html - - # Get CSS, if exists, before creating last brut_html - get_css(line) - - # Add first and last HTML tags to string - brut_html = '\n'%( - css_set, brut[2]) + \ - '%s\n'%brut_html - - # Replace line - if wip_html: wip_html = '%s\n%s'%(wip_html, brut_html) - else : wip_html = brut_html - - -#=========================# -# Done when command check # -# - convert_bcodes() # -# - convert_icodes() # -#=========================# -#====================================# -# Protect bCodes contents to base64 # -# fm: First marker ; lm: last marker # -#-----------------------------------=# -def convert_bcodes(article, fm, lm, css): - global article_temp - - article_temp = '' - bCode = False - bCode_lines = '' - bCode_ln = 0 - - for line in article: - if line.startswith(fm): - bCode = True - if article_temp: article_temp = '%s\n%s'%(article_temp, line) - else : article_temp = line - continue - - if line.startswith(lm): - bCode = False - - convert_to_b64(bCode_lines) - bCode_lines = '' - article_temp = '%s\n%s\n%s'%( - article_temp, b64_content, line - ) - continue - - if bCode: - bCode_ln += 1 - line = '
%s
'%( - bCode_ln, line, line - ) - if bCode_lines: bCode_lines = '%s\n%s'%(bCode_lines, line) - else : bCode_lines = line - else: - if article_temp: article_temp = '%s\n%s'%(article_temp, line) - else : article_temp = line - -#====================================# -# Protect iCodes contents to base64 # -# fm: First marker ; lm: last marker # -#-----------------------------------=# -def convert_icodes(article, css): - import re - global article_temp - - article_temp = '' - fm1 = '<_' - lm1 = '_>' - fm2 = '(_' ; fm2_r = '\(_' - lm2 = '_)' ; lm2_r = '_\)' - - for line in article: - # Specific marker format - if fm1 and lm1 in line: - iCodes = re.findall(r"%s(.*?)%s"%(fm1,lm1), line) - for iCode in iCodes: - convert_to_b64(iCode) - line = line.replace(fm1 + iCode + lm1, - fm1 + b64_content + lm1 - ) - - # Legacy marker format - if fm2 and lm2 in line: - iCodes = re.findall(r"%s(.*?)%s"%(fm2_r,lm2_r), line) - for iCode in iCodes: - convert_to_b64(iCode) - line = line.replace(fm2 + iCode + lm2, - fm2 + b64_content + lm2 - ) - - article_temp = '%s%s\n'%( - article_temp, line - ) - - -#=======================================# -# Convert all base64 to legacy contents # -#---------------------------------------# -def convert_all_b64(wip_lines): - global wip_html - - wip_tmp = '' - - for line in wip_lines: - b64s = re.findall(r'B64\|(.*?)\|B64', line) - for b64 in b64s: - convert_from_b64(b64) - line = line.replace('B64|%s|B64'%b64, src_content) - if wip_tmp: wip_tmp = wip_tmp + line + '\n' - else : wip_tmp = line + '\n' - - wip_html = wip_tmp - - -#=======# -# TOOLS # -#=======#-------------------------------------------------------------- -#==========================# -# Get Writer's CSS config # -# For compatible's markers # -# css_gen: generic value # -#--------------------------# -def get_css(line): - global css_set - try : css_set = line.split(" ")[1] - except: css_set = domain.domain_css - - -#=====================================# -# Base64 # -# Mainly used when article is checked # -#-------------------------------------#-------------------------------- -#===========================# -# Convert content TO base64 # -#---------------------------# -def convert_to_b64(post_content): - import base64 - global b64_content - - post_content_base64 = '' - content_bytes = post_content.encode("utf8") - base64_bytes = base64.b64encode(content_bytes) - b64_content = 'B64|' + base64_bytes.decode("utf8") + '|B64' - -#================================# -# Convert FROM base64 to content # -#--------------------------------# -def convert_from_b64(post_content): - import base64 - global src_content - - post_content_src = '' - content_bytes = post_content.encode("utf8") - base64_bytes = base64.b64decode(content_bytes) - src_content = base64_bytes.decode("utf8") - - -#=======================# -# Tabulations formating # -#-----------------------# -def tab_article(article): - global wip_html - - wip_tmp = '' - tab = 0 - - for line in article: - if len(line) == 0: continue - - if line.startswith('