Starting new code pre v2

This commit is contained in:
Cyrille L 2023-09-22 11:52:44 +02:00
parent 75b42a68d4
commit 6a17add248
40 changed files with 1671 additions and 9248 deletions

View File

@ -1,13 +1,13 @@
# Changelog # Changelog
Tyto - Littérateur Tyto - Littérateur
- Repository: https://git.a-lec.org/echolib/tyto-litterateur - Repository:
- Issues: https://git.a-lec.org/echolib/tyto-litterateur/-/issues - Issues:
- Changelog: https://git.a-lec.org/echolib/tyto-litterateur/-/blob/master/CHANGELOG.md - Changelog:
- License: https://git.a-lec.org/echolib/tyto-litterateur/-/blob/master/LICENSE - License:
- Documentation: https://tyto.echolib.re - Documentation:
## [0.10.6] ## [1.9.0]

View File

@ -1,53 +1,14 @@
# Tyto # Very early IN dev code
- FR. Pour obtenir de l'aide, taper juste la commande tyto This program can ve tested but not at all usable. Lots of work to do...
- EN. To get help, just type tyto.
- - Doc is only in french yet, but Tyto is translated, also for your websites
## Répertoire de code du projet Tyto # Commands
https://git.a-lec.org/echolib/tyto-litterateur
## Documentation officielle
https://tyto.echolib.re (en cours de construction)
## Créer un domaine
````
mkdir -p MONDOMAIN
cd MONDOMAIN
tyto new domain URL
````
# Créer un article
https://tyto.echolib.re/%C3%A9crire/
``` ```
cd articles/ # Get commands list help
tyto new index tyto
tyto edit index.tyto
``` ```
# Vérifier, prévisualiser un article # Working on
``` - Managing domain(s)
tyto check index.tyto - - needs more checks to be validated
tyto wip index.tyto - english logs translation file (French only, for now)
```
# Les modules
https://tyto.echolib.re/usages/modules.html
La barre latérale, le menu, le pied de page et les balises génériques metas
ne seront pas visible localement sans serveur nginx.
Utiliser l'option --static avec la commande wip pour les voir. Attention,
utiliser la commande publish après avoir utilisé l'option --static sur wip
mettra en ligne la version statique de la page. Il faut donc avant la
commande publish, recommencer la commande wip sur un article sans l'option
--static pour utiliser l'include de nginx (comportement par défaut)
# Publier !
```
# La première fois, ou après mise à jour des modules ou des fichiers (logo, css...)
tyto publish template
# Mettre dans le dossier "www" officiel
tyto publish index.tyto
```

View File

@ -1,93 +1,59 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Version: 1.0.0 # Version: 1.9.0
# Tyto - Littérateur # Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org> # Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License # it under the terms of the GNU General Public License as published by
# as published by the Free Software Foundation, either version 3 of the # the Free Software Foundation, either version 3 of the License, or
# License, or of the License, or (at your option) any later version. # (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details. # GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re) # XMPP: echolib (im@echolib.re)
# #
# Description: Main binary to execute # Description: Main binary to execute.
# Import modules and start checking/using arguments
# File: /usr/bin/tyto # File: /usr/bin/tyto
#---------------------------------------------------------------------- #----------------------------------------------------------------------
#------------------------- #-------------------------
# Funny Stats Project # Funny Stats Project
#------------------------- #-------------------------
# Project files : 20 # Project files :
# Project lines : 7508 # Project lines :
# Project comments : 1153 # Project comments :
# Project functions: 109 # Project functions:
# Project program : 5652 # Project program :
# #
# file lines : 93 # file lines :
# file comments : 33 # file comments :
# file functions: 0 # file functions:
# file program : 47 # file program :
#-------------------------- #--------------------------
#======#
# MAIN #
#======#=======================================================================
import sys import sys
sys.path.insert(0, '/var/lib/tyto/program')
#====================#
# MAIN #
# Treat Arguments #
#--------------------#
import logs
if not __name__ == "__main__": if not __name__ == "__main__":
logs.out("14", '', True) print("! Error: '%s' not '%s'"%(__name__, "__main__"))
sys.exit(1)
# Check arguments # Set librairies to import app files
libs = "/var/lib/tyto/program"
trfs = "/var/lib/tyto/translations"
sys.path.insert(0, libs)
sys.path.insert(0, trfs)
# Manage arguments from command line, start process
import args import args
action = args.set_action() args.start_process()
target = args.set_target()
# Check domain
import dom, status
status.domain()
# Command start argument
import check, form, html, new, publish, show, wip, infos, creators
actions = {
"check" : check.manage,
"help" : infos.tyto,
"edit" : show.manage,
"edit-about" : show.manage,
"edit-db" : show.manage,
"edit-wip" : show.manage,
"edit-www" : show.manage,
"force-wip" : wip.manage,
"new" : new.manage,
"publish" : publish.manage,
"preview" : show.manage,
"quick-pub" : publish.manage,
"show" : show.manage,
"show-about" : show.manage,
"show-db" : show.manage,
"show-wip" : show.manage,
"show-www" : show.manage,
"status" : status.check,
"wip" : wip.manage,
}
# Start action
# Argument's Check done in args.py
#---------------------------------
actions[action](target)

View File

@ -1,311 +0,0 @@
#!/bin/bash
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Autocompletion commands
# File: /usr/share/bash-completion/completions/tyto
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines : 311
# file comments : 45
# file functions: 0
# file program : 234
#--------------------------
#=================#
# Actions section #
#=================#============================================================
# Actions: argument 1 #
#---------------------#
_tyto_actions() {
cat <<EOL
check
domains
edit
edit-about
edit-db
edit-wip
edit-www
force-wip
help
new
show
show-about
show-db
show-wip
show-www
preview
publish
quick-pub
status
version
wip
EOL
}
_tyto_actions_only() {
grep -F -q -x "$1" <<EOL
domains
help
version
EOL
}
# Actions for articles and modules
#--------------------------------
_tyto_actions_wp() {
grep -F -q -x "$1" <<EOL
publish
wip
EOL
}
# Actions for edit
#-----------------
_tyto_actions_edits() {
grep -F -q -x "$1" <<EOL
edit
edit-about
edit-db
edit-wip
edit-www
EOL
}
# Actions for show
#-----------------
_tyto_actions_shows() {
grep -F -q -x "$1" <<EOL
show
show-about
show-db
show-wip
show-www
EOL
}
#=================#
# Targets section #
#=================#============================================================
# Targets for articles and modules
#--------------------------------
_tyto_targets_wp() {
cat <<EOL
added
again
footer
metas
navbar
sidebar
stats
template
updated
EOL
find . -type f -name "*.tyto" -printf '%P\n' 2>/dev/null
}
# Targets with quick-pub
#-----------------------
_tyto_targets_qp() {
find . -type f -name "*.tyto" -printf '%P\n' 2>/dev/null
}
# Targets with edit
#------------------
_tyto_targets_edits() {
cat <<EOL
domain
footer
metas
navbar
sidebar
EOL
find . -type f -name "*.tyto" -printf '%P\n' 2>/dev/null
}
# Targets with edit
#------------------
_tyto_targets_shows() {
cat <<EOL
domain
footer
metas
navbar
sidebar
stats
EOL
find . -type f -name "*.tyto" -printf '%P\n' 2>/dev/null
}
# Targets: argument 2 (all + .tyto files)
#----------------------------------------
_tyto_targets() {
cat <<EOL
added
again
domain
footer
metas
navbar
sidebar
stats
template
updated
EOL
find . -type f -name "*.tyto" -printf '%P\n' 2>/dev/null
}
# Targets: only with action "new"
#--------------------------------
_tyto_targets_new() {
cat <<EOL
domain
footer
metas
navbar
sidebar
sitemap
EOL
}
# Targets to NOT activate --force
#--------------------------------
_tyto_targets_not_options() {
grep -F -q -x "$1" <<EOL
added
again
domain
footer
metas
navbar
sidebar
stats
template
updated
EOL
}
#=================#
# Options section #
#=================#============================================================
_tyto_options() {
cat <<EOL
--static
EOL
}
# Only with [publish template]
_tyto_options_pt() {
cat <<EOL
--no-mods
EOL
}
#=====================#
# Main autocompletion #
#=====================#========================================================
_tyto_completions() {
local cur
cur="${COMP_WORDS[COMP_CWORD]}"
case $COMP_CWORD in
# Actions
1)
COMPREPLY=( $(compgen -W "$(_tyto_actions)" -- ${cur}) )
return 0
;;
# Targets
2)
local prev="${COMP_WORDS[COMP_CWORD-1]}"
# With action "new"
if [ "$prev" == "new" ];then
COMPREPLY=( $(compgen -W "$(_tyto_targets_new)" -- ${cur}) )
return 0
elif [ "$prev" == "quick-pub" ] ||
[ "$prev" == "preview" ];then
COMPREPLY=( $(compgen -W "$(_tyto_targets_qp)" -- ${cur}) )
return 0
elif [ "$prev" == "force-wip" ];then
COMPREPLY=( $(compgen -W "$(_tyto_targets_qp)" -- ${cur}) )
return 0
# With action "edit"
elif _tyto_actions_edits "$prev";then
COMPREPLY=( $(compgen -W "$(_tyto_targets_edits)" -- ${cur}) )
return 0
# With action "show"
elif _tyto_actions_shows "$prev";then
COMPREPLY=( $(compgen -W "$(_tyto_targets_shows)" -- ${cur}) )
return 0
# With wip/publish only
elif _tyto_actions_wp "$prev";then
COMPREPLY=( $(compgen -W "$(_tyto_targets_wp)" -- ${cur}) )
return 0
# When action is alone
elif ! _tyto_actions_only "$prev";then
COMPREPLY=( $(compgen -W "$(_tyto_targets)" -- ${cur}) )
return 0
fi
;;
# Optionss
3)
local prev1="${COMP_WORDS[COMP_CWORD-1]}"
local prev2="${COMP_WORDS[COMP_CWORD-2]}"
if [ "$prev2" == "wip" ];then
if ! _tyto_targets_not_options "$prev1";then
COMPREPLY=( $(compgen -W "$(_tyto_options)" -- ${cur}) )
return 0
fi
# Only with [publish template]
elif [ "$prev2" == "publish" ] && \
[ "$prev1" == "template" ];then
COMPREPLY=( $(compgen -W "$(_tyto_options_pt)" -- ${cur}) )
return 0
fi
;;
esac
}
complete -F _tyto_completions 'tyto'

View File

@ -1,14 +0,0 @@
# Changelog
Tyto - Littérateur
- Repository: https://git.a-lec.org/echolib/tyto-litterateur
- Issues: https://git.a-lec.org/echolib/tyto-litterateur/-/issues
- Changelog: https://git.a-lec.org/echolib/tyto-litterateur/-/blob/master/CHANGELOG.md
- License: https://git.a-lec.org/echolib/tyto-litterateur/-/blob/master/LICENSE
- Documentation: https://tyto.echolib.re
## [1.0.0]
- (2023.05.09)
- - Official first public release

View File

@ -1,661 +0,0 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
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 <https://www.gnu.org/licenses/>.
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
<https://www.gnu.org/licenses/>.

View File

@ -1,53 +0,0 @@
# Tyto
- FR. Pour obtenir de l'aide, taper juste la commande tyto
- EN. To get help, just type tyto.
- - Doc is only in french yet, but Tyto is translated, also for your websites
## Répertoire de code du projet Tyto
https://git.a-lec.org/echolib/tyto-litterateur
## Documentation officielle
https://tyto.echolib.re (en cours de construction)
## Créer un domaine
````
mkdir -p MONDOMAIN
cd MONDOMAIN
tyto new domain URL
````
# Créer un article
https://tyto.echolib.re/%C3%A9crire/
```
cd articles/
tyto new index
tyto edit index.tyto
```
# Vérifier, prévisualiser un article
```
tyto check index.tyto
tyto wip index.tyto
```
# Les modules
https://tyto.echolib.re/usages/modules.html
La barre latérale, le menu, le pied de page et les balises génériques metas
ne seront pas visible localement sans serveur nginx.
Utiliser l'option --static avec la commande wip pour les voir. Attention,
utiliser la commande publish après avoir utilisé l'option --static sur wip
mettra en ligne la version statique de la page. Il faut donc avant la
commande publish, recommencer la commande wip sur un article sans l'option
--static pour utiliser l'include de nginx (comportement par défaut)
# Publier !
```
# La première fois, ou après mise à jour des modules ou des fichiers (logo, css...)
tyto publish template
# Mettre dans le dossier "www" officiel
tyto publish index.tyto
```

View File

@ -1,224 +0,0 @@
/*
* All class / ID used by Tyto - Littérateur in a page
* DOMAIN MUST be changed by domain css set in configuration
*/
/* include header to footer */
div#site_container {
}
/* Include article + sidebar */
div#article_sidebar_container {
}
/*=====================================================================
* Header
*/
header#header_page {
}
/* Block */
div#site_logo {
}
a#site_logo_link {
}
img#site_logo_image {
}
/* Block */
div#site_infos {
}
a#site_link {
}
h1#site_title {
}
p#site_about {
}
/*=====================================================================
* navbar
*/
nav#site_menu {
}
menu#site_menu_items {
}
li.site_menu_item {
}
a.site_menu_link {
}
/*=====================================================================
* article
*/
article#article_main {
}
/* article title */
h2#main_title {
}
/* Writer titles*/
h3.title_3 {
}
h4.title_4 {
}
h5.title_5 {
}
h6.title_6 {
}
/* Between every <h3-6> IF CONTENTS */
div.contents {
}
div.contents_2 {
}
div.contents_3 {
}
div.contents_4 {
}
div.contents_5 {
}
/* Default if not set in post */
p.DOMAIN {
}
br.DOMAIN {
}
a.link {
}
a.link-file {
}
/* When block quote with _cite:*/
a.figc {
}
a.anchor_link {
}
abbr.DOMAIN {
}
img.DOMAIN_image {
}
ul.DOMAIN {
}
li.DOMAIN {
}
/* Words tags*/
code.icode {
}
strong.DOMAIN {
}
b.DOMAIN {
}
em.DOMAIN{
}
i.DOMAIN {
}
del.DOMAIN {
}
u.DOMAIN {
}
cite.DOMAIN {
}
span.custom {
}
/* Block-code */
code.DOMAIN {
}
pre.bcode {
}
p.bcode {
}
/* section for author and date */
div#article_infos {
}
span#article_author {
}
span#article_pub {
}
span#article_code {
}
a#article_code_link {
}
/* Sitemap */
ul.sitemap {
}
/*=====================================================================
* sidebar
*/
aside#sidebar {
}
h2#sidebar_title {
}
ul#sidebar_list {
}
li.sidebar_item {
}
a.sidebar_item_link {
}
h3.sidebar_item_title {
}
p.sidebar_item_about {
}
/*=====================================================================
* footer
*/
footer#footer_page {
}
/* container for footer_infos + footer_references */
div#footer_container {
}
/* Block*/
div#footer_infos {
}
h2#footer_site_title {
}
p#footer_about {
}
/* Block */
div#footer_references {
}
ul.footer_items {
}
li.footer_item {
}
a.footer_item_link {
}
/* Block */
div#footer_credits {
}
p.footer_copyright {
}
p.footer_generator {
}

View File

@ -1,84 +0,0 @@
# Home Domain
directory = ""
database = ""
# Local user configuration
lang_sys = ""
local_user = ""
lang_logs = ""
articles_db_d = ""
# Working directories
articles_d = ""
files_d = ""
images_d = ""
modules_d = ""
# Modules files
navbar_f = ""
sidebar_f = ""
metas_f = ""
footer_f = ""
# Domain
shortname = ""
www_url = ""
wip_url = ""
# Servers directories
srv_root = "/var/www/"
srv_domain = "
srv_wip = ""
srv_wip_tpl_d = ""
srv_wip_images_d = ""
srv_wip_files_d = ""
srv_www = ""
srv_www_tpl_d = ""
srv_www_images_d = ""
srv_www_files_d = ""
# Servers files (wip)
wip_favicon_f = ""
wip_logo_f = ""
wip_css_f = ""
wip_navbar_f = ""
wip_sidebar_f = ""
wip_metas_f = ""
wip_footer_f = ""
wip_stats_f = ""
# Servers files (www)
www_favicon_f = ""
www_logo_f = ""
www_css_f = ""
www_navbar_f = ""
www_sidebar_f = ""
www_metas_f = ""
www_footer_f = ""
www_stats_f = ""
www_rss_f = ""
# Domain user's settings
favicon = "favicon.png"
logo = "logo.png"
styles = "styles.css"
rss = "rss.xml"
rss_items = 100
title = ""
date = ""
about = ""
lang_site = ""
mail = ""
tags = ""
license = "gfdl-1.3"
license_url = ""
legal_url = ""
terms_url = ""
css = "tyto"
sep = "-"
article_code = True
relme = ""
sidebar_title = ""
sidebar_items = 6
activated = False

View File

@ -1,19 +1,19 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Tyto - Littérateur # Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org> # Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License # it under the terms of the GNU General Public License as published by
# as published by the Free Software Foundation, either version 3 of the # the Free Software Foundation, either version 3 of the License, or
# License, or of the License, or (at your option) any later version. # (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details. # GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#---------------------------------------------------------------------- #----------------------------------------------------------------------
@ -26,149 +26,77 @@
#------------------------- #-------------------------
# Funny Stats Project # Funny Stats Project
#------------------------- #-------------------------
# file lines : 174 # file lines :
# file comments : 29 # file comments :
# file functions: 2 # file functions:
# file program : 135 # file program :
#-------------------------- #--------------------------
import sys
import os, sys import langs, tyto, debug, help, new, check, userset, show
import infos
try:
action
target
except:
# Arguments from command line
# tyto [action] [target]
#----------------------------
actions = \
(
'check',
'edit',
'edit-db',
'edit-wip',
'edit-www',
'force-wip',
'new',
'preview',
'publish',
'quick-pub',
'show',
'show-db',
'show-wip',
'show-www',
'status',
'wip',
)
quicks = \
(
'force-wip',
'quick-pub',
)
options = \
(
'--static',
)
pass_actions = ('new')
# Actions that needs to check for article's database
pass_db = \
(
'check',
'edit',
'edit-db',
'edit-wip',
'edit-www',
'force-wip',
'publish',
'preview',
'quick-pub',
'show',
'show-about',
'show-db',
'show-wip',
'show-www',
'status',
'wip',
)
pass_targets = \
(
'added',
'again',
'updated',
'domain',
'footer',
'metas',
'navbar',
'sidebar',
'sitemap',
'stats',
'template'
)
pass_status = \
(
'domain',
)
multi_chk = \
(
'added',
'again',
'updated'
)
helps = \
(
'domains',
'version',
'help'
)
# action #==================#
#------- # Action Arguments #
#------------------#
def get_action():
global action
try: action = sys.argv[1] try: action = sys.argv[1]
except: action = '' except: action = ""
act_err = False
# With no argument, show help
if not action:
infos.tyto('full')
sys.exit(0)
elif action in helps:
infos.tyto(action)
# Unused argument [action]
elif not action in actions:
act_err = True
# target
#-------
try:
target = sys.argv[2]
except:
infos.tyto('full')
sys.exit(0)
# options #==================#
try: option = sys.argv[3] # Target arguments #
except: option = '' #------------------#
def get_target():
global target
try: target = sys.argv[2]
except: target = ""
# Set action and target for binary
def set_action():
return(action)
def set_target(): #================================#
return(target) # Searching options in arguments #
#--------------------------------#
def get_options():
global dlogs, force, erron
dlogs = force = erron = False
for arg in range(1, len(sys.argv)):
if sys.argv[arg] in tyto.debug_options: dlogs = True
if sys.argv[arg] in tyto.force_options: force = True
if sys.argv[arg] in tyto.debug_errors: erron = True
#===========#
# Show logs #
#-----------#
def valid_action():
global action
if not action in tyto.actions:
debug.out(1, "[action]", action, dlogs,2, False)
action = "help"
#==============#
# Start action #
#--------------#
def start_process():
# Set Lang logs
langs.load_logs_lang()
get_options()
get_action()
get_target()
valid_action()
do = {
"help" : help.show,
"check" : check.manage,
"new" : new.manage,
"set" : userset.manage,
"show" : show.manage,
}
do[action](action, target)

File diff suppressed because it is too large Load Diff

View File

@ -1,241 +0,0 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib@dismail.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Manage 'creators' argument.
# Create articles
# File: /var/lib/tyto/program/creators.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines : 241
# file comments : 41
# file functions: 3
# file program : 182
#--------------------------
import os, importlib, datetime, subprocess
import args, dom, db, langs, tyto, check, wip, logs
#========================#
# Manage action [create] #
#------------------------#
def manage(target):
target = args.target
creators = {
"sitemap" : create_sitemap,
}
try: creators[target](target)
except: logs.out("28", "%s + %s"%(args.action, args.target), True)
#=====================#
# Set and return date #
#---------------------#
def nowdate():
now = datetime.datetime.now()
return(now.strftime('%Y-%m-%d'))
#============================#
# Create sitemap.tyto file #
# Then check it, and wip it #
# ! sitemap is the "www" one #
# seen in 'wip' server #
#----------------------------#
def create_sitemap(target):
dom.valid()
# Define sitemap.tyto
sitemap_tyto = \
'# %s Tyto - Littérateur [tyto new sitemap]\n'%langs.site.sitemap_gen + \
'# NoSitemap\n' + \
'title: %s (%s %s)\n'%(langs.site.sitemap_t, '%s', langs.site.links) + \
'about: %s Tyto - Littérateur\n'%langs.site.sitemap_gen + \
'author: Tyto\n' + \
'tags: sitemap\n' + \
'date: %s\n'%nowdate() + \
'\n' + \
'%s\n' + \
'-----\n' + \
'\n' + \
'%s\n' + \
'|\n' + \
'<hr class="hr">\n' + \
'|\n' + \
'\n' + \
'%s\n'
tab = 8
uri_dir_set = ""
# Contents in article's Header
links = ""
# Index of all links in article
index_l = '-( index\n= <a href="#index">/</a>'
# All links in sitemap
contents = '-( sitemap\n= / <z id="index"></a>'
# Not real articles folder
forbid_dir = (
dom.files_d,
dom.images_d,
dom.modules_d
)
# Get all .tyto files from domain
nbr_files = 0
for r, dirs, files in os.walk(os.getcwd()):
if r.startswith(forbid_dir):
continue
# Take only .tyto files
for f in files:
if not f.endswith(".tyto"):
continue
try:
uri_file = r.rsplit(dom.articles_d)[1]
uri_file = os.path.join(uri_file, f)
except:
uri_file = f
uri_dir = uri_file.rsplit(f)[0]
if not uri_dir:
uri_dir = "~/"
# Try to load Article Database
args.action = "check"
args.target = uri_file
importlib.reload(db)
if not db.exists:
continue
else:
try:
db.hash_www
db.sitemap
if not db.sitemap:
continue
except:
continue
# Count
nbr_files += 1
# create defined link
if not links:
links = \
"link: %s\n%s%s\n%s%s\n"%(
db.title, tab * " ", db.short_srv, tab * " ", db.about
)
else:
links = \
"%s\nlink: %s\n%s%s\n%s%s\n"%(
links,
db.title, tab * " ",
db.short_srv, tab * " ", db.about
)
# Create list link line
curr_dir = uri_dir.count("/")
root_dir = uri_dir.rsplit("/")[0]
ranc_dir = root_dir.replace(" ", "_")
try: prev_dir
except: prev_dir = curr_dir
try: name_dir
except: name_dir = root_dir
#print(":",prev_dir, name_dir, curr_dir, root_dir)
#print(": %s"%(uri_dir.rsplit("/")[int(curr_dir - 1)]))
#print(">", subdirs, uri_dir.rsplit("/"))
#print(":", prev_dir, curr_dir)
if name_dir != root_dir:
index_l = '%s\n= <a href="#%s">%s</a>'%(
index_l,
ranc_dir,
root_dir
)
contents = '%s\n%s [%s] <a id="%s"></a>'%(
contents,
int(curr_dir) * "=",
root_dir,
ranc_dir
)
name_dir = root_dir
prev_dir = curr_dir
if prev_dir != curr_dir:
sanc_dir = uri_dir.rsplit("/")[int(curr_dir - 1)].replace(" ", "_")
index_l = '%s\n%s <a href="#%s">%s</a>'%(
index_l,
int(curr_dir) * "=",
sanc_dir,
uri_dir.rsplit("/")[int(curr_dir - 1)]
)
contents = '%s\n%s [%s] <a id="%s"></a>'%(
contents,
int(curr_dir) * "=",
uri_dir.rsplit("/")[int(curr_dir - 1)],
sanc_dir
)
prev_dir = curr_dir
contents = "%s\n%s _%s"%(
contents,
int(curr_dir + 1) * '=',
db.title
)
# Ending markers
index_l = "%s\n-)"%index_l
contents = "%s\n-)"%contents
# Fill new sitemap.tyto and create
sitemap_tyto = \
sitemap_tyto%(
nbr_files,
links,
index_l,
contents
)
sitemap_file = "%ssitemap.tyto"%dom.articles_d
tyto.set_file(sitemap_file, "New", sitemap_tyto)
# Check and wip
print()
www = subprocess.run(
[
'/usr/bin/tyto',
'force-wip',
'sitemap.tyto'
],
)

View File

@ -1,206 +0,0 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Load article's database and check validity
# File: /var/lib/tyto/program/db.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines : 206
# file comments : 37
# file functions: 1
# file program : 152
#--------------------------
import os
import args, logs, dom, form, tyto, check, publish
remove = exists = post = corrupt = file_wip = file_www = False
chk_again = chk_updated = False
wip_again = wip_added = wip_updated = False
www_again = www_added = www_updated = False
if dom.hole:
logs.out("13", '', True)
# target needs db (file).
# action like show, wip, edit-db
# not domain, all, again...
if args.target \
and args.action in args.pass_db \
and not args.target in args.pass_targets:
# Domain must be valid
if not dom.exists: logs.out("10", '', True)
uri_file = '%s%s'%(dom.articles_d, args.target)
uri_id = tyto.get_filesum(uri_file, False)
# Set DB file
config = '%s%s.config'%(dom.articles_db_d, uri_id)
if tyto.exists(config):
exists = True
try:
exec(open(config).read())
except:
exists = False
else:
exists = False
# Article file exists
if tyto.exists(uri_file):
post = True
hash_post = tyto.get_filesum(uri_file, True)
else:
remove = True
# Check if database config is valid (contains values)
if exists:
values = \
(
'post_id',
'post_src',
'post_wip',
'static_wip',
'post_www',
'static_www',
'direc_src',
'short_src',
'short_srv',
'sub_uri',
'http_wip',
'http_www',
'date_chk',
'hash_chk',
'date_wip',
'hash_wip',
'date_www',
'hash_www',
'title',
'about',
'author',
'meta_tags',
'date',
'snpic',
'sitemap',
'uris',
'uniq_anchors',
'uniq_abbrs',
'uniq_links',
'uniq_images',
'uniq_files',
'uniq_raws',
'comments',
'tags',
'words',
'titles',
'paragraphs',
'links',
'images',
'anchors',
'abbrs',
'strongs',
'bolds',
'emphasis',
'italics',
'dels',
'underlines',
'cites',
'customs',
'icodes',
'bcodes',
'quotes',
'lists',
'files',
'raws',
'codes',
)
# Set exist for wip and www files
for value in values:
try:
eval(str(value))
except:
remove = True
corrupt = True
break
# Remove DB if unused source article or corrupted DB
if remove and exists:
os.remove(config)
exists = False
logs.out("23", config, False)
old_chk = old_wip = old_www = False
no_chk = no_wip = no_www = False
sync_srvs = False
# Set Statuses for chk, wip, www
if exists:
# File exists on servers
if tyto.exists(post_wip): file_wip = True
if tyto.exists(post_www): file_www = True
# Statuses not set in Db
if not hash_chk: no_chk = True
if not hash_wip: no_wip = True
if not hash_www: no_www = True
# Source article has changed
if hash_post != hash_chk: old_chk = chk_updated = True
if hash_chk: chk_again = True
# WIP article is old
if not old_chk:
if hash_wip and hash_chk != hash_wip: old_wip = wip_updated = True
if no_wip: wip_added = True
if hash_wip: wip_again = True
if not file_wip:
old_wip = wip_updated = True
wip_added = True
wip_again = True
# WWW article is old
if not old_wip:
if hash_www and hash_www != hash_wip: old_www = www_updated = True
if hash_www: www_again = True
if no_www: www_added = True
if not file_www:
old_www = www_updated = True
www_added = True
www_again = True
# Article is updated on both servers
if hash_chk == hash_wip == hash_www: sync_srvs = True
#=========================#
# Show title and uri file #
#-------------------------#
def show_title():
try:
print('"%s" > %s'%(title, uri_file))
except:
return

View File

@ -0,0 +1,118 @@
#!/usr/bin/env python3
# Tyto - Littérateur
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Add more logs when debug is set in command line
# File: /var/lib/tyto/program/debug.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines :
# file comments :
# file functions:
# file program :
#--------------------------
import sys
import langs, args
#===================================#
# Show logs if "show" is True #
# -D argument for specific ones #
# color is for "*" in message #
# - 3 colors levels: #
# - - 0 = Green #
# - - 1 = Yellow #
# - - 2 = Red #
# stop to sys exit with nbr if True #
#-----------------------------------#
def out(nbr, var, val, show, color, stop):
args.get_options()
if not show and not args.dlogs: return # Show Very less logs
if args.erron and color == 0: return # Show only warn and error logs
# COlors
CS = '\033[0;0m' # Unset
CL = '\033[0;2m' # Gray
CB = '\033[1;34m' # Blue
CC = '\033[1;36m' # Cyan
CR = '\033[1;31m' # Red
CG = '\033[1;32m' # Green
CY = '\033[1;33m' # Yellow
CP = '\033[1;35m' # Pink
# Color of "*"
SC = CL # Default gray
if color == 0: SC = CG
elif color == 1: SC = CY
elif color == 2: SC = CR
# Messages for logs
messages = \
{
# ERRORS (1-100)
1 : langs.logs.err_arg,
2 : langs.logs.err_hole,
3 : langs.logs.err_dir,
4 : langs.logs.err_cd,
5 : langs.logs.err_no_file,
6 : langs.logs.err_no_dir,
7 : langs.logs.err_cr_file,
8 : langs.logs.err_lang,
50 : langs.logs.err_date,
# WARNINGS (100-200)
100 : langs.logs.warn_no_dom,
101 : langs.logs.domain_created,
102 : langs.logs.reset_dom,
103 : langs.logs.website_lang,
104 : langs.logs.domains_no,
# Great (200-255)
200 : langs.logs.load_file,
201 : langs.logs.lang_logs_sys,
202 : langs.logs.domain_found,
203 : langs.logs.created_dir,
204 : langs.logs.domain_updated,
205 : langs.logs.domain_new,
206 : langs.logs.created_file,
207 : langs.logs.updated_file,
208 : langs.logs.website_lang,
255 : langs.logs.later,
}
# Print, acoording to parameters
print("%s*%s %s%s%s > %s%s%s < %s%s%s"%(
SC, CS,
CL, messages[nbr], CS,
CB, var, CS,
CC, val, CS
)
)
# Exit if stop = True
if stop:
if nbr >= 200:
nbr = 0
sys.exit(nbr)

View File

@ -1,318 +0,0 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Load domain database and check validity
# File: /var/lib/tyto/program/dom.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines : 318
# file comments : 31
# file functions: 1
# file program : 277
#--------------------------
import os, sys, importlib, langs
import args
try:
ready
except:
lib = 'tyto_domain'
exists = incomplete = active = ready = shortname = corrupt = False
local_user = articles_db_d = False
hole = False
# Set current directory
try:
user_dir
except:
try:
user_dir = os.getcwd() + "/"
except:
hole = True
# Set current user name
try:
user
except:
try:
user = os.environ.get('USER')
except:
user = ''
# Settings for domain, check if db is not corrupted
dom_values = \
(
'directory',
'database',
'local_user',
'lang_sys',
'lang_logs',
'articles_db_d',
'articles_d',
'files_d',
'images_d',
'modules_d',
'navbar_f',
'sidebar_f',
'metas_f',
'footer_f',
'shortname',
'www_url',
'wip_url',
'srv_root',
'srv_domain',
'srv_wip',
'srv_wip_tpl_d',
'srv_wip_images_d',
'srv_wip_files_d',
'srv_www',
'srv_www_tpl_d',
'srv_www_images_d',
'srv_www_files_d',
'wip_favicon_f',
'wip_css_f',
'wip_logo_f',
'wip_navbar_f',
'wip_sidebar_f',
'wip_metas_f',
'wip_footer_f',
'wip_stats_f',
'www_navbar_f',
'www_sidebar_f',
'www_metas_f',
'www_footer_f',
'www_stats_f',
'www_logo_f',
'www_css_f',
'www_rss_f',
'www_favicon_f',
'favicon',
'logo',
'styles',
'rss',
'rss_items',
'title',
'date',
'about',
'lang_site',
'mail',
'tags',
'license',
'license_url',
'legal_url',
'terms_url',
'css',
'sep',
'article_code',
'relme',
'sidebar_title',
'sidebar_items',
'activated'
)
create_files = \
(
'navbar_f',
'sidebar_f',
'metas_f',
'footer_f',
)
wip_html_mods = ()
err_val = (()) # Make a list from values error
if not hole:
home_dir = os.path.expanduser('~')
# Set configuration domain directory
root_dir = user_dir
if '/articles' in user_dir:
root_dir = user_dir.rsplit('/articles')[0] + "/"
# Set configuration domain file
config = '%styto_domain.py'%root_dir
shortname = config
# Set exists if configuration file
if os.path.exists(config):
exists = True
try:
exec(open(config).read())
try:
os.path.exists(articles_d)
if '/articles' in user_dir:
user_uri_dir = user_dir.rsplit(articles_d)[1]
else:
user_uri_dir = ''
os.chdir(articles_d)
except: corrupt = True
except:
corrupt = True
if not args.target in args.pass_targets:
if args.target.startswith("articles/"):
args.target = args.target.rsplit("articles/")[1]
args.target = user_uri_dir + args.target
# For logs: show uri if not shortname known
try: shortname
except: pass
try: active = activated
except: pass
# Check set values configuration
if not corrupt:
for value in dom_values:
try:
eval(str(value))
value_set = True
except:
err_val = err_val + ((value),)
value_set = False
incomplete = True
active = False
#==============================================#
# When an active and complete domain is needed #
#----------------------------------------------#
if exists and not incomplete and not corrupt:
if active:
ready = True
wip_html_mods = \
(
eval(str('wip_navbar_f')),
eval(str('wip_sidebar_f')),
eval(str('wip_metas_f')),
eval(str('wip_footer_f'))
)
www_html_mods = \
(
eval(str('www_navbar_f')),
eval(str('www_sidebar_f')),
eval(str('www_metas_f')),
eval(str('www_footer_f'))
)
metas = \
(
eval(str('metas_f')),
eval(str('wip_metas_f')),
eval(str('www_metas_f'))
)
navbars = \
(
eval(str('navbar_f')),
eval(str('wip_navbar_f')),
eval(str('www_navbar_f'))
)
sidebars = \
(
eval(str('sidebar_f')),
eval(str('wip_sidebar_f')),
eval(str('www_sidebar_f'))
)
footers = \
(
eval(str('footer_f')),
eval(str('wip_footer_f')),
eval(str('www_footer_f')),
)
templates = \
(
eval(str('wip_logo_f')),
eval(str('wip_favicon_f')),
eval(str('wip_css_f')),
eval(str('wip_navbar_f')),
eval(str('wip_sidebar_f')),
eval(str('wip_metas_f')),
eval(str('wip_footer_f')),
eval(str('wip_stats_f')),
eval(str('www_favicon_f')),
eval(str('www_logo_f')),
eval(str('www_css_f')),
eval(str('www_navbar_f')),
eval(str('www_sidebar_f')),
eval(str('www_metas_f')),
eval(str('www_footer_f')),
eval(str('www_stats_f')),
eval(str('www_rss_f')),
)
statistics = \
(
eval(str('wip_stats_f')),
eval(str('www_stats_f')),
)
modules = \
{
"metas" : metas,
"navbar" : navbars,
"sidebar" : sidebars,
"footer" : footers,
"template": templates,
"stats" : statistics,
}
templates_files_wip = \
(
eval(str('wip_favicon_f')),
eval(str('wip_logo_f')),
eval(str('wip_css_f')),
eval(str('wip_navbar_f')),
eval(str('wip_sidebar_f')),
eval(str('wip_metas_f')),
eval(str('wip_footer_f')),
eval(str('wip_stats_f')),
)
templates_files_www = \
(
eval(str('www_favicon_f')),
eval(str('www_logo_f')),
eval(str('www_css_f')),
eval(str('www_navbar_f')),
eval(str('www_sidebar_f')),
eval(str('www_metas_f')),
eval(str('www_footer_f')),
eval(str('www_stats_f')),
eval(str('www_rss_f'))
)
#====================================#
# Check if domain is ready and ready #
#------------------------------------#
def valid():
if incomplete: sys.exit(41)
elif not active: sys.exit(42)
elif not ready: sys.exit(41)

View File

@ -0,0 +1,376 @@
#!/usr/bin/env python3
# Tyto - Littérateur
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Manage configuration domain(s)
# File: /var/lib/tyto/program/domain.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines :
# file comments :
# file functions:
# file program :
#--------------------------
import os, sys, configparser
import debug, tyto, tools, forms, langs
#=========================================================#
# Exit if directory name is compatible with a domain name #
#---------------------------------------------------------#
def compatible_name():
if len(conf_name.rsplit(".")) <= 1:
debug.out(3, "abc.tld", conf_name, True, 2, True)
#================================#
# Load Domain Configuration file #
# As needed, exit if not exists #
#--------------------------------#
def dcf_load():
global dcf
dcf = False
if not dcf_exists():
debug.out(100, conf_name, dcf_uri, True, 1, True)
dcf = configparser.ConfigParser()
dcf.read(dcf_uri)
#=====================================#
# Load User Domain Configuration file #
# As needed, exit if not exists #
#-------------------------------------#
def ult_dcf_load():
global ult_dcf
ult_dcf = False
if not os.path.exists(ult_dcf_uri):
debug.out(100, conf_name, ult_dcf_uri, True, 1, True)
ult_dcf = configparser.ConfigParser()
ult_dcf.read(ult_dcf_uri)
#===================================#
# Load User local Domains List File #
#-----------------------------------#
def ult_dlf_load():
global ult_dlf
ult_dlf = False
ult_dlf = configparser.ConfigParser()
ult_dlf.read(ult_dlf_uri)
#===========================================#
# Check if Domain COnfiguration file exists #
# Show status message only once #
# return True or False
#-------------------------------------------#
def dcf_exists():
global shown_ok, shown_no
if os.path.exists(dcf_uri):
try: shown_ok
except: debug.out(202, conf_name, dcf_uri, True, 0, False)
shown_ok = True
return True
else:
try: shown_no
except: debug.out(100, "False", dcf_uri, True, 1, False)
shown_no = True
return False
#=============================================#
# Ensure domain is valid and ready to be used #
#---------------------------------------------#
def valid_conf():
dcf_load()
try:
dcf_name = dcf.get("DOMAIN", "name")
except:
debug.out(100, conf_name, dcf_uri, True, 1, True)
# Check some values in ult_dcf
ult_dcf_load()
try:
ult_dcf_name = ult_dcf.get("DOMAIN", "name")
ult_dcf_hash = ult_dcf.get("DOMAIN", "hash")
ult_dcf_conf = ult_dcf.get("DOMAIN", "conf")
ult_dcf_root = ult_dcf.get("DOMAIN", "root")
except:
debug.out(100, conf_name, ult_dcf_uri, True, 1, True)
# Compare values (exit if mismatch)
if ult_dcf_name != conf_name or \
ult_dcf_conf != dcf_uri or \
dcf_name != ult_dcf_name:
debug.out(100, conf_name, "?", True, 1, True)
# Check if dcf need to be updated
now_dcf_hash = tools.get_filesum(dcf_uri, True)
if now_dcf_hash != ult_dcf_hash:
dcf_update_values("")
#=========================================#
# Guess and return wip_url from conf_name #
#-----------------------------------------#
def create_wip_url():
wip_url = "https://www-wip.%s/"
len_cn = conf_name.count(".")
# Domain name Format: a.b
if len_cn == 1:
return wip_url%conf_name
# Domain name format: (at least) a.b.c
len_cn = len(conf_name.rsplit(".")[0]) + 1
tld = conf_name[len_cn:]
return wip_url%tld
#==========================================#
# Ask User to create new domain #
# Create NEW #:
# - default Domain Configuration file #
# - default User domain configuration file #
# If not User domains list file, create it #
#------------------------------------------#
def dcf_create():
compatible_name()
# This fonction is only called with "new domain" argument
# If a conf already exists, show important RESET log
if dcf_exists():
debug.out(102, "!?", dcf_uri, True, 1, False)
# Ask User to create new domain. Will exit if not ok.
forms.ask_domain_shortname(conf_name)
# Create default files
tools.create_file(dcf_uri, tyto.ini_domain)
tools.create_dirs(ult_dir)
tools.create_file(ult_dcf_uri, tyto.ini_domain_user)
# User Domains list file
if not os.path.exists(ult_dlf_uri):
tools.create_file(ult_dlf_uri, tyto.ini_domains_list)
# Ask user for domain settings
forms.ask_domain_title()
forms.ask_domain_date()
forms.ask_domain_about()
forms.ask_domain_mail()
forms.ask_domain_tags()
# Set default lang, from config file or system lang
forms.ask_domain_lang()
# Set server directory
forms.ask_domain_server()
#===========================================#
# Set or Update domain configuration values #
#-------------------------------------------#
def dcf_update_values(srv):
# Prepare Domain Configuration File keys values
#-----------------------------------------------
dcf_load()
# Test server directory, and exit if not exists
if not srv: srv = dcf.get("SERVER", "root") # Set from db if unknown
if srv: tools.dir_exists(srv, True)
# Test registred website lang
# change to default lang sys, or "en" if no translation file
langs.load_website_lang()
srv_dom = os.path.join(srv, conf_name + "/")
srv_wip = os.path.join(srv_dom, "wip/")
srv_www = os.path.join(srv_dom, "www/")
favicon = dcf.get("TEMPLATE_FILENAMES", "favicon")
logo = dcf.get("TEMPLATE_FILENAMES", "logo")
styles = dcf.get("TEMPLATE_FILENAMES", "styles")
rss = dcf.get("TEMPLATE_FILENAMES", "rss")
stats = dcf.get("TEMPLATE_FILENAMES", "stats")
www_url = dcf.get("WEBSITE", "www_url")
wip_url = dcf.get("WEBSITE", "wip_url")
sdb_title = dcf.get("WEBSITE_MODULES", "sidebar_title")
usr_mods = os.path.join(dcf_dir + "modules/")
usr_tpl = os.path.join(dcf_dir, "template/")
usr_favicon = os.path.join(usr_tpl, favicon)
usr_logo = os.path.join(usr_tpl, logo)
usr_styles = os.path.join(usr_tpl, styles)
wip_tpl = srv_wip + "template/"
wip_favicon = os.path.join(wip_tpl, favicon)
wip_logo = os.path.join(wip_tpl, logo)
wip_styles = os.path.join(wip_tpl, styles)
wip_rss = os.path.join(wip_tpl, rss)
wip_stats = os.path.join(wip_tpl, stats)
www_tpl = srv_www + "template/"
www_favicon = os.path.join(www_tpl, favicon)
www_logo = os.path.join(www_tpl, logo)
www_styles = os.path.join(www_tpl, styles)
www_rss = os.path.join(www_tpl, rss)
www_stats = os.path.join(www_tpl, stats)
# Update Domain Configuration File
#---------------------------------
dcf.set("DOMAIN", "name", conf_name)
dcf.set("TYTO", "domain_hash", tools.get_filesum(dcf_uri, False))
dcf.set("TYTO", "domain_conf", dcf_uri)
dcf.set("TYTO", "domain_user", ult_dcf_uri)
# USER
dcf.set("USER_DIRS", "root", dcf_dir)
dcf.set("USER_DIRS", "articles", dcf_dir + "articles/")
dcf.set("USER_DIRS", "images", dcf_dir + "images/")
dcf.set("USER_DIRS", "files", dcf_dir + "files/")
dcf.set("USER_DIRS", "modules", usr_mods)
dcf.set("USER_DIRS", "database", dcf_dir + ".db/")
dcf.set("USER_DIRS", "template", usr_tpl)
dcf.set("USER_MODULES_FILES", "metas", usr_mods + "tyto_metas.raw")
dcf.set("USER_MODULES_FILES", "header", usr_mods + "tyto_header.raw")
dcf.set("USER_MODULES_FILES", "navbar", usr_mods + "tyto_navbar.raw")
dcf.set("USER_MODULES_FILES", "sidebar", usr_mods + "tyto_sidebar.raw")
dcf.set("USER_MODULES_FILES", "footer", usr_mods + "tyto_footer.raw")
dcf.set("USER_TEMPLATE_FILES", "favicon", usr_favicon)
dcf.set("USER_TEMPLATE_FILES", "logo", usr_logo)
dcf.set("USER_TEMPLATE_FILES", "styles", usr_styles)
# WEBSITE
dcf.set("WEBSITE", "lang", langs.site_lang)
www_url or dcf.set("WEBSITE", "www_url", "https://%s/"%conf_name)
wip_url or dcf.set("WEBSITE", "wip_url", create_wip_url())
sdb_title or dcf.set("WEBSITE_MODULES", "sidebar_title", langs.site.sidebar_title)
# SERVER
dcf.set("SERVER", "root", srv)
dcf.set("SERVER", "domain", srv_dom)
# WIP
dcf.set("WIP_DIRS", "root", srv_wip)
dcf.set("WIP_DIRS", "images", srv_wip + "images/")
dcf.set("WIP_DIRS", "files", srv_wip + "files/")
dcf.set("WIP_DIRS", "template", wip_tpl)
dcf.set("WIP_FILES", "favicon", wip_favicon)
dcf.set("WIP_FILES", "logo", wip_logo)
dcf.set("WIP_FILES", "styles", wip_styles)
dcf.set("WIP_FILES", "rss", wip_rss)
dcf.set("WIP_FILES", "stats", wip_stats)
dcf.set("WIP_FILES", "metas", wip_tpl + "metas.html")
dcf.set("WIP_FILES", "header", wip_tpl + "header.html")
dcf.set("WIP_FILES", "navbar", wip_tpl + "navbar.html")
dcf.set("WIP_FILES", "sidebar", wip_tpl + "sidebar.html")
dcf.set("WIP_FILES", "footer", wip_tpl + "footer.html")
# WWW
dcf.set("WWW_DIRS", "root", srv_www)
dcf.set("WWW_DIRS", "images", srv_www + "images/")
dcf.set("WWW_DIRS", "files", srv_www + "files/")
dcf.set("WWW_DIRS", "template", www_tpl)
dcf.set("WWW_FILES", "favicon", www_favicon)
dcf.set("WWW_FILES", "logo", www_logo)
dcf.set("WWW_FILES", "styles", www_styles)
dcf.set("WWW_FILES", "rss", www_rss)
dcf.set("WWW_FILES", "stats", www_stats)
dcf.set("WWW_FILES", "metas", www_tpl + "metas.html")
dcf.set("WWW_FILES", "header", www_tpl + "header.html")
dcf.set("WWW_FILES", "navbar", www_tpl + "navbar.html")
dcf.set("WWW_FILES", "sidebar", www_tpl + "sidebar.html")
dcf.set("WWW_FILES", "footer", www_tpl + "footer.html")
with open(dcf_uri, "w") as f:
dcf.write(f)
# Update User local domain configuration file
#--------------------------------------------
ult_dcf_load()
ult_dcf.set("DOMAIN", "name", conf_name)
ult_dcf.set("DOMAIN", "hash", tools.get_filesum(dcf_uri, True))
ult_dcf.set("DOMAIN", "root", dcf_dir)
ult_dcf.set("DOMAIN", "conf", dcf_uri)
ult_dcf.set("SERVER", "root", srv)
with open(ult_dcf_uri, "w") as f:
ult_dcf.write(f)
# Update User local Domains List File
#------------------------------------
ult_dlf_load()
ult_dlf.set("DOMAINS", conf_name, dcf_dir)
with open(ult_dlf_uri, "w") as f:
ult_dlf.write(f)
debug.out(204, "True", dcf_uri, True, 0, False)
#======#=======================================================================
# MAIN #
#------#
#===================================#
# Check if current directory exists #
# Exit Tyto if in black hole... #
#-----------------------------------#
try:
user_dir = os.getcwd() + "/"
home_dir = os.path.expanduser('~')
except:
debug.out(2, "PWD", "?", True, 2, True)
#==========================================#
# utl: $USER/.local/Tyto #
# dcf: Domain Configuration File #
#------------------------------------------#
# Domain Configuration directory
dcf_dir = user_dir.rsplit("articles/")[0]
# Domain name from current basename directory
# Exit if not format at least "abc.tld"
conf_name = os.path.basename(os.path.dirname(dcf_dir))
dcf_name = "tyto_domain.ini"
dcf_uri = os.path.join(dcf_dir, dcf_name)
dcf_id = tools.get_filesum(dcf_uri, False) # ID from URI
# Tyto directory in home local user files
ult_dir = os.path.join(home_dir, ".local/Tyto/")
ult_dlf_uri = os.path.join(ult_dir, "domains.ini") # Domains list file
ult_dcf_uri = os.path.join(ult_dir, dcf_id + ".ini")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,243 @@
#!/usr/bin/env python3
# Tyto - Littérateur
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Forms (edit, create domain, questions...)
# File: /var/lib/tyto/program/form.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines :
# file comments :
# file functions:
# file program :
#--------------------------
import os, re, configparser
import debug, domain, langs, tools
#====================#
# Exit Tyto with log #
# user interrupts... #
#--------------------#
def maybe_later(expected, answer):
debug.out(255, expected, answer, True, 0, True)
#=========================#
# When asking something #
# yes_only : True / False #
#-------------------------#
def ask(q, yes_only, default):
expected = ""
if yes_only:
expected = langs.logs.ok
try:
answer = input(q)
except KeyboardInterrupt:
print("")
maybe_later(expected, "?")
# return default answer if exists
if not answer:
if default:
return default
maybe_later(expected, "?")
# Answer is a Y/N process
if yes_only:
for ok in langs.logs.ok:
if answer.lower() == ok.lower():
return True
maybe_later(expected, answer)
return answer
#====================================#
# Shorter value to show in questions #
# return value[0:12]
#------------------------------------#
def shorter(value):
if len(value) > 12:
return '%s...'%(value[0:12])
# Or legacy
return value
#=========================#
# Confirm domain name #
# from directory basename #
# ------------------------#
def ask_domain_shortname(config_name):
q = "> %s (%s)%s "%(langs.logs.configure_domain, config_name, langs.logs.q)
ask(q, True, False)
#======================#
# Getting domain Title #
#----------------------#
def ask_domain_title():
domain.dcf_load()
title = domain.dcf.get("DOMAIN", "title")
q = "> %s (%s)%s "%(langs.logs.domain_title, shorter(title), langs.logs.q)
answer = ask(q, False, title)
if answer != title:
tools.update_ini_file(domain.dcf_uri, "DOMAIN", "title", answer)
#===========================#
# Get domain creation date #
# Check if date match regex #
#---------------------------#
def ask_domain_date():
domain.dcf_load()
date = domain.dcf.get("DOMAIN", "date")
example = date or "YYYY[-MM-DD]"
q = "> %s (%s)%s "%(langs.logs.domain_date, example, langs.logs.q)
answer = ask(q, False, date)
# Check date format (not valid date)
test = True
tuple_date = answer.rsplit("-")
tuple_len = len(tuple_date)
for i in range(tuple_len):
if i == 0:
if len(tuple_date[i]) != 4 or not tuple_date[i].isdigit():
test = False
break
elif len(tuple_date[i]) != 2 or not tuple_date[i].isdigit():
test = False
break
# Exit if not valid
if not test:
debug.out(50, "YYYY[-MM-DD]", answer, True, 2, True)
if answer != date:
tools.update_ini_file(domain.dcf_uri, "DOMAIN", "date", answer)
#========================#
# Get domain description #
#------------------------#
def ask_domain_about():
domain.dcf_load()
about = domain.dcf.get("DOMAIN", "about")
q = "> %s (%s)%s "%(langs.logs.domain_about, shorter(about), langs.logs.q)
answer = ask(q, False, about)
if answer != about:
tools.update_ini_file(domain.dcf_uri, "DOMAIN", "about", answer)
#=======================#
# Get domain admin mail #
#-----------------------#
def ask_domain_mail():
domain.dcf_load()
mail = domain.dcf.get("DOMAIN", "mail")
q = "> %s (%s)%s "%(langs.logs.domain_mail, shorter(mail), langs.logs.q)
answer = ask(q, False, mail)
if answer != mail:
tools.update_ini_file(domain.dcf_uri, "DOMAIN", "mail", answer)
#===============================================#
# Get domain tags (wil be used in all articles) #
#-----------------------------------------------#
def ask_domain_tags():
domain.dcf_load()
tags = domain.dcf.get("DOMAIN", "tags")
q = "> %s (%s)%s "%(langs.logs.domain_tags, shorter(tags), langs.logs.q)
answer = ask(q, False, tags)
if answer != tags:
# Remove useless spaces for HTML meta
tuple_tags = answer.rsplit(",")
answer = ""
for i, tag in enumerate(tuple_tags):
answer = answer + tag.strip()
if i != len(tuple_tags) - 1:
answer = answer + ","
tools.update_ini_file(domain.dcf_uri, "DOMAIN", "tags", answer)
#===================================#
# Get domain lang #
# default en if no translation file # > !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! < TODO
#-----------------------------------#
def ask_domain_lang():
domain.dcf_load()
lang = domain.dcf.get("WEBSITE", "lang") or langs.get_sys_lang()
q = "> %s (%s)%s "%(langs.logs.domain_lang, lang, langs.logs.q)
answer = ask(q, False, lang).lower()
# Lang Format is 2 character
if len(answer) != 2:
debug.out("8", "xx", answer, True, 2, False)
ask_domain_lang()
return
# Check if translation file exists
if not langs.translation_exists("website", answer, False):
debug.out(103, "en", "%swebsite_en.py"%langs.trfs, True, 1, False)
answer = "en"
if answer != lang:
tools.update_ini_file(domain.dcf_uri, "WEBSITE", "lang", answer)
#===================================#
# Get domain server root #
#-----------------------------------#
def ask_domain_server():
domain.dcf_load()
srv = domain.dcf.get("SERVER", "root")
if srv:
if not tools.dir_exists(srv, False):
tested = True
srv = ""
q = "> %s (%s)%s "%(langs.logs.domain_srv, srv, langs.logs.q)
answer = ask(q, False, srv)
# Check if directory exists
if not tools.dir_exists(answer, False):
answer = srv
ask_domain_server()
return
domain.dcf_update_values(answer)

View File

@ -0,0 +1,43 @@
#!/usr/bin/env python3
# Tyto - Littérateur
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Show help commands
# File: /var/lib/tyto/program/help.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines :
# file comments :
# file functions:
# file program :
#--------------------------
import langs, debug
#==========================================#
# Show help in system langage #
# Help Contents is in translations/logs_XX #
#------------------------------------------#
def show(action, target):
print(langs.logs.help_contents)

View File

@ -1,544 +0,0 @@
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Create HTML page
# File: /var/lib/tyto/program/html.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines : 544
# file comments : 71
# file functions: 8
# file program : 414
#--------------------------
import os, sys, importlib
import logs, db, dom, tyto, form, langs
# Publish option can be
wip_opts = ('wip', 'new')
pub_opts = ('www', 'pub')
# Not a line if it starts with...(for sidebar, navbar)
nolines = ('#', '/')
# For static modules
if dom.ready:
tags_html_mods = \
{
dom.wip_navbar_f : '<!--# include virtual="/template/navbar.html"-->',
dom.wip_sidebar_f : '<!--# include virtual="/template/sidebar.html"-->',
dom.wip_metas_f : '<!--# include virtual="/template/metas.html"-->',
dom.wip_footer_f : '<!--# include virtual="/template/footer.html"-->'
}
#==========================#
# Load article DB #
# Start HTML page sections #
#--------------------------#
def set_page(target, article_bottom):
create_metas_page() # Include metas tags
create_main_page(target, article_bottom) # Create main page
#============================================#
# Set metas_page to be included in main page #
#--------------------------------------------#
def create_metas_page():
global metas_page
# Settings for metas
#-------------------
metas_page = ''
scale = 'width=device-width, initial-scale=1.0'
all_tags = dom.tags + ',' + db.meta_tags
css_ref = 'href="%stemplate/%s"'%(db.sub_uri, dom.styles)
rss_ref = 'type="application/rss+xml" ' + \
'href="%s%s" title="RSS 2.0. %s %s %s"'%(
db.sub_uri, dom.rss,
dom.title, dom.sep, dom.shortname
)
icon_ref = 'type="image/png" href="%stemplate/%s"'%(
db.sub_uri, dom.favicon
)
relme = '' # External URL in metas (if exists in config domain)
if dom.relme:
relme = '\n <link rel="me" type="text/html" href="%s">'%(
dom.relme
)
# Create author and date publish section infos
create_html_time_meta('wip')
# Set all raw HTML metas
#-----------------------
global metas
metas = \
tags_html_mods[dom.wip_metas_f] + '\n' + \
' <meta name="viewport" content="%s">\n'%scale + \
' <meta name=”url” content=”%s”>\n'%dom.www_url + \
' <meta name="language" content="%s">\n'%dom.lang_site + \
' <meta name="reply-to" content="%s">\n'%dom.mail + \
' <meta name="copyright" content="%s">\n'%dom.license + \
' <meta name="generator" content="%s">\n'%tyto.Tyto + \
' <meta name="title" content="%s">\n'%db.title + \
' <meta name="author" content="%s">\n'%db.author + \
' <meta name="description" content="%s">\n'%db.about + \
' <meta name="keywords" content="%s">\n'%all_tags + \
'%s'%meta_pub + \
' <link rel="canonical" href="%s">\n'%db.http_www + \
' <link rel="alternate" %s>\n'%(rss_ref) + \
' <link rel="stylesheet" %s>\n'%css_ref + \
' <link rel="shortcut icon" %s>\n'%icon_ref + \
' <!-- Open Graph data -->\n' + \
' <meta property="og:site_name" content="%s">\n'%dom.title + \
' <meta property="og:title" content="%s">\n'%db.title + \
' <meta property="og:type" content="article">\n' + \
' <meta property="og:url" content="%s">\n'%db.http_www + \
' <meta property="og:description" content="%s">\n'%db.about + \
' <meta property="og:image" content="%s">\n'%db.snpic + \
'%s'%relme + \
' <title>%s %s %s</title>'%(db.title, dom.sep, dom.title)
#=======================================#
# Set main page, with all HTML sections #
#---------------------------------------#
def create_main_page(target, article_bottom):
global main_page, post_html_code
# Create link for website's logo
#-------------------------------
logo_html = \
'<a href="/"\n' + \
'%stitle="%s %s logo: %s"\n'%(11 * " ",
langs.site.home, dom.sep, dom.title
) + \
'%sid="site_logo_link">\n'%(11 * " ") + \
'%s<img src="%stemplate/%s"\n'%(
10 * " ", db.sub_uri, dom.logo
) + \
'%salt="logo: %s"\n'%(15 * " ", dom.title) + \
'%sid="site_logo_image">\n'%(15 * " ") + \
'%s</a>'%(8 * " ")
post_html_code = ''
if dom.article_code:
post_html_code = \
' <span id="article_code"> \n' + \
' <a id="article_code_link"\n' + \
' href="./%s"\n'%os.path.basename(db.short_src) + \
' title="%s [%s]">{%s}</a></span> \n'%(
langs.site.tyto_psrc, db.title,
langs.site.source_code
)
#-----------------------#
# Create main HTML Page #
#-----------------------#
main_page = \
'<!Doctype html>\n' + \
'<html lang="%s">\n'%dom.lang_site + \
' <head>\n' + \
'%s\n'%metas + \
' </head>\n\n' + \
' <body>\n' + \
' <div id="site_container">\n' + \
' <header id="header_page">\n' + \
' <div id="site_logo">\n' + \
' %s\n'%logo_html + \
' </div>\n' + \
' <div id="site_infos">\n' + \
' <h1 id="site_title">\n' + \
' <a href="/"\n' + \
' title="%s"\n'%(langs.site.home) + \
' id="site_link">%s</a>\n'%dom.title + \
' </h1>\n' + \
' <p id="site_about">%s</p>\n'%dom.about + \
' </div>\n' + \
' </header>\n' + \
tags_html_mods[dom.wip_navbar_f] + '\n' + \
' <div id="article_sidebar_container">\n' + \
' <article id="article_main">\n' + \
' <h1 accesskey="t" id="post_title"\n' + \
' title="[%s] %s %s %s %s">%s</h1>\n'%(
db.title, langs.site.w_written, db.date,
langs.site.by, db.author,
db.title,
) + \
'%s\n'%article_bottom + \
' <div id="article_infos">\n' + \
' <p>\n' + \
' <span id="article_author"\n' + \
' title="%s %s [%s]">%s</span>, %s\n'%(
db.author, langs.site.author_of, db.title,
db.author, langs.site.le
) + \
'%s\n'%time_html_pub + \
'%s'%post_html_code + \
' </p>\n' + \
' </div>\n' + \
' </article>\n' + \
'\n' + \
tags_html_mods[dom.wip_sidebar_f] + '\n' + \
' </div>\n' + \
tags_html_mods[dom.wip_footer_f] + '\n' + \
' </div>\n' + \
' </body>\n' + \
'</html>'
#============================================#
# Create HTML line for article infos section #
# when wip, and publish #
#--------------------------------------------#
def create_html_time_meta(process):
# Need to reload the DB to get last time updated
importlib.reload(db)
global time_html_pub, meta_pub, date_raw
if process == 'wip':
try:
date_raw = db.date_wip # <time datetime= / meta search_date
date_pub = db.date_wip.rsplit(' ')[0]
time_pub = db.date_wip.rsplit(' ')[1]
except:
logs.out("23", '"date_wip = ?" > %s'%db.uri_file, True)
elif process == 'publish':
try:
date_raw = db.date_www # <time datetime=
date_pub = db.date_www.rsplit(' ')[0]
time_pub = db.date_www.rsplit(' ')[1]
except:
logs.out("23", '"date_www = ?" > %s'%db.uri_file, True)
if dom.lang_site == 'fr':
date_new = date_pub.rsplit('-')
date_pub = date_new[2] + '/' + date_new[1] + '/' + date_new[0]
# in <article> > section info : line with new date
time_html_pub = \
'<!--Tyto_Published-->\n' + \
' <time datetime="%s">\n'%date_raw + \
' <span id="article_pub"\n' + \
' title="[%s] %s %s (%s)">%s</span>\n'%(
db.title, langs.site.w_published, date_pub, time_pub,
db.date
) + \
' </time>\n' + \
'<!--/Tyto_Published-->'
# meta search_date=
meta_pub = \
'<!--Tyto_Meta--> <meta name="search_date" content="%s">\n'%(
date_raw.rsplit(' ')[0]
)
#=================================================#
# Create metas.html from _configs/tyto.metas.html #
# Opiton 'pub' force create (when publish) #
#-------------------------------------------------#
def create_user_metas(option):
dom.valid()
form.create_metas(option)
if option in wip_opts: target = dom.wip_metas_f
elif option in pub_opts: target = dom.www_metas_f
if option == 'www' and tyto.exists(target):
form.asking('%s. %s%s '%(
langs.site.metas, langs.site.form_rep, langs.site.q
), True)
# Create wip metas.html file according to option
#-----------------------------------------------
try: user_file = open(dom.metas_f, 'r').read()
except: logs.out("1", dom.metas_f, True)
user_metas = ''
tab = 4 * ' '
metas_used = ('<meta ', '<link ')
for line in user_file.rsplit('\n'):
if line.startswith(metas_used):
if user_metas: user_metas = "%s\n%s%s"%(user_metas, tab, line)
else: user_metas = '%s%s'%(tab, line)
tyto.set_file(target, 'New', user_metas)
#==============================================#
# Create HTML sidebar from file tyto.navbar #
# If no index file in src directory: pass # #
# Create empty file in template/ if not exists #
#----------------------------------------------#
def create_navbar(option):
dom.valid()
form.create_navbar(option)
if not tyto.exists(dom.navbar_f):
logs.out("1", dom.navbar_f, True)
if option in wip_opts: target = dom.wip_navbar_f
elif option in pub_opts: target = dom.www_navbar_f
if option == 'www' and tyto.exists(target):
form.asking('%s. %s(%s)%s '%(
langs.site.navbar, langs.site.form_rep,
option, langs.site.q
), True)
# navbar has items
navbar_items = False
# Set first HTML line
menu_html = \
'%s<nav accesskey="m" id="site_menu">\n'%(4 * ' ') + \
'%s<menu id="site_menu_items">'%(6 * ' ')
navbar_lines = open(dom.navbar_f, 'r').read()
for line in navbar_lines.rsplit('\n'):
if not line or line.startswith(nolines): continue
# Get HTML title if defined (commented after)
if '#' in line:
direc = line.rsplit('#')[0].rstrip()
title = '%stitle="%s"\n'%(15 * ' ', line.rsplit('#')[1].lstrip())
else:
direc = line
title = ''
# Check if directory exists in articles/
dir_uri = os.path.join(dom.articles_d, direc)
if not os.path.isdir(dir_uri):
logs.out("24", '%s/'%dir_uri, False)
continue
# Check if an index.[ext] exists (src, wip, www)
no_wip_index = False
no_www_index = False
src_index = ''
wip_index = '%s%s/index.html'%(dom.srv_wip, direc)
www_index = '%s%s/index.html'%(dom.srv_www, direc)
# Source index article must exist
src_index = [ \
filename \
for filename in os.listdir(dir_uri) \
if filename.startswith("index.") \
and os.path.isfile \
]
if not src_index:
src_index = '%s%s/index.tyto'%(dom.articles_d, direc)
logs.out('26', '> %s'%(src_index), False)
continue
# index.html server files must exist (or 404 error)
if option in wip_opts:
if not tyto.exists(wip_index):
logs.out('26', '> %s'%(wip_index), False)
no_wip_index = True
continue
elif option in pub_opts:
if not tyto.exists(www_index):
logs.out('26', '> %s'%(www_index), False)
no_www_index = True
continue
# Add link to HTML structure
navbar_items = True
menu_item = \
'\n%s<li class="site_menu_item">\n'%(8 * ' ') + \
'%s<a class="site_menu_link"\n'%(10 * ' ') + \
'%s'%title + \
'%shref="/%s/">%s</a>\n'%(
15 * ' ', direc, direc
) + \
'%s</li>'%(8 * ' ')
menu_html = '%s%s'%(menu_html, menu_item)
# Nothing to do
if not navbar_items:
tyto.set_file(target, 'New', '')
# Create ending HTML file
else:
menu_html = '\n%s\n%s</menu>\n%s</nav>\n'%(menu_html, 6 * ' ', 4 * ' ')
tyto.set_file(target, 'New', menu_html)
#==============================================#
# Create HTML sidebar from file tyto.sidebar #
# Create empty file in template/ if not exists #
#----------------------------------------------#
def create_sidebar(option):
dom.valid()
form.create_sidebar(option)
if not tyto.exists(dom.sidebar_f):
logs.out("1", dom.sidebar_f, True)
if int(dom.sidebar_items) > 16: db.sidebar_items = 6
if option in wip_opts: target = dom.wip_sidebar_f
elif option in pub_opts: target = dom.www_sidebar_f
if option == 'www' and tyto.exists(target):
form.asking('%s. %s%s '%(
langs.site.sidebar, langs.site.form_rep, langs.site.q
), True)
sidebar_items = False
# Set HTML sidebar
sidebar_list = ''
sidebar_html = \
'<aside accesskey="s" id="sidebar">\n' + \
' <h2 id="sidebar_title">%s</h2>\n' + \
' <ul id="sidebar_list">\n' + \
'%s' + \
' </ul>\n' + \
'</aside>'
sidebar_title = dom.sidebar_title
sidebar_lines = open(dom.sidebar_f, 'r').read()
counter = 0
for line in sidebar_lines.rsplit('\n'):
if not line or line.startswith(nolines):
continue
if line.startswith(':'):
sidebar_title = line.rsplit(':')[1].lstrip()
continue
f_uri = '%s%s'%(dom.articles_d, line)
if not tyto.exists(f_uri):
logs.out("24", f_uri, False)
continue
# Get Hash from uri to get db file
hash_uri = tyto.get_filesum(f_uri, False)
db_uri = '%s%s.config'%(dom.articles_db_d, hash_uri)
if not tyto.exists(db_uri):
logs.out('25', line, False)
continue
# Load article"s database
exec(open(db_uri).read(),globals())
# Check wip status and if article exists in server
if option in wip_opts:
if hash_wip != hash_chk:
logs.out("30", line, False)
continue
if not tyto.exists(post_wip):
logs.out("24", post_wip, False)
continue
elif option in pub_opts:
if hash_www != hash_chk:
logs.out("30", line, False)
continue
if not tyto.exists(post_www):
logs.out("24", post_www, False)
continue
# Add item if not max
sidebar_items = True
counter += 1
if counter > dom.sidebar_items: break
# Show item to add
logs.out("35", '"%s" > %s'%(title, line), False)
# Create HTML list for this article
link_title = '%s [%s]'%(title, author)
sidebar_list = sidebar_list + \
' <li class="sidebar_item">\n' + \
' <a class="sidebar_item_link"\n' + \
' href="/%s">\n'%short_srv + \
' <h3 class="sidebar_item_title">%s</h3>\n'%title + \
' <p class="sidebar_item_about"\n' + \
' title="%s">\n'%link_title + \
' %s - %s\n'%(date, about) + \
' </p>\n' + \
' </a>\n' + \
' </li>\n'
# Nothing to do
if not sidebar_items:
tyto.set_file(target, 'New', '')
else:
# Create HTML complete sidebar
sidebar_temp = sidebar_html%(sidebar_title, sidebar_list)
# Indent HTML code
sidebar_content = ''
for line in sidebar_temp.rsplit('\n'):
sidebar_content = sidebar_content + '%s%s\n'%(4 * ' ', line)
tyto.set_file(target, True, sidebar_content)
#===================================================#
# Create footer.html from _configs/tyto.footer.html #
#----------------------------------------------=====#
def create_user_footer(option):
dom.valid()
form.create_footer(option)
if option in wip_opts: target = dom.wip_footer_f
elif option in pub_opts: target = dom.www_footer_f
if option == 'www' and tyto.exists(target):
form.asking('%s. %s%s '%(
langs.site.footer, langs.site.form_rep, langs.site.q
), True)
try: footer_f = open(dom.footer_f, 'r').read()
except: logs.out("1", dom.footer_f, True)
footer = ''
tab = 4 * ' '
for line in footer_f.rsplit('\n'):
if not line or line.startswith('#'): continue
if footer: footer = "%s\n%s%s"%(footer, tab, line)
else: footer = '%s%s'%(tab, line)
tyto.set_file(target, 'New', footer)

View File

@ -1,131 +0,0 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Show helps and informations
# File: /var/lib/tyto/program/infos.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines : 131
# file comments : 27
# file functions: 3
# file program : 91
#--------------------------
import os, sys, importlib
import langs
importlib.reload(langs)
# Set colors
CS = '\033[0;0m'
CR = '\033[1;31m'
CY = '\033[1;33m'
CG = '\033[1;32m'
#
# Show Version
#
def version():
# Show Version
tytobin = open('/usr/bin/tyto').read()
for line in tytobin.rsplit('\n'):
if line.startswith('# Version:'):
print(line)
break
#==========================================#
# List all found domain in local directory #
#------------------------------------------"
def list_domains():
# Show domains list
try:
has_domains = True
user = os.environ.get('USER')
user_dir = os.path.expanduser('~')
db_domains = '%s/.local/tyto'%user_dir
except:
has_domains = False
if not os.path.exists(db_domains):
has_domains = False
print('! No directory > %s/'%db_domains)
if has_domains:
for folder in os.listdir(db_domains):
domain_local_uri = '%s/%s'%(db_domains, folder)
if os.path.isdir(domain_local_uri):
line = ' - %s >'%folder
# Check configuration file and load
domain_conf = '%s/domain_config.bkp'%domain_local_uri
if not os.path.exists(domain_conf):
line = '%s %sUnknown%s ?'%(line, CR, CS)
else:
try:
exec(open(domain_conf).read(),globals())
line = '%s %sConfig%s > '%(line, CG, CS)
except:
pass
try:
if os.path.exists(directory):
line = '%s %s%s%s'%(line, CG, directory, CS)
else:
line = '%s %s%s%s'%(line, CR, directory, CS)
except:
line = '%s %sNo root%s > '%(line, CR, CS)
try:
line = '%s %s'%(line, www_url)
except:
line = '%s %sNo URL%s > '%(line, CR, CS)
print(line)
#
# --help [full]
#
def tyto(target):
if target == "full":
version()
list_domains()
print(langs.site.args_helps)
print(langs.site.ex_helps)
elif target == 'help':
print(langs.site.args_helps)
elif target == 'domains':
list_domains()
elif target == 'version':
version()
sys.exit(0)

View File

@ -1,90 +1,135 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Tyto - Littérateur # Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org> # Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License # it under the terms of the GNU General Public License as published by
# as published by the Free Software Foundation, either version 3 of the # the Free Software Foundation, either version 3 of the License, or
# License, or of the License, or (at your option) any later version. # (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details. # GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re) # XMPP: echolib (im@echolib.re)
# #
# Description: Load translations file for logs and forms/sites # Description: Load lang logs file according to system language
# Load lang site file according to domain configuration
# File: /var/lib/tyto/program/langs.py # File: /var/lib/tyto/program/langs.py
#---------------------------------------------------------------------- #----------------------------------------------------------------------
#------------------------- #-------------------------
# Funny Stats Project # Funny Stats Project
#------------------------- #-------------------------
# file lines : 90 # file lines :
# file comments : 28 # file comments :
# file functions: 0 # file functions:
# file program : 53 # file program :
#-------------------------- #--------------------------
import sys, locale, os
import locale, sys, os, importlib import args, debug, domain
import dom
try: trfs = "/var/lib/tyto/translations/"
site.yes
except: #==================================#
# Import translation directory # Check if translation file exists #
trans_dir = '/var/lib/tyto/translations' # module: #
sys.path.insert(0, trans_dir) # - "logs": logs_xx #
# - "website": website_xx #
# lang: 2 chars language #
# out: exit if True
# return True or False #
#----------------------------------#
def translation_exists(module, lang, out):
global tr_file
modules = ("logs", "website")
if not module in modules: return # in case of internal typo error
tr_file = "%s%s_%s.py"%(trfs, module, lang)
if not os.path.exists(tr_file):
debug.out(5, lang, tr_file, True, 2, out)
return False
return True
#=============================================================================#
# LOGS | #
# Set and import file | #
#=============================================================================#
#=============================#
# Get system Lang to set logs #
#-----------------------------#
def get_sys_lang():
global lang, tr_logs_uri
tr_logs_uri = "%slogs_%s.py"
try: lang = locale.getdefaultlocale()[0].rsplit("_")[0]
except: lang = "en"
if not translation_exists("logs", lang, False):
lang = "en"
tr_logs_uri = tr_logs_uri%(trfs, lang)
return lang
#===============================#
# Import logs lang file in logs #
#-------------------------------#
def load_logs_lang():
global logs, lang, set_logs
# Create yes array with all yes languages
try: try:
answer_yes set_logs
except: except:
answer_yes = (()) logs = __import__("logs_%s"%get_sys_lang())
for lang_file in os.listdir(trans_dir): debug.out(201, lang, tr_logs_uri, False, 0, False)
if lang_file.startswith("site_") and lang_file.endswith(".py"): set_logs = True
lang_file = lang_file.replace(".py", "")
lang = importlib.import_module(lang_file)
answer_yes = answer_yes + ((lang.yes),)
# Get default system language #=============================================================================#
# or set "en" (english) if no translation file # WEBSITE | #
# Get/Set and import file | #
#=============================================================================#
#=======================================#
# Get website lang from dcf to set site #
#---------------------------------------#
def get_website_lang():
global site_lang, tr_website_uri
tr_website_uri = "%swebsite_%s.py"
domain.dcf_load()
site_lang = domain.dcf.get("WEBSITE", "lang")
if not translation_exists("website", site_lang, False):
site_lang = get_sys_lang()
tr_website_uri = tr_website_uri%(trfs, site_lang)
return site_lang
#==================================#
# Import website lang file in site #
#----------------------------------#
def load_website_lang():
global site, site_lang, set_site
try: try:
lang_sys = locale.getdefaultlocale()[0].split('_')[0] set_site
os.path.exists('%s/logs_%s.py'%(trans_dir, lang_sys))
except: except:
lang_sys = 'en' site = __import__("website_%s"%get_website_lang())
debug.out(208, site_lang, tr_website_uri, False, 0, False)
set_site = True
# Set language logs from configuration domain
# or set default english if not known
try:
dom.exists
lang_logs = dom.lang_logs
os.path.exists('%s/logs_%s.py'%(trans_dir, lang_logs))
log = importlib.import_module('logs_%s'%lang_logs, package=None)
except:
log = importlib.import_module('logs_%s'%lang_sys, package=None)
# Set language site/form from configuration domain
# or set default english if not known
try:
dom.exists
lang_site = dom.lang_site
os.path.exists('%s/site_%s.py'%(trans_dir, lang_site))
site = importlib.import_module('site_%s'%lang_site, package=None)
except:
site = importlib.import_module('site_%s'%lang_sys, package=None)

View File

@ -1,127 +0,0 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Show logs messages, exit with nbr
# File: /var/lib/tyto/program/logs.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines : 127
# file comments : 23
# file functions: 1
# file program : 93
#--------------------------
import os, sys
import langs
try:
shebang
except:
# Use to mark new article
shebang = "#!/NEW"
# Set colors
CS = '\033[0;0m'
CR = '\033[1;31m'
CY = '\033[1;33m'
CG = '\033[1;32m'
# Exit from program with message #
#--------------------------------#
def out(nbr, value, out):
logs = {
'1' : '%s%s%s > %s'%(CR, langs.log.unused_r, CS, value),
'2' : '%s%s%s > %s'%(CR, langs.log.data_inc, CS, value),
'3' : '%s%s%s %s'%(CR, langs.log.data_inv, CS, value),
'4' : '%sUnable to create file%s: %s'%(CR, CS, value),
'5' : '%s%s%s > "%s"'%(CR, langs.log.no_arg, CS, value),
'6' : '%s%s%s > %s'%(CR, langs.log.sep_inv, CS, value),
'7' : '%s%s%s > %s'%(CR, langs.log.post_inv, CS, value),
'8' : '%s%s%s %s'%(CR, langs.log.mark_np, CS, value),
'9' : '%s%s%s > %s'%(CR, langs.log.post_chg, CS, value),
'10' : '%s%s%s'%(CR, langs.log.dom_no, CS),
'11' : '%s%s%s > %s'%(CR, langs.log.err_arg, CS, value),
'12' : '%s%s%s > %s'%(CR, langs.log.post_inc, CS, value),
'13' : '%s%s%s'%(CR, langs.log.no_fidi, CS),
'14' : '%sMismatch%s program start'%(CR, CS),
'15' : '%s%s%s %s'%(CR, langs.log.anch_nu, CS, value),
'16' : '%s%s%s "%s = ?"'%(CR, langs.log.unused_c, CS, value),
'17' : '%s%s%s "%s ?"'%(CR, langs.log.unused_v, CS, value),
'18' : '%s%s%s > %s'%(CR, langs.log.unused_p, CS, value),
'19' : '%s%s%s %s'%(CG, langs.log.was_wip, CS, value),
'20' : ' ╞═ %s%s%s %s'%(CG, langs.log.was_chk, CS, value),
'21' : '%s%s%s > %s'%(CG, langs.log.post_val, CS, value),
'22' : '%s%s%s %s'%(CY, langs.log.symb_np, CS, value),
'23' : '%s%s%s > %s'%(CY, langs.log.db_inv, CS, value),
'24' : '%s%s%s > %s'%(CY, langs.log.unused_r, CS, value),
'25' : ' ╞═ %s%s%s > %s'%(CY, langs.log.nycheck, CS, value),
'26' : '%s%s%s %s'%(CY, langs.log.nyfile, CS, value),
'27' : '%s%s%s %s'%(CY, langs.log.snpic_d, CS, value),
'28' : '%s (%s)'%(langs.log.ntd, value),
'29' : '%sEmpty configuration%s %s'%(CY, CS, value),
'30' : '%s%s%s > %s'%(CY, langs.log.nywip, CS, value),
'31' : '%s%s%s'%(CR, langs.log.nomods, CS),
'32' : ' ╞══ %s%s%s > %s'%(CG, langs.log.file_c, CS, value),
'33' : ' ╞══ %s%s%s > %s'%(CG, langs.log.dir_c, CS, value),
'34' : ' ╞══ %s%s%s > %s'%(CG, langs.log.file_n, CS, value),
'35' : ' ╞═ %s%s%s %s'%(CG, langs.log.add, CS, value),
'36' : '%s %s'%(langs.log.file_e, value),
'37' : '%s %s'%(langs.log.dir_e, value),
'38' : '%s%s%s "%s ?"'%(CR, langs.log.unused_t, CS, value),
'39' : '%s%s%s > %s'%(CR, langs.log.dom_cor, CS, value),
'40' : '%s%s%s > %s'%(CY, langs.log.dom_ina, CS, value),
'41' : '%s%s%s > %s'%(CR, langs.log.dom_inc, CS, value),
'42' : '%s%s%s > %s'%(CG, langs.log.dom_act, CS, value),
'43' : '%s%s%s'%(CY, langs.log.dom_no, CS),
'44' : '%s%s%s "tyto check %s"'%(CY, langs.log.check_m, CS, value),
'45' : '%s%s %s%s > %s'%(CY, langs.log.meta_t, langs.log.no_up, CS, value),
'46' : '%s%s %s%s > %s'%(CY, langs.log.time_t, langs.log.no_up, CS, value),
'51' : '%s%s%s > %s'%(CY, langs.log.data_inc, CS, value),
'60' : '\n%s'%langs.log.status_r,
'61' : '%s%s%s > %s'%(CG, langs.log.file_e, CS, value),
'85' : ' ╞═ %s%s%s > %s'%(CY, langs.log.was_pub, CS, value),
'81' : '%s%s%s > %s'%(CR, langs.log.post_exists, CS, value),
'82' : '%s%s "%s"%s > %s'%(CR, langs.log.shebang_r, shebang, CS, value),
'84' : '%s%s%s %s'%(CR, langs.log.title_no, CS, value),
'91' : ' ╞═ %s%s%s > %s'%(CY, langs.log.post_nfd, CS, value),
'92' : ' ╞═ %s%s%s > %s'%(CG, langs.log.post_yfd, CS, value),
'94' : ' ╞═ %s%s%s > %s'%(CY, langs.log.st_chk_o, CS, value),
'95' : ' ╞═ %s%s%s > %s'%(CG, langs.log.status_s, CS, value),
'96' : ' ╞═ %s%s%s > %s'%(CY, langs.log.static_y, CS, value),
'97' : ' ╞═ %s%s%s > %s'%(CG, langs.log.static_n, CS, value),
'98' : ' ╞═ %s%s%s > %s'%(CY, langs.log.status_n, CS, value),
'99' : ' ╞═ %s%s%s > %s'%(CY, langs.log.status_o, CS, value),
'255' : '%s'%langs.log.laterout
}
msg = logs[nbr]
print(msg)
out_0 = (21, 28)
if int(nbr) in out_0: nbr = 0
if out: sys.exit(int(nbr))

View File

@ -1,94 +1,61 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Tyto - Littérateur # Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org> # Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License # it under the terms of the GNU General Public License as published by
# as published by the Free Software Foundation, either version 3 of the # the Free Software Foundation, either version 3 of the License, or
# License, or of the License, or (at your option) any later version. # (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details. # GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re) # XMPP: echolib (im@echolib.re)
# #
# Description: Create something new (domain, sidebar...) # Description: When user wants to create something new
# File: /var/lib/tyto/program/new.py # File: /var/lib/tyto/program/new.py
#---------------------------------------------------------------------- #----------------------------------------------------------------------
#------------------------- #-------------------------
# Funny Stats Project # Funny Stats Project
#------------------------- #-------------------------
# file lines : 94 # file lines :
# file comments : 27 # file comments :
# file functions: 1 # file functions:
# file program : 59 # file program :
#-------------------------- #--------------------------
import args, domain
import sys
from unidecode import unidecode
import args, dom, logs, langs, form, html, tyto, show, creators
#===============================================# #====================================#
# manage argument new for # # Manage arguments from command line #
# - domain: target becomes 3rd command argument # # Specific to action "new" #
#-----------------------------------------------# #------------------------------------#
def manage(target): def manage(action, target):
# "domain" target do = {
#---------------- "domain" : create_domain,
option = args.action }
if target == "domain":
try: option = sys.argv[3]
except: option = args.action
if target in args.pass_targets: do[target]()
actions = {
'domain' : form.manage,
'sidebar' : html.create_sidebar,
'navbar' : html.create_navbar,
'metas' : html.create_user_metas,
'footer' : html.create_user_footer,
'sitemap' : creators.manage
}
actions[target](option)
# article target name
#--------------------
else:
if args.target.endswith(".tyto"):
args.target = args.target.replace(".tyto", '')
# In case needed (todo later) #===================================#
# u = unidecode(args.target, "utf-8") # From command line "new domain" #
# args.target = unidecode(u) # Create and set only if not exists #
# or if user "force" option
#-----------------------------------#
def create_domain():
if not domain.dcf_exists() or args.force:
domain.dcf_create()
return
filepost = "%s%s.tyto"%(dom.articles_d, args.target)
if tyto.exists(filepost):
logs.out("81", filepost, True)
else:
form.asking("%s%s {%s}%s "%(
langs.site.new_post,
langs.site.q,
filepost,
langs.site.q
), True)
post = tyto.new_article%(logs.shebang,
args.target,
dom.user,
tyto.nowdate().rsplit(' ')[0]
)
tyto.set_file(filepost, True, post)
show.read_lines(filepost, True)

View File

@ -1,294 +0,0 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Publish on www server
# File: /var/lib/tyto/program/publish.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines : 294
# file comments : 50
# file functions: 6
# file program : 206
#--------------------------
import os, sys, shutil, importlib, subprocess
from pathlib import Path
import logs, args, dom, db, wip, html, tyto, form, stats, rss, langs, check
#==============================#
# Manage action, get post db #
# check if publish can be done #
#------------------------------#
def manage(target):
dom.valid()
# Specific QUICK processes: check > wip > publish
if args.action == "quick-pub":
try: db.uri_file
except: logs.out("28", "%s + %s"%(args.action, args.target), True)
wip = subprocess.run(
[
'/usr/bin/tyto',
'force-wip',
target
],
)
importlib.reload(db)
check_to_publish('one')
publish_article()
rss.create_feed()
return
# Target is footer, sidebar, navbar, metas
# template: create/copy template/ files
# all: publish all wip article
#-----------------------------------------
elif target in args.pass_targets:
do = {
'updated' : publish_all,
'again' : publish_all,
'added' : publish_all,
'sidebar' : html.create_sidebar,
'navbar' : html.create_navbar,
'metas' : html.create_user_metas,
'footer' : html.create_user_footer,
'template' : publish_template,
'stats' : stats.manage
}
do[target]('www')
return
# Database must exists...
if not target: logs.out("5", '', True)
if not db.post: logs.out("1", db.uri_file, True)
if not db.exists: logs.out("25", db.uri_file, True)
# Publish in www server an article
check_to_publish('one')
# Article already published
if db.file_www:
logs.out("85", '%s > %s'%(db.date_chk, db.uri_file), False)
answer = form.asking('%s%s '%(
langs.site.publish_a, langs.site.q
), True)
# Publish
publish_article()
# Create new ATOM/RSS file
rss.create_feed()
#============================================#
# Option 'all' to publish again, based on DB #
#--------------------------------------------#
def publish_all(option):
tyto.show_multi_message('www', dom.srv_www)
form.asking('%s%s '%(langs.site.proceed, langs.site.q), True)
# Sort by newer articles (created by last check)
db_articles = sorted(Path(dom.articles_db_d).iterdir(),
key=os.path.getmtime
)
# Load domain configuration DB
option = args.target
found = False
for post_db in db_articles:
if not str(post_db).endswith('.config'): continue
# Load DB
exec(open(post_db).read(),globals())
args.target = short_src
importlib.reload(db)
if option == "again" and not db.www_again: continue
elif option == "added" and not db.www_added: continue
elif option == "updated" and not db.www_updated: continue
check_to_publish('all')
if err_pub:
continue
found = True
publish_article()
if not found:
logs.out("28", 'publish %s'%option, True)
# If found: create new ATOM/RSS file
rss.create_feed()
#==============================#
# Check if it can be published #
#------------------------------#
def check_to_publish(process):
global err_pub
err_pub = False
print('')
db.show_title()
# Article was not checked or changed
if db.no_chk:
logs.out("25", db.uri_file, False)
err_pub = 25
elif db.old_chk:
logs.out("9", db.uri_file, False)
err_pub = 9
# Article must exists in wip server
if db.no_wip or db.old_wip:
logs.out("30", db.uri_file, False)
err_pub = 30
elif not db.file_wip:
logs.out("1", db.post_wip, False)
err_pub = 1
if err_pub:
if process == 'all': return
elif process == 'one': sys.exit(err_pub)
#===============#
# Let's publish #
#---------------#
def publish_article():
# Copy wip page to www page
if os.makedirs('%s%s'%(dom.srv_www, db.direc_src), exist_ok=True):
logs.out("33", '%s%s'%(dom.srv_www, db.direc_src), False)
# Replace in DB hash_wip and date_wip
db_values = \
[
("date_www", '"%s"'%db.date_www, '"%s"'%tyto.nowdate()),
("hash_www", '"%s"'%db.hash_www, '"%s"'%db.hash_post),
("static_www", '%s'%db.static_www, '%s'%db.static_wip)
]
tyto.change_in_db(db.config, db_values)
# Copy needed files (Also create sub-folders)
tyto.files_to_srv('www')
# Replace publish HTML line
replace_lines_pub()
#=================================================#
# Replace line in article containing publish date #
#-------------------------------------------------#
def replace_lines_pub():
html.create_html_time_meta('publish')
in_pub = False
wip_html_post = open(db.post_wip, 'r').read()
www_html_post = wip_html_post
for line in wip_html_post.rsplit('\n'):
if line.startswith('<!--Tyto_Published-->'):
in_pub = True
time_wip_pub = line
continue
elif line.startswith('<!--/Tyto_Published-->'):
time_wip_pub = '%s\n%s'%(time_wip_pub, line)
in_pub = False
break
elif line.startswith('<!--Tyto_Meta-->'):
time_wip_meta = line
continue
if in_pub:
time_wip_pub = '%s\n%s'%(time_wip_pub, line)
# Update file with new time meta
try:
www_html_post = \
www_html_post.replace(time_wip_meta,
html.meta_pub
)
except:
logs.out("45", db.post_www, False)
# update file with new article time
try:
www_html_post = \
www_html_post.replace(time_wip_pub,
html.time_html_pub
)
except:
logs.out("46", db.post_www, False)
tyto.set_file(db.post_www, 'New', www_html_post)
#================================#
# Publish template in www server #
#--------------------------------#
def publish_template(option):
form.asking('%s%s > %s '%(
langs.site.uptpl, langs.site.q,
dom.srv_www_tpl_d
), True)
# Copy all file in wip server template, except "nofiles"
nofiles = (
'footer.html',
'metas.html',
'navbar.html',
'sidebar.html'
)
for item in os.listdir(dom.srv_wip_tpl_d):
if item.startswith(nofiles):
continue
item_src = '%s%s'%(dom.srv_wip_tpl_d, item)
item_dst = '%s%s'%(dom.srv_www_tpl_d, item)
if os.path.isdir(item_src):
shutil.copytree(item_src, item_dst, dirs_exist_ok=True)
logs.out("33", item_dst, False)
else:
shutil.copy2(item_src, item_dst)
logs.out("32", item_dst, False)
# Create new file from _configs/ files
if args.option == "--no-mods":
return
html.create_sidebar('pub')
html.create_navbar('pub')
html.create_user_metas('pub')
html.create_user_footer('pub')

View File

@ -1,129 +0,0 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Create feed RSS/Atom
# File: /var/lib/tyto/program/rss.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines : 129
# file comments : 28
# file functions: 1
# file program : 90
#--------------------------
import os
from pathlib import Path
import logs, dom, db, tyto, langs
#============================#
# Create ATOM/RSS feed #
# only with publish argument #
#----------------------------#
def create_feed():
# Generic fedd Header
set_f = \
'<?xml version="1.0" encoding="utf-8"?>\n' + \
'<rss version="2.0">\n' + \
' <channel>\n' + \
' <title>%s - %s - Flux RSS 2.0</title>\n'%(
dom.title, dom.www_url
) + \
' <link>%s</link>\n'%dom.www_url + \
' <description>RSS 2.0 - %s (%s)</description>\n'%(
dom.title, dom.about
) + \
' <image>\n' + \
' <url>%s/%s</url>\n'%(dom.www_url, dom.logo) + \
' <title>logo %s</title>\n'%dom.title + \
' <link>%s</link>\n'%dom.www_url + \
' </image>\n' + \
' <language>%s</language>\n'%dom.lang_site + \
' <category>%s</category>\n'%dom.tags + \
' <lastBuildDate>%s</lastBuildDate>\n'%tyto.nowdate() + \
' <copyright>%s</copyright>\n'%dom.license + \
' <webMaster>%s</webMaster>\n'%dom.mail + \
' <generator>%s</generator>'%tyto.Tyto
# Sort by newer articles (created by last check)
db_articles = sorted(Path(dom.articles_db_d).iterdir(),
key=os.path.getmtime,
reverse=True
)
rss_item = False
nbr_item = 0
# Loop published articles. Get databases of articles
for post_db in db_articles:
if not str(post_db).endswith('.config'):
continue
# Load DB
exec(open(post_db).read(),globals())
if not hash_www or hash_chk != hash_www:
continue
# NoSitemap
if not db.sitemap:
continue
rss_item = True
nbr_item += 1
if nbr_item > dom.rss_items:
break
set_f = \
'%s\n'%set_f + \
'\n <item>\n' + \
' <title>%s</title>\n'%title + \
' <link>%s</link>\n'%http_www + \
' <guid>%s</guid>\n'%http_www + \
' <pubDate>%s</pubDate>\n'%date_www + \
' <description>%s</description>\n'%about + \
' <author>%s</author>\n'%author + \
' <image>\n' + \
' <url>%s</url>\n'%snpic + \
' <title>%s</title>\n'%(title) + \
' <link>%s</link>\n'%http_www + \
' </image>\n' + \
' <category>%s</category>\n'%tags + \
' </item>'
# Do nothing if no item
if not rss_item:
logs.out("28", '(ATOM/RSS)', False)
return
set_f = \
'%s\n'%set_f + \
' </channel>\n' + \
'</rss>'
print('\n ├─ %s'%langs.site.rss_c)
tyto.set_file(dom.www_rss_f, 'New', set_f)

View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
# Tyto - Littérateur
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: When user wants to set something (mainly in domain)
# File: /var/lib/tyto/program/set.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines :
# file comments :
# file functions:
# file program :
#--------------------------

View File

@ -1,216 +1,65 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Tyto - Littérateur # Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org> # Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License # it under the terms of the GNU General Public License as published by
# as published by the Free Software Foundation, either version 3 of the # the Free Software Foundation, either version 3 of the License, or
# License, or of the License, or (at your option) any later version. # (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details. # GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re) # XMPP: echolib (im@echolib.re)
# #
# Description: Manage show*/edit* arguments. # Description: When user wants to see something
# Read or edit file from [target] argument
# File: /var/lib/tyto/program/show.py # File: /var/lib/tyto/program/show.py
#---------------------------------------------------------------------- #----------------------------------------------------------------------
#------------------------- #-------------------------
# Funny Stats Project # Funny Stats Project
#------------------------- #-------------------------
# file lines : 216 # file lines :
# file comments : 39 # file comments :
# file functions: 3 # file functions:
# file program : 156 # file program :
#-------------------------- #--------------------------
import os
import os, sys, importlib, subprocess import domain, debug
import args, logs, langs, dom, db, form, tyto, check, html, stats
#========================# #====================================#
# Read lines from a file # # Manage arguments from command line #
# alone: True/False # # Specific to action "show" #
#------------------------# #------------------------------------#
def read_lines(f, alone): def manage(action, target):
if not f: return do = {
if not tyto.exists(f): logs.out("1", f, True) "domains": all_domains,
}
datas = open(f).read() do[target]()
# Align content line, after line number
ln_datas = len(datas.splitlines()) + 1
sp_max = len(str(ln_datas))
print('', f)
print(' ├─%s─┐'%(sp_max * ''))
for ln, line in enumerate(datas.rsplit('\n'), 1):
sp = sp_max - len(str(ln))
print('%s %s%s'%(int(sp) * " ", ln, line))
# Ends for show. False should be for form
if alone: decor = ''
else: decor = ''
print(' %s%s─┘'%(decor, sp_max * ''))
if not f == dom.config: dom.valid()
#======================# #============================#
# From command line: # # List all registred domains #
# Show or edit file # #----------------------------#
# final html, db, src # def all_domains():
#----------------------# domain.ult_dlf_load()
def manage(target):
if not dom.exists: logs.out("10", '', True)
dom.valid()
actions_read = ('show', 'show-about', 'show-db', 'show-wip', 'show-www')
actions_edit = ('edit', 'edit-about', 'edit-db', 'edit-wip', 'edit-www')
post_src = post_db = post_wip = post_www = False
# Set file from post DB when target is an article
#------------------------------------------------
try: post_src = db.uri_file
except: pass
if post_src:
target = "post"
try: post_db = db.config
except: pass
try: post_wip = db.post_wip
except: pass
try: post_www = db.post_www
except: pass
# Convert command action to do[]
# as edit* &nd show* [action] have same target file
actions = \
{
"show" : 'src',
"edit" : 'src',
"post" : 'src',
"preview" : 'wip',
"show-db" : 'db',
"edit-db" : 'db',
"show-wip" : 'wip',
"edit-wip" : 'wip',
"show-www" : 'www',
"edit-www" : 'www'
}
action = actions[args.action]
# Set target file from "new" [action]
do = \
{
'src' : {
"domain" : dom.config,
"footer" : dom.footer_f,
"metas" : dom.metas_f,
"navbar" : dom.navbar_f,
"sidebar" : dom.sidebar_f,
"post" : post_src
},
'db' : {
"domain" : dom.config,
"footer" : dom.footer_f,
"metas" : dom.metas_f,
"navbar" : dom.navbar_f,
"sidebar" : dom.sidebar_f,
"post" : post_db
},
'wip' : {
"domain" : dom.config,
"footer" : dom.wip_footer_f,
"metas" : dom.wip_metas_f,
"navbar" : dom.wip_navbar_f,
"sidebar" : dom.wip_sidebar_f,
"post" : post_wip,
"sitemap" : '%ssitemap.html'%dom.srv_wip,
"stats" : dom.wip_stats_f,
},
'www' : {
"domain" : dom.config,
"footer" : dom.www_footer_f,
"metas" : dom.www_metas_f,
"navbar" : dom.www_navbar_f,
"sidebar" : dom.www_sidebar_f,
"post" : post_www,
"stats" : dom.www_stats_f,
},
}
# Read or edit file, according to legacy args.action
file = do[action][target]
if not file:
logs.out("28", '%s + %s'%(args.action, args.target), True)
if not file or not tyto.exists(file):
logs.out("1", file, True)
# Except for show-about > Show post DB
if args.action == "preview":
preview_wip(file)
return
elif args.action in actions_read:
read_lines(file, True)
elif args.action in actions_edit:
curr_hash = tyto.get_filesum(file, True)
tyto.edit_file(file)
# If edit article and hash changed, ask to check
if args.action == "edit":
new_hash = tyto.get_filesum(file, True)
if curr_hash == new_hash: return
# Launch process for some changed file
#-------------------------------------
if file == post_src:
# Reload post DB (if edited article, and check it if ask "y")
importlib.reload(db)
check = subprocess.run(
[
'/usr/bin/tyto',
'check',
args.target
]
)
elif file == dom.sidebar_f: html.create_sidebar('wip')
elif file == dom.navbar_f: html.create_navbar('wip')
elif file == dom.metas_f: html.create_user_metas('wip')
#=====================================#
# Preview in browser wip page #
# Ensure xdg-open (useless in server) #
#-------------------------------------#
def preview_wip(file):
try: try:
xdg = subprocess.run( c = 0
[ for key, value in domain.ult_dlf.items("DOMAINS"):
'/usr/bin/xdg-open', if key: c += 1
file, print(": %s > %s"%(key,value))
], print("|\n; total =",c)
)
except: except:
logs.out("28", "/usr/bin/xdg-open %s"%file, True) debug.out(104, "False", domain.ult_dlf_uri, True, 1, False)

View File

@ -1,226 +0,0 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Create total statistics file for www or wip
# File: /var/lib/tyto/program/stats.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines : 226
# file comments : 38
# file functions: 4
# file program : 166
#--------------------------
import os, importlib
import args, dom, logs, form, tyto, show, langs
sti_articles = 0
#=======================#
# Manage "stats" option #
#-----------------------#
def manage(process):
dom.valid()
global file_uri, domain_srv
if process == 'wip':
file_uri = dom.wip_stats_f
domain_srv = dom.wip_url
elif process == 'www':
file_uri = dom.www_stats_f
domain_srv = dom.www_url
loop_articles(process)
#==========================#
# Check databases' article #
#--------------------------#
def loop_articles(process):
global sti_articles
# Get databases of articles
for db in os.listdir(dom.articles_db_d):
if not db.endswith('.config'):
continue
# Load DB
db = '%s%s'%(dom.articles_db_d, db)
exec(open(db).read(),globals())
# Check hash status (wip/www)
hash_srv = ''
if process == 'wip': hash_srv = hash_wip
elif process == 'www': hash_srv = hash_www
# - Now generic for wip and www
# - Article has changed and could have different stats
if not hash_srv or \
hash_srv != hash_chk:
continue
sti_articles += 1
if sti_articles == 1: count_stats(False)
else: count_stats(True)
# Create file if article
if sti_articles > 0: create_stats_file(file_uri)
else: logs.out("28", '%s stats'%process, True)
#===============================#
# False: Set First statistics #
# True: Count total statistics #
#-------------------------------#
def count_stats(add):
# Set
if not add:
global stats, authors, author_names
# Specific for Authors (not in database stats)
author_names = author.replace(' ', '').split(",")
authors = 0
stats = { \
"sti_uniq_anchors" : uniq_anchors,
"sti_uniq_abbrs" : uniq_abbrs,
"sti_uniq_links" : uniq_links,
"sti_uniq_images" : uniq_images,
"sti_uniq_files" : uniq_files,
"sti_uniq_codes" : uniq_codes,
"sti_uniq_raws" : uniq_raws,
"sti_comments" : comments,
"sti_tags" : tags,
"sti_lines" : lines,
"sti_words" : words,
"sti_titles" : titles,
"sti_paragraphs" : paragraphs,
"sti_links" : links,
"sti_images" : images,
"sti_anchors" : anchors,
"sti_abbrs" : abbrs,
"sti_strongs" : strongs,
"sti_bolds" : bolds,
"sti_emphasis" : emphasis,
"sti_italics" : italics,
"sti_dels" : dels,
"sti_underlines" : underlines,
"sti_cites" : cites,
"sti_customs" : customs,
"sti_icodes" : icodes,
"sti_bcodes" : bcodes,
"sti_quotes" : quotes,
"sti_lists" : lists,
"sti_files" : files,
"sti_raws" : raws,
"sti_codes" : codes,
}
# Count
else:
# Authors are not set in database stats
new_authors = author.replace(' ', '').split(",")
# Do not count author if known
for name in new_authors:
if name in author_names:
continue
author_names = author_names + [name]
# From database stats
for i in stats:
stat_db = i.rsplit("sti_")[1]
stats[i] = stats[i] + eval(stat_db)
#============================#
# Create stat file in server #
#----------------------------#
def create_stats_file(file_uri):
# Count authors
authors = len(author_names)
sti = \
'# Statistics file created by %s\n'%tyto.Tyto + \
'# Website: %s\n'%domain_srv + \
'# File: %s\n'%file_uri + \
'# Generated: %s\n'%tyto.nowdate() + \
'\n' + \
'# Uniq statistics from articles headers\n' + \
'articles = %d\n'%int(sti_articles) + \
'uniq_authors = %d\n'%int(authors) + \
'uniq_anchors = %d\n'%stats["sti_uniq_anchors"] + \
'uniq_abbrs = %d\n'%stats["sti_uniq_abbrs"] + \
'uniq_links = %d\n'%stats["sti_uniq_links"] + \
'uniq_images = %d\n'%stats["sti_uniq_images"] + \
'uniq_files = %d\n'%stats["sti_uniq_files"] + \
'uniq_codes = %d\n'%stats["sti_uniq_codes"] + \
'uniq_raws = %d\n'%stats["sti_uniq_raws"] + \
'\n' + \
'# Statistics from articles contents\n' + \
'comments = %d\n'%stats["sti_comments"] + \
'tags = %d\n'%stats["sti_tags"] + \
'lines = %d\n'%stats["sti_lines"] + \
'words = %d\n'%stats["sti_words"] + \
'titles = %d\n'%stats["sti_titles"] + \
'paragraphs = %d\n'%stats["sti_paragraphs"] + \
'links = %d\n'%stats["sti_links"] + \
'images = %d\n'%stats["sti_images"] + \
'anchors = %d\n'%stats["sti_anchors"] + \
'abbrs = %d\n'%stats["sti_abbrs"] + \
'strongs = %d\n'%stats["sti_strongs"] + \
'bolds = %d\n'%stats["sti_bolds"] + \
'emphasis = %d\n'%stats["sti_emphasis"] + \
'italics = %d\n'%stats["sti_italics"] + \
'dels = %d\n'%stats["sti_dels"] + \
'underlines = %d\n'%stats["sti_underlines"] + \
'cites = %d\n'%stats["sti_cites"] + \
'customs = %d\n'%stats["sti_customs"] + \
'icodes = %d\n'%stats["sti_icodes"] + \
'bcodes = %d\n'%stats["sti_bcodes"] + \
'quotes = %d\n'%stats["sti_quotes"] + \
'lists = %d\n'%stats["sti_lists"] + \
'\n' + \
'# Included files in articles contents\n' + \
'files = %d\n'%stats["sti_files"] + \
'codes = %d\n'%stats["sti_codes"] + \
'raws = %d\n'%stats["sti_raws"]
tyto.set_file(file_uri, 'New', sti)
try:
print('', langs.site.stats_f%(
sti_articles, stats["sti_words"]
)
)
except:
print(' └ Articles = %s ; Words = %s'%(
sti_articles, stats["sti_words"]
)
)

View File

@ -1,241 +0,0 @@
#!/usr/bin/env python3
# Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of the
# License, or of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Show statuses for commands, domain, article
# File: /var/lib/tyto/program/status.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines : 241
# file comments : 51
# file functions: 3
# file program : 170
#--------------------------
import os
import args, dom, logs
#=====================#
# Check domain status #
#---------------------#
def domain():
if dom.hole:
logs.out("13", '', True)
# Only condition to not check domain status here
if args.action == 'new' and \
args.target == "domain":
return
# As subprocesses, avoid show domain status each time
if args.action in args.quicks:
return
# [action] not in list
if args.act_err:
logs.out("11", args.action, True)
# No domain found
if not dom.exists:
logs.out("10", '', True)
# Domain id corrupted
if dom.corrupt:
logs.out("39", dom.shortname, True)
# Domain is incomplete
if dom.incomplete:
logs.out("41", dom.shortname, False)
# Show unused values
for err_val in dom.err_val:
logs.out("16", err_val, True)
# Domain not activated
if not dom.active:
logs.out("40", dom.shortname, True)
# Domain is activated
if dom.active:
logs.out("42", dom.shortname, False)
# No backward in [target]
if "../" in args.target:
logs.out("11", '"../"', True)
#===========================#
# Create unused directories #
#---------------------------#
import tyto
srv_show_wip = srv_show_www = local_show = dom_err = False
for value in dom.dom_values:
set_value = eval(str('dom.%s'%value))
# wip directories
if value.endswith('_d'):
if value.startswith("srv_wip"):
if not tyto.exists(set_value):
if not srv_show_wip:
print('\n │ [wip]')
srv_show_wip = True
try:
os.makedirs(set_value, exist_ok=True)
logs.out("33", set_value, False)
except:
logs.out("1", set_value, False)
dom_err = True
# www directories
elif value.startswith("srv_www"):
if not tyto.exists(set_value):
if not srv_show_www:
print('\n │ [www]')
srv_show_www = True
try:
os.makedirs(set_value, exist_ok=True)
logs.out("33", set_value, False)
except:
logs.out("1", set_value, False)
dom_err = True
# local directories
else:
if not tyto.exists(set_value):
if not local_show:
print('\n │ [local]')
local_show = True
try:
os.makedirs(set_value, exist_ok=True)
logs.out("33", set_value, False)
except:
logs.out("1", set_value, False)
dom_err = True
# Create missing modules files
import html
if not tyto.exists(dom.metas_f) or \
not tyto.exists(dom.wip_metas_f):
html.create_user_metas('new')
if not tyto.exists(dom.navbar_f) or \
not tyto.exists(dom.wip_navbar_f):
html.create_navbar('new')
if not tyto.exists(dom.sidebar_f) or \
not tyto.exists(dom.wip_sidebar_f):
html.create_sidebar('new')
if not tyto.exists(dom.footer_f) or \
not tyto.exists(dom.wip_footer_f):
html.create_user_footer('new')
#==============================#
# On demand with status action #
#------------------------------#
def check(target):
import db
# target needed
if not target:
logs.out("5", '[target]', True)
# Domain statuses
elif target == "domain":
# Check unused files in servers
logs.out("60", '', False)
check_domain_files("wip")
check_domain_files("www")
return
# target is an article
# Unused file
elif not db.post:
logs.out("1", db.uri_file, True)
# Article has DB
elif db.exists:
# Article datas
print('\n ├ [%s] > %s'%(db.title, db.uri_file))
# chk
if db.old_chk: logs.out("94", db.uri_file, False)
else: logs.out("20", db.uri_file, False)
# wip
print(' │ [wip]')
if not db.file_wip:
logs.out("91", db.post_wip, False)
else:
logs.out("92", db.post_wip, False)
# wip static
if db.static_wip: logs.out("96", db.post_wip, False)
else: logs.out("97", db.post_wip, False)
if db.no_wip: logs.out("98", db.post_wip, False)
elif db.old_wip: logs.out("99", db.post_wip, False)
else: logs.out("95", db.post_wip, False)
# www
print(' │ [www]')
if not db.file_www:
logs.out("91", db.post_www, False)
else:
logs.out("92", db.post_www, False)
# www static
if db.static_www: logs.out("96", db.post_wip, False)
else: logs.out("97", db.post_wip, False)
if db.no_www: logs.out("98", db.post_www, False)
elif db.old_www: logs.out("99", db.post_www, False)
else: logs.out("95", db.post_www, False)
return
# Article has NO DB
elif not db.exists:
logs.out("25", db.uri_file, True)
#=====================#
# Check servers files #
#---------------------#
def check_domain_files(srv):
import tyto
if srv == "www": template_files = dom.templates_files_www
elif srv == "wip": template_files = dom.templates_files_wip
else: return
dom_err = False
print(' │ [%s]'%srv)
for f in template_files:
if not tyto.exists(f):
dom_err = True
logs.out("1", f, False)
if not dom_err:
logs.out("28", 'tout va bien', False)

View File

@ -0,0 +1,113 @@
#!/usr/bin/env python3
# Tyto - Littérateur
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Tools used by Tyto - Littérateur
# File: /var/lib/tyto/program/tools.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines :
# file comments :
# file functions:
# file program :
#--------------------------
from hashlib import blake2b
import os, configparser
import debug
#========================#
# Return sum of src file #
# 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()
#========================================#
# Check directory: exit if out and log #
# Mainly used to check domain server dir #
#----------------------------------------#
def dir_exists(dir_path, out):
exists = bool(os.path.exists(dir_path))
if not exists:
if out: debug.out(6, "False", dir_path, True, 2, True)
else: debug.out(6, "False", dir_path, True, 2, False)
return False
return True
#============================#
# Create a new file and logs #
#----------------------------#
def create_file(file_path, contents):
up = bool(os.path.exists(file_path))
try:
with open(file_path, "w") as f:
f.write(contents)
except:
# Exit at error
debug.out(7, "False", file_path, True, 2, True)
if up: debug.out(207, file_path, False, 0, False)
else: debug.out(206, file_path, False, 0, False)
#===========================================#
# Update ini file, replacing existing value #
#-------------------------------------------#
def update_ini_file(file_path, section, key, val):
# Exit if no file
if not os.path.exists(file_path):
debug.out(5, "False", file_path, True, 2, True)
config = configparser.ConfigParser()
config.read(file_path)
config.set(section, key, val)
with open(file_path, "w") as f:
config.write(f)
#====================#
# Create directories #
#--------------------#
def create_dirs(path):
try:
if not os.path.exists(path):
os.makedirs(path, exist_ok=True)
debug.out(203, "True", path, False, 0, False)
except:
# Exit if not created
debug.out(5, "False", path, True, 2, True)

View File

@ -1,725 +1,179 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Tyto - Littérateur # Tyto - Littérateur
#
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org> # Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
#
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License # it under the terms of the GNU General Public License as published by
# as published by the Free Software Foundation, either version 3 of the # the Free Software Foundation, either version 3 of the License, or
# License, or of the License, or (at your option) any later version. # (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details. # GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re) # XMPP: echolib (im@echolib.re)
# #
# Description: Tools and some seetings. # Description: Templates, settings, values
# File: /var/lib/tyto/program/tyto.py # File: /var/lib/tyto/program/tyto.py
#---------------------------------------------------------------------- #----------------------------------------------------------------------
#------------------------- #
# Funny Stats Project # Arguments in command line #
#------------------------- #
# file lines : 725 actions = (
# file comments : 121 "check", "wip", "publish",
# file functions: 14 "new",
# file program : 522 "set",
#-------------------------- "show",
)
targets = (
"domain",
"domains",
"title", "date", "about", "mail", "tags", "lang", "server",
)
force_options = ("--force", "-F")
debug_options = ("--debug", "-D")
debug_errors = ('--errors', "-E")
import os, sys, re, subprocess, locale, base64, datetime, shutil #
from hashlib import blake2b #
import args, dom, logs, langs #
full_name = "Tyto - Littérateur"
web_url = "https://tyto.echolib.re"
git_url = "https://git.a-lec.org/echolib/tyto-litterateur"
# :D #===========================#
Tyto = 'Tyto - Littérateur' # Templates #==================================================
Tytogit = 'https://git.a-lec.org/echolib/tyto-litterateur' # Domain configuration file #
Tytoweb = 'https://tyto.echolib.re' #---------------------------#
ini_domain = """[DOMAIN]
activated = no
name =
title =
date =
about =
tags =
mail =
license = gfdl-1.3
license_url = https://www.gnu.org/licenses/fdl-1.3.txt
legals_url =
terms_url =
statuses_url =
[WEBSITE]
www_url =
wip_url =
lang =
css = tyto
separator = |
article_code = yes
static = no
# Needed header tags [WEBSITE_MODULES]
needed_header_tags = \ navbar = yes
( sidebar_title =
'title', sidebar_items = 6
'about', sitemaps = yes
'author', rss_items = 100
'tags',
'date'
)
# Optional header tags [TEMPLATE_FILENAMES]
opt_header_tags = \ favicon = favicon.png
( logo = logo.png
'file', styles = styles.css
'image', rss = rss.xml
'link', stats = stats.ini
'abbr',
'raw',
'code',
'snpic'
)
opt_tags_long_name = \ [USER_DIRS]
( root =
'link', articles =
'file' images =
) files =
modules =
database =
template =
opt_tags_check_uri = \ [USER_TEMPLATE_FILES]
( logo =
'image', favicon =
'file', styles =
'raw',
'code'
)
# Set all tags used in article's header [USER_MODULES_FILES]
headers = \ metas =
( header =
'title:', navbar =
'about:', sidebar =
'author:', footer =
'tags:',
'date:',
'link:',
'image:',
'file:',
'abbr:',
'code:',
'raw:',
'#',
'snpic:',
)
[SERVER]
root = /var/www/
domain =
# Words Tags (paragraphs, lists, bold, strong...) [WIP_DIRS]
# Used to check, and replace (wip) tags root =
# ! As base64 is used, do NOT set marker: =_ _= images =
# [5] = name for stats and log. files =
#------------------------------------------------------------- template =
icode_tags = \
(
'{_', '_}',
'<code class="icode">', '</code>',
'icodes',
'\\{_', '\\_}'
)
strong_tags = \ [WIP_FILES]
( favicon =
'*_', '_*', logo =
'<strong class="%s">'%dom.css, '</strong>', styles =
'strongs', rss =
'\\*_', '\\_*', stats =
'-S1-', '-S2-' metas =
) header =
navbar =
sidebar =
footer =
bold_tags = \ [WWW_DIRS]
( root =
'+_', '_+', images =
'<b class="%s">'%dom.css, '</b>', files =
'bolds', template =
'\\+_', '\\_+',
'-B1-', '-B2-'
)
em_tags = \ [WWW_FILES]
( favicon =
';_', '_;', logo =
'<em class="%s">'%dom.css, '</em>', styles =
'emphasis', rss =
'\\;_', '\\_;', stats =
'-EM1-', '-EM2-' metas =
) header =
navbar =
i_tags = \ sidebar =
( footer =
':_', '_:',
'<i class="%s">'%dom.css, '</i>',
'italics',
'\\:_', '\\_:',
'-I1-', '-I2-'
)
u_tags = \
(
'._', '_.', '<u class="%s">'%dom.css,
'</u>',
'underlines',
'\\._', '\\_.',
'-U1-', '-U2-'
)
del_tags = \
(
'~_', '_~',
'<del class="%s">'%dom.css, '</del>',
'dels',
'\\~_', '\\_~',
'-DE1-', '-DE2-'
)
cite_tags = \
(
'[_', '_]',
'<cite class="%s">'%dom.css, '</cite>',
'cites',
'\\[_', '\\_]',
'-CI1-', '-CI2-'
)
custom1_tags = \
(
'%_', '_%',
'<span class="custom">', '</span>',
'customs',
'\\%_', '\\_%',
'-CU1-', '-CU2-'
)
markers_tags = \
[
strong_tags,
bold_tags,
em_tags,
i_tags,
u_tags,
del_tags,
cite_tags,
custom1_tags,
]
# At begining line, create block contents
block_tags = [
('((', '))', '<p class="%s">', '</p>', 'paragraphs'),
('[[', ']]', '[[', ']]', 'quotes'),
('{{', '}}', '{{', '}}', 'bcodes'),
('-(', '-)', '-(', '-)', 'lists'),
('<<', '>>', '<div class="%s">', '</div>', 'div'),
]
# Anchor tags
anchor_tags = \
(
'>_', '_<',
'<a class="anchor_link" href="#%s">', '</a>',
'anchors'
)
# Tags that do not need to be paired
#-----------------------------------
single_tags = [
('|', '<br class="%s">'), # New Line
('->', '<a class="anchor_target" id="%s"></a>'), # Anchors
]
# When counting words, do no count line starting with:
nolinewords = \
(
block_tags[0][0], block_tags[0][1], # paragraphs
block_tags[1][0], block_tags[1][1], # quotes
block_tags[2][0], block_tags[2][1], # bcodes
block_tags[3][0], block_tags[3][1], # lists
single_tags[0][0], single_tags[1][0], # New line, anchor
'_%s:'%opt_header_tags[1], '_%s:'%opt_header_tags[4], # _image:, _raw:
'_%s:'%opt_header_tags[5] # _code
)
# warning symbols (Check if paired)
#----------------------------------
tpl_tags = [
('(', ')'),
('[', ']'),
('{', '}'),
('«', '»'),
]
# When including HTML in article, check some paired tags
#-------------------------------------------------------
leg_html_tags = [
('<!--', '-->'),
('<div', '</div>'),
('<ul', '</ul>'),
('<li', '</li>'),
('<p', '</p>'),
('<span','</span>'),
]
# Markers for lists, to check in list content
#--------------------------------------------
markers_lists = ('+', '=', ' ', '#')
# Tags used for titles
#---------------------
titles_user = ('#1', '#2', '#3', '#4', '#5')
titles_html = ('<h1', '<h2', '<h3', '<h4', '<h5', '<h6')
titles_tags = [
("", "",),
('#1 ', '<h2 class="title_2">%s</h2>'),
('#2 ', '<h3 class="title_3">%s</h3>'),
('#3 ', '<h4 class="title_5">%s</h4>'),
('#4 ', '<h5 class="title_6">%s</h5>'),
('#5 ', '<h6 class="title_6">%s</h6>')
]
# Tags for quote
quote_tags = [
('_cite:', 'author'),
('_date:', 'date'),
('_link:', 'link'),
('_book:', 'book'),
('_lang:', 'lang')
]
# Tags to check in header in content _TAG
head_tags = ("image:", "raw:", "code;")
# Valid characters for some datas
chrs_invalid = \
set('{}[]_()+*=/:%~´')
new_article = """%s
# Tyto - Litterateur (tyto new %s)
title:
about:
author: %s
tags:
date: %s
#abbr: TYTO
Le générateur de sites web Libre
Tyto - Littérateur
# Use this image for social networks
#snpic: Pic-1
#image: Pic-1
URI
Texte-alternatif
#link: lien 1
URI/URL
Text-alternatif
-----
#_image:Pic-1 c=title_class
#1
((
))
[TYTO]
domain_hash =
domain_conf =
domain_user =
""" """
# Stats for icodes, bcodes, quotes # Template file configuration for each a created domain
nbr_icodes = 0
#=======#
# TOOLS #
#=======#--------------------------------------------------------------
# #
# Return True if file exists ini_domain_user = """[DOMAIN]
# name =
def exists(uri): hash =
if os.path.exists(uri): return(True) root =
else: return(False) conf =
[SERVER]
root =
"""
#========================================# ini_domains_list = """[DOMAINS]
# Return converted valid HTML characters # """
#----------------------------------------#
def convert_altname(altname):
altname = altname.replace('<', '&lt;')
altname = altname.replace('>', '&gt;')
altname = altname.replace('"', '&quot;')
altname = altname.replace("'", '&apos;')
return altname
#=======================#
# 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 #
#------------------------------#
def nowdate():
now = datetime.datetime.now()
return(now.strftime('%Y-%m-%d %H:%M:%S'))
#======================#
# Open and edit a file #
#----------------------#
def edit_file(edit_file):
if not os.path.exists(edit_file):
logs.out("1", edit_file, True)
try:
file_edit = subprocess.run(
[
'/usr/bin/nano',
'--linenumbers',
edit_file
]
)
except:
logs.out("1", "/usr/bin/nano", True)
#=====================#
# Create a file #
# Or append text #
# new: True = create #
# False = Append #
#---------------------#
def set_file(path, new, text):
if new: opt = "w"
else: opt = "a"
try:
file = open(path, opt)
file.write(text)
file.close()
if opt == 'w':
logs.out("32", path, False)
except:
logs.out("4", path, True)
#==========================#
# Get CSS from line if set #
#--------------------------#
def get_css(line):
# Use this default, if not in conf
css = 'tyto'
try: css = dom.css
except: pass
# Get CSS from line
try: css = re.search (r'(?<=' ') +([^ -.]*)', line).group(1)
except: pass
return css
#==============================#
# Replace escaped markers #
# check: with "" #
# wip: with altternate #
# reverse: True/False #
#------------------------------#
def protect_escaped(post_bottom, reverse):
for m1, m2, h1, h2, n, e1, e2, r1, r2 in markers_tags:
# In check mode, No need to keep escaped markers
if args.action == "check":
r1 = r2 = ''
if reverse:
post_bottom = post_bottom.replace(r1, m1)
post_bottom = post_bottom.replace(r2, m2)
else:
post_bottom = post_bottom.replace(e1, r1)
post_bottom = post_bottom.replace(e2, r2)
return post_bottom
#=============================================#
# First check process to protect contents #
# Protect block-Codes, quotes #
# Also remove empty/commented lines #
# Used in check and wip #
# check: create string without quotes, bcodes #
# wip: remplace quotes, bcode with base64 #
#---------------------------------------------#
def protect_bcodes_quotes(process, post_bottom):
global protect_article
global nbr_titles, nbr_bcodes, nbr_quotes # Stats for DB
in_bcode = in_quote = False
protect_article = ''
bcode = quote = '' # Only for wip process
for line in post_bottom.rsplit('\n'):
start_bcode = close_bcode = False
start_quote = close_quote = False
# Settings and counters
#----------------------
# Bcode (at close, replace with base64)
if not in_quote:
if line.startswith(block_tags[2][0]): # Open
start_bcode = True
in_bcode = True
elif line.startswith(block_tags[2][1]): # Close
close_bcode = True
in_bcode = False
if process == "wip":
bcode = '%s\n%s'%(bcode, line)
bcode = convert_altname(bcode)
b64_bcode = b64('Encode', bcode, 'B64.', '.B64')
line = b64_bcode
# Quote (at close, replace with base64)
if not in_bcode:
if line.startswith(block_tags[1][0]): # Open
start_quote = True
in_quote = True
elif line.startswith(block_tags[1][1]): # Close
close_quote = True
in_quote = False
if process == "wip":
quote = '%s\n%s'%(quote, line)
quote = convert_altname(quote)
b64_quote = b64('Encode', quote, 'Q64.', '.Q64')
line = b64_quote
# Counters and keep tags for check process
#-----------------------------------------
if process == "check":
if in_bcode and not start_bcode \
or in_quote and not start_quote :
line = '#-Protectedline-'
# Set new article content for wip process
#----------------------------------------
elif process == "wip":
# Remove empty line and comments
if not in_quote and not in_bcode:
if not line:
continue
elif line.startswith('#') and not line.startswith(titles_user):
continue
# bcode convertion to base64
elif in_bcode:
# Convert lines to b64
if not bcode: bcode = line
else: bcode = '%s\n%s'%(bcode, line)
line = ''
continue
elif in_quote:
# Convert lines to b64
if not quote: quote = line
else: quote = '%s\n%s'%(quote, line)
line = ''
continue
# Set new content
#----------------
# check: remove quote/bcode, keep tags
# wip: replace close tag with quote/bcode (keep in open tag)
if not protect_article: protect_article = line
else: protect_article = '%s\n%s'%(protect_article, line)
# Clean in wip process for new quote/bcode
if process == "wip":
if close_bcode: bcode = b64_bcode = ''
if close_quote: quote = b64_quote = ''
#=======================================#
# Protec iCodes #
# Used in check and wip #
# Methode: iterate (c)haracter in lines #
# check: remove icdoe #
# wip: convert to b64 #
#---------------------------------------#
def protect_icodes(post_bottom):
global nbr_icodes
# Get only lines that contains code
in_icode = ok_icode = go_icode = False
for ln, line in enumerate(post_bottom.rsplit('\n')):
if not icode_tags[0] in line or \
not icode_tags[1] in line:
continue
code = ""
for i, c in enumerate(line):
if c == "_":
try:
# {_
if line[i-1] == icode_tags[0][0] and line[i-2] != "\\":
in_icode = True
ok_icode = False
#go_icode = True
continue
# _}
elif line[i+1] == icode_tags[1][1] and line[i-2] != "\\":
in_icode = False
ok_icode = True
go_icode = False
except:
continue
if in_icode:
ok_icode = False
code = "%s%s"%(code, c)
# End icode
if ok_icode:
nbr_icodes += 1
tyto_code = "%s%s%s"%(icode_tags[0], code, icode_tags[1])
if args.action == "check":
post_bottom = \
post_bottom = post_bottom.replace(tyto_code , '')
elif args.action == "wip":
code = convert_altname(code) # HTML sympbols
html_code = "%s%s%s"%(
icode_tags[2], code, icode_tags[3])
b64_code = b64('Encode', html_code, 'I64.', '.I64')
post_bottom = post_bottom.replace(tyto_code, b64_code)
# Reset for next
code = tyto_code = html_code = b64_code = ""
ok_icode = False
post_bottom = post_bottom.replace("\\%s"%icode_tags[0], icode_tags[0])
post_bottom = post_bottom.replace("\\%s"%icode_tags[1], icode_tags[1])
return post_bottom
#=====================================#
# Encode/Decode string to/from base64 #
# Data protection in UTF8 #
#-------------------------------------#
def b64(action, content, before, after):
if action == 'Encode':
global b64_content
b64_base64 = ''
content_bytes = content.encode("utf8")
base64_bytes = base64.b64encode(content_bytes)
b64_content = before + base64_bytes.decode("utf8") + after
return b64_content
elif action == 'Decode':
global src_content
src_content = ''
content_bytes = content.encode("utf8")
base64_bytes = base64.b64decode(content_bytes)
src_content = base64_bytes.decode("utf8")
return src_content
else:
print("Options: 'Encode', 'Decode'")
sys.exit(1)
#====================================#
# Replace in post_db #
# Used for wip and publish #
# to replace hash and date when done #
#------------------------------------#
def change_in_db(db_file, db_values):
try: post_db = open(db_file, "r").read()
except: logs.out("1", db_file, True)
for value in db_values:
old_value = re.findall(r'%s\s+=\s+%s'%(
value[0],value[1]
), post_db
)[0]
new_value = old_value.replace(value[1], value[2])
if new_value != old_value:
post_db = post_db.replace(old_value, new_value)
set_file(db_file, 'New', post_db)
#===================================#
# Copy files used by article to srv #
#-----------------------------------#
def files_to_srv(server):
import db
for uri in db.uris:
# Extract Directories from uri file
d_in = uri.split("/")[-1]
d_in = uri.rsplit(d_in)[0]
# Destination file and directories according to server
# (remove last / from domain directory value)
f_src = '%s%s'%(dom.articles_d[:-1], uri)
if server == 'wip':
f_dst = '%s%s'%(dom.srv_wip[:-1], uri)
d_dst = '%s%s'%(dom.srv_wip[:-1], d_in)
elif server == 'www':
f_dst = '%s%s'%(dom.srv_www[:-1], uri)
d_dst = '%s%s'%(dom.srv_www[:-1], d_in)
# Create sub-directories in server
try:
if os.makedirs(d_dst, exist_ok=True):
logs.out("33", d_dst, False)
except:
logs.out('4', d_dst, True)
# COpy files to server
try:
shutil.copy2(f_src, f_dst)
logs.out("32", f_dst, False)
except:
logs.out('4', f_dst, True)
# Copy source post file in server
# if article_code is True in domain DB
if dom.article_code:
if server == "wip": base_srv = dom.srv_wip
elif server == "www": base_srv = dom.srv_www
f_dst = "%s%s"%(base_srv, db.short_src)
try:
shutil.copy2(db.post_src, f_dst)
logs.out("32", f_dst, False)
except:
logs.out('4', f_dst, True)
#========================================#
# For mass treatment, show message about #
#----------------------------------------#
def show_multi_message(server, srv_dir):
if args.target == "added":
print("%s '%s' > %s"%(langs.site.srv_added, server, srv_dir))
elif args.target == "updated":
print("%s '%s' > %s "%(langs.site.srv_updated, server, srv_dir))
elif args.target == "again":
print("%s '%s' > %s"%(langs.site.srv_again, server, srv_dir))
# Domain keys that can be empty
opt_domain_keys = ("legals_url", "terms_url", "statuses_url")

View File

@ -0,0 +1,53 @@
#!/usr/bin/env python3
# Tyto - Littérateur
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: When user wants to set something (mainly in domain)
# File: /var/lib/tyto/program/set.py
#----------------------------------------------------------------------
#-------------------------
# Funny Stats Project
#-------------------------
# file lines :
# file comments :
# file functions:
# file program :
#--------------------------
import langs, forms
#====================================#
# Manage arguments from command line #
# Specific to action "set #
#------------------------------------#
def manage(action, target):
do = {
"title" : forms.ask_domain_title,
"date" : forms.ask_domain_date,
"about" : forms.ask_domain_about,
"mail" : forms.ask_domain_mail,
"lang" : forms.ask_domain_lang,
"server" : forms.ask_domain_server,
}
do[target]()

File diff suppressed because it is too large Load Diff

View File

@ -1,89 +1,64 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Name: Tyto - Littérateur # Tyto - Littérateur
# Type: translation file
# Description: Only for logs (internal messages) [en]
# file: logs_en.py
# Folder: /var/lib/tyto/translations/
# By echolib (XMPP: im@echolib.re)
# Repo: https://git.a-lec.org/echolib/tyto.git
# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
#********************************************************************** # Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
# Generic # This program is free software: you can redistribute it and/or modify
sidebar = 'Sidebar' # it under the terms of the GNU General Public License as published by
navbar = 'Navbar' # the Free Software Foundation, either version 3 of the License, or
meta_t = '<meta> tag' # (at your option) any later version.
time_t = '<time> tag'
metas = 'Metas Tags'
footer = 'Footer'
line = "Ligne"
no_up = "not updated"
ntd = "Nothing to do"
all_ok = "All is OK"
nonewpost = "No new article"
unused_r = "Unused ressource"
unused_c = "Unused database value"
db_inv = "Corrupted article's database"
err_arg = "Argument error"
no_arg = "Unused argument"
no_fidi = "Black Hole: no file or directory here"
dom_ina = "Inactive domain"
dom_inc = "Incomplete domain"
dom_act = "Active domain"
dom_cor = "Corrupted domain"
data_inc = "Incomplete data"
data_inv = "Invalid data"
dom_no = "No domain found"
file_c = "File created" # This program is distributed in the hope that it will be useful,
file_n = "File changed" # but WITHOUT ANY WARRANTY; without even the implied warranty of
file_e = "File exists" # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
dir_c = "Directory created" # GNU General Public License for more details.
dir_e = "Directory exists"
post_exists = "Ab article already exists"
# chk # You should have received a copy of the GNU General Public License
shebang_r= 'Remove shebang' # along with this program. If not, see <https://www.gnu.org/licenses/>..
nycheck = "Article not yet checked"
was_chk = "Article was 'check'"
st_chk_o = "Old 'check' status"
post_inc = "Unused in article"
post_inv = "Article not valid"
post_val = "Article is valid"
title_no = "Empty title"
unused_p = "Empty article"
# wip #----------------------------------------------------------------------
nywip = "Article not yet wip" # XMPP: echolib (im@echolib.re)
was_wip = "Article was 'wip'" #
# Description: English logs translation file
# File: /var/lib/tyto/translations/logs_en.py
#
# How to translate:
# - create filename logs_xx.py in /var/lib/tyto/translations/
# where xx are 2 first lang letters (es, for spanish...)
# - copy its contents and translate values
#----------------------------------------------------------------------
# www # Note: python file
was_pub = "Article was published"
# Misc # Réponses valides (! NON sensible à la case : oui = OUI, Oui...)
post_nfd = "Page not found" ok = ("yes", "y")
post_yfd = "Page found"
static_y = "Page is static"
static_n = "Page not static"
status_n = "Status: unused"
status_o = "Status: old"
status_s = "Status: up to date"
check_m = "Check manually"
post_chg = "Article changed: 'check' it first"
sep_inv = "Unused separator in article"
unused_v = "Unused value in article"
unused_t = "Unused value in header"
mark_np = "Not paired marks"
symb_np = "Not paired symbols"
snpic_d = "Using default snpic. Not found"
anch_nu = "Anchor not uniq"
nyfile = "file not yet created"
add = "Add:"
nomods = "Create HTML modules first"
status_r = "Checking unused ressources..."
was_wip = "Article already 'wip'"
laterout = "Maybe later..." #
# Show HELP
#
help_contents = """
tyto [action] [target] [options]
[action]
new : create new domain (reset with -F)
set : set website lang, domain values (title, server...)
check :
wip :
publish :
[target]
domain : all about current domain home
domains : list all registred domains
title : [set]: domain title
date : [set]: domain creation date
about : [set]: domain description
mail : [set]: domain admin mail
tags : [set]: domain tags (added to all articles)
lang :
server : [set]: server local URI
[options] ; multi-set
--force, -F : force doing things...
--debug, -D : show more logs
--errors, -E : Show only warn and error logs
"""

View File

@ -1,88 +1,108 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Nom: Tyto - Littérateur # Tyto - Littérateur
# Type: Fichier de traduction
# Description: Seulement pour les logs (messages internes) [fr]
# Fichier: logs_fr.py
# Dossier: /var/lib/tyto/translations/
# Par echolib (XMPP: im@echolib.re)
# Dépôt: https://git.a-lec.org/echolib/tyto.git
# Licence: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
#********************************************************************** # Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
# Generique # This program is free software: you can redistribute it and/or modify
sidebar = 'Barre Latérale' # it under the terms of the GNU General Public License as published by
navbar = 'Barre de navigation' # the Free Software Foundation, either version 3 of the License, or
meta_t = 'Balise <meta>' # (at your option) any later version.
time_t = 'Balise <time>'
metas = 'Balises Metas'
footer = "Pied de Page"
line = "Line"
no_up = "non mise à jour"
ntd = "Rien à faire"
all_ok = "Tout va bien"
nonewpost = "Rien de nouveau"
unused_r = "Ressource manquante"
unused_c = "Valeur de la base de donnée manquante"
db_inv = "Base de donnée de l'article corrompue"
err_arg = "Erreur d'argument"
no_arg = "Argument manquant"
no_fidi = "Trou Noir: aucun fichier ou dossier ici"
dom_ina = "Domaine inactif"
dom_inc = "Domaine incomplet"
dom_act = "Domaine actif"
dom_cor = "Domaine corrompu"
data_inc = "Donnée incomplète"
data_inv = "Donnée invalide"
dom_no = "Aucun domaine trouvé"
file_c = "Fichier créé"
file_n = "Fichier modifié"
file_e = "Fichier présent"
dir_c = "Dossier créé"
dir_e = "Dossier présent"
post_exists = "Un article existe déjà"
# chk # This program is distributed in the hope that it will be useful,
shebang_r= 'Enlever le shebang' # but WITHOUT ANY WARRANTY; without even the implied warranty of
nycheck = "Article pas encore 'check'" # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
was_chk = "Article déjà vérifié" # GNU General Public License for more details.
st_chk_o = "Statut 'check' Ancien"
post_inc = "Donnée manquante dans l'article"
post_inv = "Article non valide"
post_val = "Article valide"
title_no = "Titre vide"
unused_p = "Article vide"
# Wip # You should have received a copy of the GNU General Public License
nywip = "Article pas encore 'wip'" # along with this program. If not, see <https://www.gnu.org/licenses/>..
was_wip = "Article déjà 'wip'"
# www #----------------------------------------------------------------------
was_pub = "Article déjà publié" # XMPP: echolib (im@echolib.re)
#
# Description: Fichier français de traduction des logs
# File: /var/lib/tyto/translations/logs_fr.py
#
# Comment traduire :
# - créer un fichier nommé logs_xx.py dans /var/lib/tyto/translations/
# oû xx sont les 2 première lettres de la langue (es, pour espagnol...)
# - Copier ce contenu dedans, et traduire les variables
#----------------------------------------------------------------------
# Misc # Rappel: Fichier au format python
post_nfd = "Page non présente"
post_yfd = "Page présente"
static_y = "Page statique"
status_n = "Statut : non présent"
status_o = "Statut : ancien"
status_s = "Statut : à jour"
static_n = "Page non statique" # Réponses valides (! NON sensible à la case : oui = OUI, Oui...)
check_m = "Vérifier manuellement" ok = ("oui", "o")
post_chg = "Article modifié : commencer par 'check'"
sep_inv = "Séparateur manquant dans l'article" # Form
unused_v = "Valeur manquante dans l'article" q = " ?"
unused_t = "Valeur manquante dans l'entête" configure_domain = "Configurer le domaine"
mark_np = "Marqueurs non jumelés" domain_title = "Titre du domaine"
symb_np = "Symboles non jumelés" domain_date = "Date de création"
snpic_d = "snpic utilisé par défaut. Manquant" domain_about = "Description du domaine"
anch_nu = "Ancre non unique" domain_mail = "Courriel de l'administration"
nyfile = "Fichier pas encore créé" domain_tags = "Mots-clés génériques [1,2,3]"
domain_lang = "Langue du site web"
domain_srv = "URI du serveur"
# logs for debug
#---------------
# Errors
err_arg = "Argument invalide"
err_hole = "Dossier courant invalide"
err_date = "Format de date invalide"
err_lang = "Format de langue invalide"
err_dir = "Dossier non compatible"
err_no_dir = "Dossier inexistant"
err_cd = "Dossier non créé"
err_no_file = "Fichier manquant"
err_cr_file = "Fichier non créé"
# Warnings
warn_no_dom = "Domaine non configuré"
reset_dom = "RÉINITIALISE le domaine"
# infos
load_file = "Chargement du fichier"
lang_logs_sys = "Langue des logs"
website_lang = "Langue du site web"
domains_no = "Aucun domaine trouvé"
domain_found = "Domaine présent"
domain_created = "Domaine déjà créé"
domain_updated = "Domaine mis à jour"
domain_new = "Domaine créé"
created_dir = "Dossier créé"
created_file = "Fichier créé"
updated_file = "Fichier mis à jour"
later = "Peut-être plus targ..."
add = "Ajout:"
nomods = "Créer d'abord les modules HTML"
status_r = "Vérification des ressources manquantes..."
laterout = "Pour plus tard..." #
# Show HELP
#
help_contents = """
tyto [action] [target] [options]
[action]
new : créer un nouveau domaine (réinitialisé avec -F)
set : définir la langue du site web, du domaine (titre, serveur...)
show : [domains]
check :
wip :
publish :
[target]
domain : pour tout ce qui concerne un domaine
domains : montre tous les domaines enregistrés
title : [set]: titre du domaine
date : [set]: date de création du domaine
about : [set]: description du domaine
mail : [set]: courriel de l'administrateur
tags : [set]: étiquettes du domaine (ajoutées aux articles)
lang :
server : [set]: URI du serveur local
[options] ; multiples
--force, -F : forcer à faire quelque chose...
--debug, -D : montrer plus de logs
--errors, -E : montrer uniquement les avertissement et erreurs
"""

View File

@ -1,342 +0,0 @@
#!/usr/bin/env python3
# Name: Tyto - Littérateur
# Type: translation file
# Description: Only for website [en]
# file: site_en.py
# Folder: /var/lib/tyto/translations/
# By echolib (XMPP: im@echolib.re)
# Repo: https://git.a-lec.org/echolib/tyto.git
# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
#**********************************************************************
# IMPORTANT Instructions
#-----------------------
# This is a python file, so... DO NOT REMOVE:
# - "#"
# - "%s", "%d"
# - "\n"
# - "+ \"
# Keep array ! ('','',)
yes = ("y", "yes",)
# Generic
article = "Article"
links = "links"
sidebar = 'Sidebar'
navbar = 'Navbar'
metas = 'Metas Tags'
footer = 'Footer'
title = 'Title'
File = 'File'
name = 'Name'
by = "by"
le = "the"
fo = "for"
proceed = "Continue"
q = '?'
i = '!'
pp = ":"
# Website
#----------------------------------------------------------------------
# Misc.
source_code = "Source code"
home = "Home"
go_home = "Go to Homepage"
read = "Read"
tyto_psrc = "Source code in Tyto format of"
w_written = "was written the"
w_published = "was published the"
written = "written the"
author_of = "is the uthor of"
# Sidebar
site_sdb_t = "Featured..."
# Footer
tyto_site_t = "Official website of %s, the Libre websites generator"
tyto_git_t = "%s's official source code repository"
legal_t = "Legal notice"
terms_t = "Terms of Use"
terms_s = "T.o.U"
law = "Law"
about = "About"
add_inf = "additional Informations %s"%about.lower()
licence = "License"
contact = "Contact"
mail = "Mail"
mail_to = "Contact by %s the admin of"%mail.lower()
feed = "Feed"
generator = "Generator"
# Misc for Tyto
#--------------
# Check
check_a = "Check again this article"
post_chg = "Article was edited. Check it"
new_post = "Create article"
# Wip
wip_new = "Create a new HTML page in 'wip' server again"
srv_again = "Create again converted HTMl pages in server"
srv_added = "Create missing HTML pages in server"
srv_updated = "Update HTMl pages in server"
wip_in_mod = "Include static module"
# publish
publish_a = "Publish again this article"
rss_c = "Create ATOM/RSS feed"
# Other
uptpl = "Update directory"
stats_f = "Articles: %s (%s words)"
reg_domains = "Registred domains"
sitemap_gen = "Sitemap generated by"
sitemap_t = "Sitemap"
# Form
#----------------------------------------------------------------------
form_edit = "Edit the domain with the form"
form_start = ' ├──────────────────────────────────────────────┐\n' + \
' │ Configure a new domain for current directory │\n' + \
' │ Answer Y/y = yes. Enter to keep {default}\n' + \
' │ Empty Answer cancel process, except for │\n' + \
' │ - [Optional] │\n' + \
' │ - known {default} value │\n' + \
' ├──────────────────────────────────────────────┘'
form_warn = '\n' + \
' ├──────────────────────────────────────┐\n' + \
' │ Please, READ the configuration datas │\n' + \
' ├──────────────────────────────────────┘'
form_ready = '\n' + \
' ├──────────────────────────────────────┐\n' + \
' │ Domain is ready. Have fun, writers ! │\n' + \
' └──────────────────────────────────────┘'
form_inv = '\n' + \
' ├─────────────────────────────────────┐\n' + \
' │ Domain is INVALID. Try form again ! │\n' + \
' └─────────────────────────────────────┘'
form_opt = "[Optional]"
form_url = "URL to official website"
form_wip = "URL to 'wip' website"
form_db_new = "Created new database"
form_trlog = "[2 char.] Logs language"
form_srv = "Local server directory"
form_logo = "Logo filename"
form_fav_f = "Favicon filename !(.png)"
form_css_f = "CSS filename"
form_rss_f = "Atom/RSS filename"
form_rss_i = "Atom/RSS articles' number"
form_title = "Website title"
form_date = "Domain creation year"
form_about = "Domain Description"
form_mail = "Webmaster's mail"
form_tags = "[comma separated] Domain tags"
form_lic = "Domain License"
form_licurl = "License URL"
form_legal = "Legal Notice URL"
form_terms = "Terms of Use URL"
form_css = "[alnum] CSS Prefix"
form_sep = "[1 char.] Pages titles separator"
form_pscode = "Show Article source code"
form_relme = 'rel="me" URL'
form_trsite = "[2 char.] Website language"
form_sdb_i = "Article number"
form_activ = "Activate and prepare domain"
form_dir_e = "Directory exists"
form_dir_c = "Directory created"
form_file_e = "File exists"
form_file_c = "File created"
form_reset = "Reset configuration"
form_rep = "Replace HTML file"
# Documentation of configuration files
#-------------------------------------
metas_inf = "Create <meta> tags"
metas_doc = \
'# For %s\n' + \
'# Type text/HTML file\n' + \
'# Description Configuration file for HTML <metas> tags\n' + \
'# Content inserted in <head> section\n' + \
'# File %s\n' + \
'# How Insert <metas ...> and <link ...>\n' + \
'# Notes - Ony these tags are added :\n' + \
'# - <metas>\n' + \
'~ - <link>\n' + \
'# - Do NOT copy this file to template directory\n' + \
'# - These tags are already set'
navbar_inf = "Create navbar"
navbar_doc = \
'# For %s\n' + \
'# Type: Text file\n' + \
'# Description Configuration file for navbar"\n' + \
'# (directories\'s list)\n' + \
'# Commands tyto new navbar (reset)\n' + \
'# tyto wip/publish navbar (Create)\n' + \
'# tyto show navbar (show config)\n' + \
'# tyto show-wip/show-www navbar (Show HTML)\n' + \
'# tyto edit navbar (edit this file)\n' + \
'# File %s\n' + \
'# Comment 1 folder name per line *1\n' + \
'# (from articles/)\n' + \
'# not begining with "/"\n' + \
'# Order in sidebar position\n' + \
'# Remember To avoid 404 error, you must:\n' + \
'# - add article index.{tyto}\n' + \
'# in set folder\n' + \
'# - check and wip article\n' + \
'# *1 Option To define a title link:' + \
'# - add "# title link"\n' + \
'\n# %s\n'%(20 * "-") +\
'# Examples :\n' + \
'# documentation\n' + \
'# about # infos about this website\n' + \
'# %s\n\n'%(20 * "-")
sidebar_inf = "Create sidebar"
sidebar_doc = \
'# For %s\n' + \
'# Type Text file\n' + \
'# Description Configuration file for sidebar\n' + \
'# (articles\'s list)\n' + \
'# File %s\n' + \
'# Commands tyto new sidebar (reset)\n' + \
'# tyto wip/publish sidebar (Create)\n' + \
'# tyto show sidebar (Show config)\n' + \
'# tyto show-wip/show-www sidebar (Show HTML)\n' + \
'# tyto edit sidebar (edit this file)\n' + \
'# How 1 article URI per line\n' + \
'# (from articles/)\n' + \
'# not begining with "/"\n' + \
'# Order in sidebar position\n' + \
'# Max articles = %d\n' + \
'# Option Tp set sidebar title:\n' + \
'# ": Sidebar Title"\n' + \
'\n# %s\n'%(20 * "-") + \
'# Examples :\n' + \
'# : My new articles list'
'# index.tyto\n' + \
'# dir1/index.tyto\n' + \
'# %s\n\n'%(20 * "-")
footer_inf = "Create footer"
footer_doc = \
'# For %s\n' + \
'# Type text/HTML file\n' + \
'# Description Configuration file for footer\n' + \
'# File %s\n' + \
'# Commands tyto new footer (reset)\n' + \
'# tyto wip/publish footer (Create)\n' + \
'# tyto show footer (Show config)\n' + \
'# tyto show-wip/show-www footer (Show HTML)\n' + \
'# tyto edit footer (edit this file)\n' + \
'# How Put any HTML code\n' + \
'# Notes - Lines are ignored if:\n' + \
'# - empty\n' + \
'# - begin with "#"\n' + \
'# - Do NOT copy to template directory'
'# %s\n'%(20 * "-")
# Help with Tyto commands
args_helps = """\n# New domain :
- Create directory and go in
- Create domain with 'tyto new domain [URL]'
- Create .tyto file in directory "articles/"
- Use these actions: check > wip > publish
! - Modules files are in directory "_configs/"
and used to custom some website parts
- (css, logo...) files go in "wip/template/"
# Usage: tyto [action] [target]
# [action] > withour [target]
version : Show installed version
domains : Show installed domains
help : Show commands help
# [action] > According to [target]
# Edit a file
edit : Source file, configuration module
edit-about: [footer] Edit description section in footer
or same as [edit-db]
edit-db : Edit database/configuration file
edit-wip : Edit a file in server 'wip'
edit_www : Edit a file in server 'www'
new : [domain] Créer un domaine ou le modifier via le formulaire
[sidebar, navbar, footer, metas] Create and replace
with default module configuration file
[filename] (no .tyto) Create article in current folder
[sitemap], create new website sitemap
# Show contents file (with line number)
show : Show source file, source configuration module
show-about: [footer] Show description footer file
or same as [show-db]
show-db : Show database/configuration file
show-wip : Show a file in server 'wip'
show-www : Show a file in server 'www'
# Create HTML page
check : Check the validity of a tyto format file
wip : Create article HTML page in server 'wip'
force-wip : [file], check, and then, wip
preview : [module]/[file], open 'wip' file on default browser
publish : Create article HTML page in server 'www'
quick-pub : [file], check, wip, publish
# [target] > According to [action]
# Multiple articles
updated : Update articles (already checked)
again : Force all articles (already checked)
added : [check] Search and check for .tyto articles in domain
(not yet checked)
[wip, publish] Create articles HTML pages
that were edited and checked
# Update modules/files template
template : - Create (replace) modules in directory "template/"
- [publish] Also, copy all other files from "wip/template/"
# Domain and files
domain : Create or edit a domain
[file] : URI file (autocompletion friendly)
# Modules
footer : Footer configuration file
metas : <meta>, <link> configuration file
navbar : Navbar configuration file
sidebar : Sidebar configuration file
stats : Stats file (server 'wip' er 'www')
sitemap : sitemap.tyto/.html file
# [option] :
--static : Créer une page HTML entièrement statique
--no-mods : With [publish template], do not recreate modules
"""
ex_helps = """# Examples :
# Check article (according to sub-folder)
$ tyto check mysubdir/index.tyto
# Create (replace) default sidebar configuration file
$ tyto new sidebar
# Edit navbar configuration file
$ tyto edit navbar
# edit doc/index.html in server 'www'
$ tyto edit-www doc/index.tyto
# Create HTML sidebar file in server 'wip'
$ tyto wip sidebar
# Show footer HTML file in server 'wip'
$ tyto show-wip footer
# Create statistics file in serveur 'www'
$ tyto publish stats"""

View File

@ -1,339 +0,0 @@
#!/usr/bin/env python3
# Nom: Tyto - Littérateur
# Type: Fichier de traduction
# Description: Seulement pour le site web [fr]
# Fichier: site_fr.py
# Dossier: /var/lib/tyto/translations/
# Par echolib (XMPP: im@echolib.re)
# Dépôt: https://git.a-lec.org/echolib/tyto.git
# Licence: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
#**********************************************************************
# Instructions IMPORTANTES
#-------------------------
# Ceci est un fichier python, donc... NE PAS ENLEVER :
# - "#"
# - "%s", "%d"
# - "\n"
# - "+ \"
# Garder ! ('','',)
yes = ("o", "oui",)
# Generic
article = "Article"
links = "liens"
sidebar = 'Barre Latérale'
navbar = 'Barre de menu'
metas = 'Balises Metas'
footer = 'Pied de Page'
title = 'Titre'
File = 'Fichier'
name = 'Nom'
by = "par"
le = "le"
fo = "pour"
proceed = "Continuer"
q = ' ?'
i = ' !'
pp = " :"
# Site web
#----------------------------------------------------------------------
# Divers
source_code = "Code source"
home = "Accueil"
go_home = "Aller à la page d'accueil"
read = "À lire"
tyto_psrc = "Code source au format Tyto de"
w_written = "a été écrit le"
w_published = "a été publié le"
written = "écrit le"
author_of = "est l'auteur de"
# Barre latérale
site_sdb_t = "À l'affiche..."
# Pied de page
tyto_site_t = "Site web officiel du générateur de sites web Libre %s"
tyto_git_t = "Dépôt officiel du code source de %s"
legal_t = "Mentions légales"
terms_t = "Conditions Générales d'Utilisation"
terms_s = "C.G.U"
law = "Loi"
about = "À propos de"
add_inf = "Information supplémentaires %s"%about.lower()
licence = "Licence"
contact = "Contact"
mail = "Courriel"
mail_to = "Contacter par %s l'administrateur de"%mail.lower()
feed = "Flux"
generator = "Generateur"
# Misc for Tyto
#--------------
# Check
check_a = "Vérifier encore l'article"
post_chg = "Article édité. Le vérifier"
new_post = "Créer l'article"
# Wip
wip_new = "Créer encore une page HTML dans le serveur 'wip'"
srv_again = "Créer encore les pages dans le serveur"
srv_added = "Créer les pages HTML manquantes dans le serveur"
srv_updated = "Mise à jour des pages HTML dans le serveur"
wip_in_mod = "Intégration statique des modules"
# publish
publish_a = "Publier encore l'article"
rss_c = "Créer le flux ATOM/RSS"
# Autre
uptpl = "Mettre à jour le dossier"
stats_f = "Articles : %s (%s mots)"
reg_domains = "Domaines enregistrés"
sitemap_gen = "Plan du site (sitemap) généré par"
sitemap_t = "Plan du site"
# Formulaire
#----------------------------------------------------------------------
form_edit = "Éditer le domaine avec le formulaire"
form_start = ' ├───────────────────────────────────────────────┐\n' + \
' │ Configurer un domaine pour le dossier courant │\n' + \
' │ Répondre O/o = Oui. Entrer garde le {default}\n' + \
' │ Sans réponse : arrêt, sauf pour │\n' + \
' │ - [Optionnel] │\n' + \
' │ - Valeur {default} connue │\n' + \
' ├───────────────────────────────────────────────┘'
form_warn = '\n' + \
' ├──────────────────────────────────────────┐\n' + \
' │ SVP, lisez les données de configurations │\n' + \
' ├──────────────────────────────────────────┘'
form_ready = '\n' + \
' ├─────────────────────────────────────────┐\n' + \
' │ Le domaine est prêt. Amusez-vous bien ! │\n' + \
' └─────────────────────────────────────────┘'
form_inv = '\n' + \
' ├───────────────────────────────────────────┐\n' + \
' │ Le Domaine est INVALIDE. Essayez encore ! │\n' + \
' └───────────────────────────────────────────┘'
form_opt = "[Optionnel]"
form_url = "URL du site web officiel"
form_wip = "URL du site web 'wip'"
form_db_new = "Nouvelle base de données crée"
form_trlog = "[2 car.] Langue des messages"
form_srv = "Dossier du serveur local"
form_logo = "Nom du fichier du logo"
form_fav_f = "Nom du fichier favicon !(.png)"
form_css_f = "Nom du fichier CSS"
form_rss_f = "Nom du fichier Atom/RSS"
form_rss_i = "Nombre d'articles Atom/RSS"
form_title = "Titre du site web"
form_date = "Année de création du domaine"
form_about = "Description du domaine"
form_mail = "Courriel du webmestre"
form_tags = "[séparées par une virgule] Étiquettes du domaine"
form_lic = "Licence du domaine"
form_licurl = "URL de la licence"
form_legal = "URL des mentions légales"
form_terms = "URL des CGU"
form_css = "[alnum] Préfix CSS"
form_sep = "[1 car.] Séparateur des titres de pages"
form_pscode = "Montrer le code source des articles"
form_relme = 'URL pour rel="me"'
form_trsite = "[2 car.] Langue du site web"
form_sdb_i = "Nombre d'articles"
form_activ = "Activer et preparer le domaine"
form_dir_e = "Dossier présent"
form_dir_c = "Dossier créé"
form_file_e = "Fichier présent"
form_file_c = "Fichier créé"
form_reset = "Réinitialiser la configuration"
form_rep = "Remplacer le fichier HTML"
# Documentation des fichiers de configuration
#--------------------------------------------
metas_inf = "Créer les balises <meta>"
metas_doc = \
'# Pour %s\n' + \
'# Type Fichier text/HTML\n' + \
'# Description Fichier de configuration des balises <meta> HTML \n' + \
'# Contenu inséré dans la section <head>\n' + \
'# Fichier %s\n' + \
'# Comment Insérer des balises <metas ...> et <link ...>\n' + \
'# Notes - Sont ajoutées uniquement les balises :\n' + \
'# - <metas>\n' + \
'~ - <link>\n' + \
'# - Ne PAS copier ce fichier dans le dossier template\n' + \
'# - Les balises suivantes sont déjà présentes'
navbar_inf = "Créer la barre de menu"
navbar_doc = \
'# Pour %s\n' + \
'# Type fichier texte\n' + \
'# Description Utilisé par "wip/publish navbar"\n' + \
'# (Liste des dossiers)\n' + \
"# Commandes tyto new navbar (réinitialiser)\n" + \
'# tyto wip/publish navbar (créer)\n' + \
'# tyto show navbar (afficher la configuration)\n' + \
'# tyto show-wip/show-www navbar (afficher l\'HTML)\n' + \
'# tyto edit navbar (editer ce fichier)\n' + \
'# Fichier %s\n' + \
'# Comment 1 nom de dossier par ligne *1\n' + \
'# (depuis articles/)\n' + \
'# Ne commence pas par "/"\n' + \
'# L\'ordre définit la position\n' + \
'# Note Pour éviter l\'erreur 404 :\n' + \
'# - ajouter un article index.{ext}\n' + \
'# dans le dossier mentionné\n' + \
'# - check et wip sur l\'article\n' + \
'# *1 Option Pour définir un titre de lien :\n' + \
'# - ajouter "# titre du lien"\n' + \
'\n# %s\n'%(20 * "-") +\
'# Exemples :\n' + \
'# documentation\n' + \
'# a-propos # Informations concernant ce site\n' + \
'# %s\n\n'%(20 * "-")
sidebar_inf = "Créer la barre latérale"
sidebar_doc = \
'# Pour %s\n' + \
'# Type fichier texte\n' + \
'# Description Fichier de configuration de la barre latérale\n' + \
'# (Liste d\'articles)\n' + \
'# Fichier %s\n' + \
"# Commandes tyto new sidebar (réinitialiser)\n" + \
'# tyto wip/publish sidebar (créer)\n' + \
'# tyto show sidebar (afficher la configuration)\n' + \
'# tyto show-wip/show-www sidebar (afficher l\'HTML)\n' + \
'# tyto edit sidebar (editer ce fichier)\n' + \
'# Comment 1 URI de l\'article par ligne\n' + \
'# (depuis articles/)\n' + \
'# Ne commence pas par "/"\n' + \
'# L\'ordre définit la position\n' + \
'# Articles max = %d\n' + \
'# Option Pour définir un titre à la barre latérale:\n' + \
'# ": Titre de la sidebar"\n' + \
'\n# %s\n'%(20 * "-") + \
'# Exemples :\n' + \
'# : Ma liste des nouveaux articles\n' + \
'# index.tyto\n' + \
'# dir1/index.tyto\n' + \
'# %s\n\n'%(20 * "-")
footer_inf = "Créer le pied de page"
footer_doc = \
'# Pour %s\n' + \
'# Type Fichier text/HTML\n' + \
'# Description Fichier de configuration du pied de page\n' + \
'# Fichier %s\n' + \
"# Commandes tyto new footer (réinitialiser)\n" + \
'# tyto wip/publish footer (créer)\n' + \
'# tyto show footer (afficher la configuration)\n' + \
'# tyto show-wip/show-www footer (afficher l\'HTML)\n' + \
'# tyto edit footer (editer ce fichier)\n' + \
'# Comment Insérer du code HTML\n' + \
'# Notes - Les lignes sont ignorées si :\n' + \
'# - vides\n' + \
'# - commencent par "#"\n' + \
'# - Ne PAS copier ce fichier dans le dossier template\n' + \
'# %s\n'%(20 * "-")
# Help with Tyto commands
args_helps = """\n# Nouveau domaine :
- Créer un dossier et aller dedans
- Créer un domain avec 'tyto new domain [URL]'
- Créer un fichier .tyto dans le dossier "articles/"
- Utiliser les actions check > wip > publish
! - Les fichiers des modules sont dans le dossier "_configs/"
et utilisés pour personnaliser certaines parties du site
- Les fichier (css, logo...) vont dans le dossier serveur "wip/template/"
# Usage: tyto [action] [target]
# [action] > Sans [target]
version : Montre la version installée
domains : Montre les domains installés
help : Montre l'aide des commandes
# [action] > Selon l'argument [target]
# Modifier un ficher
edit : Fichier source, module de configuration
edit-db : Modifier une base de données/fichier de configuration
edit-wip : Modifier un fichier dans le serveur 'wip'
edit_www : Modifier un fichier dans le serveur 'www'
new : [domain] Créer un domaine ou le modifier via le formulaire
[sidebar, navbar, footer, metas] Créer ou remplacer le
fichier de configuration du module par le défaut
[filename] (sans .tyto) Créer un article dans le
dossier actuel
[sitemap], créer le plan du site (sitemap)
# Afficher un fichier (avec numéros de ligne)
show : Fichier source, module de configuration
show-db : Afficher une base de données/fichier de configuration
show-wip : Afficher un fichier dans le serveur 'wip'
show-www : Afficher un fichier dans le serveur 'www'
# Processus de création / Mise en ligne
check : Vérifier la validité d'un article au format tyto
wip : Créer une page HTML de l'article dans le serveur 'wip'
force-wip : [file], check, wip
preview : [module]/[file], ouvre le fichier 'wip' dans le navigateur par défaut
publish : Créer une page HTML de l'article dans le serveur 'www'
quick-pub : [file] , check, wip, publish
# [target] > Selon l'action [action]
# Traitement en masse
updated : Mise à jour des articles modifiés (déjà vérifiés)
again : Forcer TOUS les articles déjà vérifiés
added : [check] Vérifier tous les article .tyto dans le domaine
qui n'ont pas été déjà validés
[wip, publish] Créer les pages HTML des articles
qui ont été modifiés et vérifiés
# Mise en ligne du thème et des modules
template : - Recréer les modules HTML dans "template/"
- Copie tous les autres fichier du dossier wip/template/
# Domaine et fichier
domain : Créer un domain ou le modifier
[file] : URI du fichier (l'autocompletion est votre amie)
# Les modules
footer : Fichier de configuration du pied de page
metas : Fichier de configuration des balises HTML <meta>, <link>
navbar : Fichier de configuration du menu de navigation
sidebar : Fichier de configuration de la barre latérale
stats : Fichier de statistiques (serveur 'wip' ou 'www')
sitemap : Fichier sitemap.tyto/.html
# [option]
--static : Créer une page HTML entièrement statique
--no-mods : Avec [publish template], ne pas recréer les modules
"""
ex_helps = """# Exemples :
# Vérifier l'article dans le sous dossier (suivant l'emplacement)
$ tyto check mysubdir/index.tyto
# Créer ou remettre par défaut la barre latérale
$ tyto new sidebar
# Modifier la configuration du menu de navigation
$ tyto edit navbar
# Modifier doc/index.html dans le serveur 'www'
$ tyto edit-www doc/index.tyto
# Créer le fichier HTML de la barre latérale (serveur 'wip')
$ tyto wip sidebar
# Afficher le contenu du pied de page HTML dans le serveur 'wip'
$ tyto show-wip footer
# Créer le fichier de statistiques dans le serveur 'www'
$ tyto publish stats"""

View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
# Tyto - Littérateur
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>..
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: English website translation file
# File: /var/lib/tyto/translations/logs_en.py
#
# How to translate:
# - create filename website_xx.py in /var/lib/tyto/translations/
# where xx are 2 first lang letters (es, for spanish...)
# - copy its contents and translate values
#----------------------------------------------------------------------
# Note: python file
sidebar_title = "Featured posts"
sitemap = "sitemap"

View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
# Tyto - Littérateur
# Copyright (C) 2023 Cyrille Louarn <echolib+tyto@a-lec.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>..
#----------------------------------------------------------------------
# XMPP: echolib (im@echolib.re)
#
# Description: Fichier français de traduction des sites web
# File: /var/lib/tyto/translations/website_fr.py
#
# Comment traduire :
# - créer un fichier nommé logs_xx.py dans /var/lib/tyto/translations/
# oû xx sont les 2 première lettres de la langue (es, pour espagnol...)
# - Copier ce contenu dedans, et traduire les variables
#----------------------------------------------------------------------
# Rappel: Fichier au format python
sidebar_title = "Articles recommandés"
sitemap = "Plan du site"