initial commit
This commit is contained in:
commit
5ebc506921
975 changed files with 154341 additions and 0 deletions
10
.editorconfig
Normal file
10
.editorconfig
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = tab
|
||||||
|
tab_width = 4
|
1
.fossil-settings/allow-symlinks
Normal file
1
.fossil-settings/allow-symlinks
Normal file
|
@ -0,0 +1 @@
|
||||||
|
on
|
14
.fossil-settings/ignore-glob
Normal file
14
.fossil-settings/ignore-glob
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
src/data/*
|
||||||
|
src/*.tar.gz
|
||||||
|
src/*.asc
|
||||||
|
src/*.log
|
||||||
|
src/include/lib/KD2
|
||||||
|
src/debug_sql.sqlite
|
||||||
|
src/modules/*
|
||||||
|
src/config.local.php
|
||||||
|
build/windows/*.exe
|
||||||
|
build/windows/php.zip
|
||||||
|
build/windows/install_dir
|
||||||
|
build/*.tar.gz*
|
||||||
|
build/debian/*.deb
|
||||||
|
src/psalm.phar
|
1
.fossil-settings/manifest
Normal file
1
.fossil-settings/manifest
Normal file
|
@ -0,0 +1 @@
|
||||||
|
on
|
BIN
.fslckout
Normal file
BIN
.fslckout
Normal file
Binary file not shown.
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
src/data
|
1
.php-version
Normal file
1
.php-version
Normal file
|
@ -0,0 +1 @@
|
||||||
|
8.1.26
|
21
.travis.yml
Normal file
21
.travis.yml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
language: php
|
||||||
|
php:
|
||||||
|
- '7.2'
|
||||||
|
- '7.3'
|
||||||
|
- '7.4'
|
||||||
|
|
||||||
|
install:
|
||||||
|
- make -C src deps
|
||||||
|
|
||||||
|
script:
|
||||||
|
- php tests/run.php
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
irc:
|
||||||
|
channels:
|
||||||
|
- "chat.freenode.net#garradin"
|
||||||
|
template:
|
||||||
|
- "%{build_number} by %{author} on %{branch}: %{message} "
|
||||||
|
- "Build details: %{build_url}"
|
||||||
|
use_notice: false
|
||||||
|
skip_join: true
|
661
COPYING
Normal file
661
COPYING
Normal file
|
@ -0,0 +1,661 @@
|
||||||
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 19 November 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://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.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
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 <http://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
|
||||||
|
<http://www.gnu.org/licenses/>.
|
32
README.md
Normal file
32
README.md
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# Paheko - Le gestionnaire d'association
|
||||||
|
|
||||||
|
Paheko est un logiciel de gestion d'association.
|
||||||
|
|
||||||
|
Plus d'infos sur le site de développement ici : [fossil.kd2.org/paheko](https://fossil.kd2.org/paheko/)
|
||||||
|
|
||||||
|
[Documentation développeuse⋅développeur](https://fossil.kd2.org/paheko/wiki?name=Documentation+d%C3%A9veloppeur)
|
||||||
|
|
||||||
|
Il est possible d'essayer gratuitement sur la plateforme [Paheko.cloud](https://paheko.cloud/).
|
||||||
|
|
||||||
|
Le code sur Github n'est qu'un miroir, le développement principal se passe sur Fossil, mais les PR sont quand même possibles sur Github.
|
||||||
|
|
||||||
|
**PR/Patch :** sauf si c'est une correction de bug, le mieux est de discuter de la modification sur dev(arobase)paheko.cloud avant de proposer le patch, pour qu'il ait plus de chances d'être accepté.
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
GNU Affero GPL v3 (voir fichier COPYING)
|
||||||
|
|
||||||
|
Cette licence permet la libre redistribution, utilisation et modification du logiciel.
|
||||||
|
|
||||||
|
La seule condition est de re-partager les éventuelles modifications apportées.
|
||||||
|
|
||||||
|
Cette clause s'applique même si le logiciel n'est pas distribué et simplement installé sur un serveur.
|
||||||
|
|
||||||
|
## Code utilisé
|
||||||
|
|
||||||
|
Inclus les bibliothèques suivantes :
|
||||||
|
|
||||||
|
* [KD2fw](https://fossil.kd2.org/kd2fw/) - Copyright : 2001-2022+ BohwaZ - Licence : GNU AGPL v3
|
||||||
|
* [Gibberish AES](https://github.com/mdp/gibberish-aes) - Copyright : Mark Percival 2008 - http://markpercival.us - Licence : MIT
|
||||||
|
* [Parsedown](https://github.com/erusev/parsedown) - Copyright Emanuil Rusev - License MIT
|
||||||
|
* [Unzipit.js](https://github.com/greggman/unzipit) - Copyright (c) 2019 Gregg Tavares 2014 Josh Wolfe - License MIT
|
15
SECURITY.md
Normal file
15
SECURITY.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# Security Policy
|
||||||
|
|
||||||
|
We take the security of Garradin very seriously.
|
||||||
|
|
||||||
|
Nous prenons la sécurité de Garradin au sérieux.
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
Only the latest stable branch is supported.
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
If you find a security issue, please contact us: security@garradin.eu
|
||||||
|
|
||||||
|
Vous pouvez nous contacter à l'adresse e-mail ci-dessus si vous trouvez un problème de sécurité.
|
64
archives/0.7.0_migration.sql
Normal file
64
archives/0.7.0_migration.sql
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
CREATE TABLE plugins_signaux
|
||||||
|
-- Association entre plugins et signaux (hooks)
|
||||||
|
(
|
||||||
|
signal TEXT NOT NULL,
|
||||||
|
plugin TEXT NOT NULL REFERENCES plugins (id),
|
||||||
|
callback TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (signal, plugin)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE compta_rapprochement
|
||||||
|
-- Rapprochement entre compta et relevés de comptes
|
||||||
|
(
|
||||||
|
operation INTEGER NOT NULL PRIMARY KEY REFERENCES compta_journal (id),
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
auteur INTEGER NOT NULL REFERENCES membres (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE fichiers
|
||||||
|
-- Données sur les fichiers
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg)
|
||||||
|
type TEXT NULL, -- Type MIME
|
||||||
|
image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue
|
||||||
|
datetime TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Date d'ajout ou mise à jour du fichier
|
||||||
|
id_contenu INTEGER NOT NULL REFERENCES fichiers_contenu (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX fichiers_date ON fichiers (datetime);
|
||||||
|
|
||||||
|
CREATE TABLE fichiers_contenu
|
||||||
|
-- Contenu des fichiers
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier
|
||||||
|
taille INTEGER NOT NULL, -- Taille en octets
|
||||||
|
contenu BLOB NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX fichiers_hash ON fichiers_contenu (hash);
|
||||||
|
|
||||||
|
CREATE TABLE fichiers_membres
|
||||||
|
-- Associations entre fichiers et membres (photo de profil par exemple)
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES membres (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE fichiers_wiki_pages
|
||||||
|
-- Associations entre fichiers et pages du wiki
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES wiki_pages (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE fichiers_compta_journal
|
||||||
|
-- Associations entre fichiers et journal de compta (pièce comptable par exemple)
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES compta_journal (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
24
archives/0.7.2_migration.sql
Normal file
24
archives/0.7.2_migration.sql
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
-- Colonne manquante
|
||||||
|
ALTER TABLE rappels_envoyes ADD COLUMN id_rappel INTEGER NULL REFERENCES rappels (id);
|
||||||
|
|
||||||
|
-- Un bug a permis d'insérer des comptes avec des lettres minuscules, créant des problèmes
|
||||||
|
-- corrigeons donc les comptes pour les mettre en majuscules.
|
||||||
|
|
||||||
|
UPDATE compta_comptes SET id = UPPER(id);
|
||||||
|
|
||||||
|
-- Le champ id_auteur était à NOT NULL, il faut corriger ça pour pouvoir avoir un rapprochement anonyme
|
||||||
|
-- une fois que le membre a été supprimé
|
||||||
|
|
||||||
|
CREATE TABLE compta_rapprochement2
|
||||||
|
-- Rapprochement entre compta et relevés de comptes
|
||||||
|
(
|
||||||
|
id_operation INTEGER NOT NULL PRIMARY KEY REFERENCES compta_journal (id),
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
id_auteur INTEGER NULL REFERENCES membres (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO compta_rapprochement2 SELECT operation, date, auteur FROM compta_rapprochement;
|
||||||
|
|
||||||
|
DROP TABLE compta_rapprochement;
|
||||||
|
|
||||||
|
ALTER TABLE compta_rapprochement2 RENAME TO compta_rapprochement;
|
85
archives/0.8.0_migration.sql
Normal file
85
archives/0.8.0_migration.sql
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
-- Ajouter champ pour OTP
|
||||||
|
ALTER TABLE membres ADD COLUMN secret_otp TEXT NULL;
|
||||||
|
|
||||||
|
-- Ajouter champ clé PGP
|
||||||
|
ALTER TABLE membres ADD COLUMN clef_pgp TEXT NULL;
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- Mise à jour des tables contenant un champ date pour ajouter la contrainte --
|
||||||
|
-- Ceci afin de forcer les champs à contenir un format de date correct --
|
||||||
|
-- On en profite pour ajouter les ON DELETE nécessaires --
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Convertir les dates UNIX en date Y-m-d, apparemment il y en a encore parfois ?
|
||||||
|
UPDATE wiki_pages SET date_creation = datetime(date_creation, "unixepoch") WHERE CAST(date_creation AS INT) = date_creation;
|
||||||
|
UPDATE wiki_pages SET date_creation = datetime(date_creation) WHERE datetime(date_creation) != date_creation;
|
||||||
|
|
||||||
|
-- Renommage des tables qu'il faut mettre à jour
|
||||||
|
ALTER TABLE cotisations_membres RENAME TO cotisations_membres_old;
|
||||||
|
ALTER TABLE rappels RENAME TO rappels_old;
|
||||||
|
ALTER TABLE rappels_envoyes RENAME TO rappels_envoyes_old;
|
||||||
|
ALTER TABLE wiki_pages RENAME TO wiki_pages_old;
|
||||||
|
ALTER TABLE wiki_revisions RENAME TO wiki_revisions_old;
|
||||||
|
ALTER TABLE compta_categories RENAME TO compta_categories_old;
|
||||||
|
ALTER TABLE compta_comptes_bancaires RENAME TO compta_comptes_bancaires_old;
|
||||||
|
ALTER TABLE compta_exercices RENAME TO compta_exercices_old;
|
||||||
|
ALTER TABLE compta_journal RENAME TO compta_journal_old;
|
||||||
|
ALTER TABLE compta_rapprochement RENAME TO compta_rapprochement_old;
|
||||||
|
ALTER TABLE fichiers RENAME TO fichiers_old;
|
||||||
|
ALTER TABLE membres_operations RENAME TO membres_operations_old;
|
||||||
|
ALTER TABLE membres_categories RENAME TO membres_categories_old;
|
||||||
|
|
||||||
|
-- Suppression des index pour que les nouveaux soient liés aux nouvelles tables
|
||||||
|
DROP INDEX cm_unique;
|
||||||
|
DROP INDEX wiki_uri;
|
||||||
|
DROP INDEX wiki_revisions_id_page;
|
||||||
|
DROP INDEX wiki_revisions_id_auteur;
|
||||||
|
DROP INDEX compta_operations_exercice;
|
||||||
|
DROP INDEX compta_operations_date;
|
||||||
|
DROP INDEX compta_operations_comptes;
|
||||||
|
DROP INDEX compta_operations_auteur;
|
||||||
|
DROP INDEX fichiers_date;
|
||||||
|
|
||||||
|
-- Suppression ancienne table recherche
|
||||||
|
DROP TABLE wiki_recherche;
|
||||||
|
|
||||||
|
-- Suppression des triggers
|
||||||
|
-- Sinon les nouveaux ne seront pas créés sur la nouvelle table
|
||||||
|
DROP TRIGGER wiki_recherche_delete;
|
||||||
|
DROP TRIGGER wiki_recherche_update;
|
||||||
|
DROP TRIGGER wiki_recherche_contenu_insert;
|
||||||
|
DROP TRIGGER wiki_recherche_contenu_chiffre;
|
||||||
|
|
||||||
|
-- Création des tables mises à jour (et de leurs index)
|
||||||
|
.read 0.8.0_schema.sql
|
||||||
|
|
||||||
|
-- Copie des données
|
||||||
|
INSERT INTO cotisations_membres SELECT * FROM cotisations_membres_old;
|
||||||
|
INSERT INTO rappels SELECT * FROM rappels_old;
|
||||||
|
INSERT INTO rappels_envoyes SELECT id, id_membre, id_cotisation, id_rappel, date, media FROM rappels_envoyes_old;
|
||||||
|
INSERT INTO wiki_pages SELECT * FROM wiki_pages_old;
|
||||||
|
INSERT INTO wiki_revisions SELECT * FROM wiki_revisions_old;
|
||||||
|
INSERT INTO compta_categories SELECT * FROM compta_categories_old;
|
||||||
|
INSERT INTO compta_comptes_bancaires SELECT * FROM compta_comptes_bancaires_old;
|
||||||
|
INSERT INTO compta_exercices SELECT * FROM compta_exercices_old;
|
||||||
|
INSERT INTO compta_journal SELECT *, NULL FROM compta_journal_old;
|
||||||
|
INSERT INTO compta_rapprochement SELECT * FROM compta_rapprochement_old;
|
||||||
|
INSERT INTO fichiers SELECT * FROM fichiers_old;
|
||||||
|
INSERT INTO membres_operations SELECT * FROM membres_operations_old;
|
||||||
|
INSERT INTO membres_categories SELECT id, nom, droit_wiki, droit_membres, droit_compta,
|
||||||
|
droit_inscription, droit_connexion, droit_config, cacher, id_cotisation_obligatoire FROM membres_categories_old;
|
||||||
|
|
||||||
|
-- Suppression des anciennes tables
|
||||||
|
DROP TABLE cotisations_membres_old;
|
||||||
|
DROP TABLE rappels_old;
|
||||||
|
DROP TABLE rappels_envoyes_old;
|
||||||
|
DROP TABLE wiki_pages_old;
|
||||||
|
DROP TABLE wiki_revisions_old;
|
||||||
|
DROP TABLE compta_categories_old;
|
||||||
|
DROP TABLE compta_comptes_bancaires_old;
|
||||||
|
DROP TABLE compta_exercices_old;
|
||||||
|
DROP TABLE compta_journal_old;
|
||||||
|
DROP TABLE compta_rapprochement_old;
|
||||||
|
DROP TABLE fichiers_old;
|
||||||
|
DROP TABLE membres_operations_old;
|
||||||
|
DROP TABLE membres_categories_old;
|
390
archives/0.8.0_schema.sql
Normal file
390
archives/0.8.0_schema.sql
Normal file
|
@ -0,0 +1,390 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS config (
|
||||||
|
-- Configuration de Garradin
|
||||||
|
cle TEXT PRIMARY KEY NOT NULL,
|
||||||
|
valeur TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
-- On stocke ici les ID de catégorie de compta correspondant aux types spéciaux
|
||||||
|
-- compta_categorie_cotisations => id_categorie
|
||||||
|
-- compta_categorie_dons => id_categorie
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_categories
|
||||||
|
-- Catégories de membres
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
nom TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
|
||||||
|
droit_wiki INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_membres INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_compta INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_inscription INTEGER NOT NULL DEFAULT 0,
|
||||||
|
droit_connexion INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_config INTEGER NOT NULL DEFAULT 0,
|
||||||
|
cacher INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
id_cotisation_obligatoire INTEGER NULL REFERENCES cotisations (id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Membres de l'asso
|
||||||
|
-- Table dynamique générée par l'application
|
||||||
|
-- voir Garradin\Membres\Champs.php
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_sessions
|
||||||
|
-- Sessions
|
||||||
|
(
|
||||||
|
selecteur TEXT NOT NULL,
|
||||||
|
hash TEXT NOT NULL,
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
expire INT NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (selecteur, id_membre)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS cotisations
|
||||||
|
-- Types de cotisations et activités
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
id_categorie_compta INTEGER NULL, -- NULL si le type n'est pas associé automatiquement à la compta
|
||||||
|
|
||||||
|
intitule TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
montant REAL NOT NULL,
|
||||||
|
|
||||||
|
duree INTEGER NULL, -- En jours
|
||||||
|
debut TEXT NULL, -- timestamp
|
||||||
|
fin TEXT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY (id_categorie_compta) REFERENCES compta_categories (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS cotisations_membres
|
||||||
|
-- Enregistrement des cotisations et activités
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS cm_unique ON cotisations_membres (id_membre, id_cotisation, date);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_operations
|
||||||
|
-- Liaision des enregistrement des paiements en compta
|
||||||
|
(
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_operation INTEGER NOT NULL REFERENCES compta_journal (id) ON DELETE CASCADE,
|
||||||
|
id_cotisation INTEGER NULL REFERENCES cotisations_membres (id) ON DELETE SET NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (id_membre, id_operation)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS rappels
|
||||||
|
-- Rappels de devoir renouveller une cotisation
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
delai INTEGER NOT NULL, -- Délai en jours pour envoyer le rappel
|
||||||
|
|
||||||
|
sujet TEXT NOT NULL,
|
||||||
|
texte TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS rappels_envoyes
|
||||||
|
-- Enregistrement des rappels envoyés à qui et quand
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE,
|
||||||
|
id_rappel INTEGER NULL REFERENCES rappels (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date),
|
||||||
|
|
||||||
|
media INTEGER NOT NULL -- Média utilisé pour le rappel : 1 = email, 2 = courrier, 3 = autre
|
||||||
|
);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- WIKI
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS wiki_pages
|
||||||
|
-- Pages du wiki
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
uri TEXT NOT NULL, -- URI unique (équivalent NomPageWiki)
|
||||||
|
titre TEXT NOT NULL,
|
||||||
|
date_creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_creation) IS NOT NULL AND datetime(date_creation) = date_creation),
|
||||||
|
date_modification TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_modification) IS NOT NULL AND datetime(date_modification) = date_modification),
|
||||||
|
parent INTEGER NOT NULL DEFAULT 0, -- ID de la page parent
|
||||||
|
revision INTEGER NOT NULL DEFAULT 0, -- Numéro de révision (commence à 0 si pas de texte, +1 à chaque changement du texte)
|
||||||
|
droit_lecture INTEGER NOT NULL DEFAULT 0, -- Accès en lecture (-1 = public [site web], 0 = tous ceux qui ont accès en lecture au wiki, 1+ = ID de groupe)
|
||||||
|
droit_ecriture INTEGER NOT NULL DEFAULT 0 -- Accès en écriture (0 = tous ceux qui ont droit d'écriture sur le wiki, 1+ = ID de groupe)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS wiki_uri ON wiki_pages (uri);
|
||||||
|
|
||||||
|
CREATE VIRTUAL TABLE IF NOT EXISTS wiki_recherche USING fts4
|
||||||
|
-- Table dupliquée pour chercher une page
|
||||||
|
(
|
||||||
|
id INT PRIMARY KEY NOT NULL, -- Clé externe obligatoire
|
||||||
|
titre TEXT NOT NULL,
|
||||||
|
contenu TEXT NULL, -- Contenu de la dernière révision
|
||||||
|
FOREIGN KEY (id) REFERENCES wiki_pages(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS wiki_revisions
|
||||||
|
-- Révisions du contenu des pages
|
||||||
|
(
|
||||||
|
id_page INTEGER NOT NULL REFERENCES wiki_pages (id) ON DELETE CASCADE,
|
||||||
|
revision INTEGER NULL,
|
||||||
|
|
||||||
|
id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL,
|
||||||
|
|
||||||
|
contenu TEXT NOT NULL,
|
||||||
|
modification TEXT NULL, -- Description des modifications effectuées
|
||||||
|
chiffrement INTEGER NOT NULL DEFAULT 0, -- 1 si le contenu est chiffré, 0 sinon
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date),
|
||||||
|
|
||||||
|
PRIMARY KEY(id_page, revision)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS wiki_revisions_id_page ON wiki_revisions (id_page);
|
||||||
|
CREATE INDEX IF NOT EXISTS wiki_revisions_id_auteur ON wiki_revisions (id_auteur);
|
||||||
|
|
||||||
|
-- Triggers pour synchro avec table wiki_pages
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_delete AFTER DELETE ON wiki_pages
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM wiki_recherche WHERE id = old.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_update AFTER UPDATE OF id, titre ON wiki_pages
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET id = new.id, titre = new.titre WHERE id = old.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Trigger pour mettre à jour le contenu de la table de recherche lors d'une nouvelle révision
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_insert AFTER INSERT ON wiki_revisions WHEN new.chiffrement != 1
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET contenu = new.contenu WHERE id = new.id_page;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Si le contenu est chiffré, la recherche n'affiche pas de contenu
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_chiffre AFTER INSERT ON wiki_revisions WHEN new.chiffrement = 1
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET contenu = '' WHERE id = new.id_page;
|
||||||
|
END;
|
||||||
|
|
||||||
|
/*
|
||||||
|
CREATE TABLE wiki_suivi
|
||||||
|
-- Suivi des pages
|
||||||
|
(
|
||||||
|
id_membre INTEGER NOT NULL,
|
||||||
|
id_page INTEGER NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (id_membre, id_page),
|
||||||
|
|
||||||
|
FOREIGN KEY (id_page) REFERENCES wiki_pages (id), -- Clé externe obligatoire
|
||||||
|
FOREIGN KEY (id_membre) REFERENCES membres (id) -- Clé externe obligatoire
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
|
--
|
||||||
|
-- COMPTA
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_exercices
|
||||||
|
-- Exercices
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL,
|
||||||
|
|
||||||
|
debut TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(debut) IS NOT NULL AND date(debut) = debut),
|
||||||
|
fin TEXT NULL DEFAULT NULL CHECK (fin IS NULL OR (date(fin) IS NOT NULL AND date(fin) = fin)),
|
||||||
|
|
||||||
|
cloture INTEGER NOT NULL DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_comptes
|
||||||
|
-- Plan comptable
|
||||||
|
(
|
||||||
|
id TEXT NOT NULL PRIMARY KEY, -- peut contenir des lettres, eg. 53A, 53B, etc.
|
||||||
|
parent TEXT NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL,
|
||||||
|
|
||||||
|
position INTEGER NOT NULL, -- position actif/passif/charge/produit
|
||||||
|
plan_comptable INTEGER NOT NULL DEFAULT 1, -- 1 = fait partie du plan comptable, 0 = a été ajouté par l'utilisateur
|
||||||
|
desactive INTEGER NOT NULL DEFAULT 0 -- 1 = compte historique désactivé
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_comptes_parent ON compta_comptes (parent);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_comptes_bancaires
|
||||||
|
-- Comptes bancaires
|
||||||
|
(
|
||||||
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
banque TEXT NOT NULL,
|
||||||
|
|
||||||
|
iban TEXT NULL,
|
||||||
|
bic TEXT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(id) REFERENCES compta_comptes(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_projets
|
||||||
|
-- Projets (compta analytique)
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_journal
|
||||||
|
-- Journal des opérations comptables
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL,
|
||||||
|
remarques TEXT NULL,
|
||||||
|
numero_piece TEXT NULL, -- N° de pièce comptable
|
||||||
|
|
||||||
|
montant REAL NOT NULL,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date),
|
||||||
|
moyen_paiement TEXT NULL,
|
||||||
|
numero_cheque TEXT NULL,
|
||||||
|
|
||||||
|
compte_debit TEXT NULL, -- N° du compte dans le plan, NULL est utilisé pour une opération qui vient d'un exercice précédent
|
||||||
|
compte_credit TEXT NULL, -- N° du compte dans le plan
|
||||||
|
|
||||||
|
id_exercice INTEGER NULL DEFAULT NULL, -- En cas de compta simple, l'exercice est permanent (NULL)
|
||||||
|
id_auteur INTEGER NULL,
|
||||||
|
id_categorie INTEGER NULL, -- Numéro de catégorie (en mode simple)
|
||||||
|
id_projet INTEGER NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(moyen_paiement) REFERENCES compta_moyens_paiement(code),
|
||||||
|
FOREIGN KEY(compte_debit) REFERENCES compta_comptes(id),
|
||||||
|
FOREIGN KEY(compte_credit) REFERENCES compta_comptes(id),
|
||||||
|
FOREIGN KEY(id_exercice) REFERENCES compta_exercices(id),
|
||||||
|
FOREIGN KEY(id_auteur) REFERENCES membres(id) ON DELETE SET NULL,
|
||||||
|
FOREIGN KEY(id_categorie) REFERENCES compta_categories(id) ON DELETE SET NULL,
|
||||||
|
FOREIGN KEY(id_projet) REFERENCES compta_projets(id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_exercice ON compta_journal (id_exercice);
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_date ON compta_journal (date);
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_comptes ON compta_journal (compte_debit, compte_credit);
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_auteur ON compta_journal (id_auteur);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_moyens_paiement
|
||||||
|
-- Moyens de paiement
|
||||||
|
(
|
||||||
|
code TEXT NOT NULL PRIMARY KEY,
|
||||||
|
nom TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
--INSERT INTO compta_moyens_paiement (code, nom) VALUES ('AU', 'Autre');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CB', 'Carte bleue');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CH', 'Chèque');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('ES', 'Espèces');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('PR', 'Prélèvement');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('TI', 'TIP');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('VI', 'Virement');
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_categories
|
||||||
|
-- Catégories pour simplifier le plan comptable
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
type INTEGER NOT NULL DEFAULT 1, -- 1 = recette, -1 = dépense, 0 = autre (utilisé uniquement pour l'interface)
|
||||||
|
|
||||||
|
intitule TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
|
||||||
|
compte TEXT NOT NULL, -- Compte affecté par cette catégorie
|
||||||
|
|
||||||
|
FOREIGN KEY(compte) REFERENCES compta_comptes(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS plugins
|
||||||
|
(
|
||||||
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
|
officiel INTEGER NOT NULL DEFAULT 0,
|
||||||
|
nom TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
auteur TEXT NULL,
|
||||||
|
url TEXT NULL,
|
||||||
|
version TEXT NOT NULL,
|
||||||
|
menu INTEGER NOT NULL DEFAULT 0,
|
||||||
|
config TEXT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS plugins_signaux
|
||||||
|
-- Association entre plugins et signaux (hooks)
|
||||||
|
(
|
||||||
|
signal TEXT NOT NULL,
|
||||||
|
plugin TEXT NOT NULL REFERENCES plugins (id),
|
||||||
|
callback TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (signal, plugin)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_rapprochement
|
||||||
|
-- Rapprochement entre compta et relevés de comptes
|
||||||
|
(
|
||||||
|
id_operation INTEGER NOT NULL PRIMARY KEY REFERENCES compta_journal (id) ON DELETE CASCADE,
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date),
|
||||||
|
id_auteur INTEGER NULL REFERENCES membres (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers
|
||||||
|
-- Données sur les fichiers
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg)
|
||||||
|
type TEXT NULL, -- Type MIME
|
||||||
|
image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue
|
||||||
|
datetime TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(datetime) IS NOT NULL AND datetime(datetime) = datetime), -- Date d'ajout ou mise à jour du fichier
|
||||||
|
id_contenu INTEGER NOT NULL REFERENCES fichiers_contenu (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS fichiers_date ON fichiers (datetime);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_contenu
|
||||||
|
-- Contenu des fichiers
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier
|
||||||
|
taille INTEGER NOT NULL, -- Taille en octets
|
||||||
|
contenu BLOB NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS fichiers_hash ON fichiers_contenu (hash);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_membres
|
||||||
|
-- Associations entre fichiers et membres (photo de profil par exemple)
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES membres (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_wiki_pages
|
||||||
|
-- Associations entre fichiers et pages du wiki
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES wiki_pages (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_compta_journal
|
||||||
|
-- Associations entre fichiers et journal de compta (pièce comptable par exemple)
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES compta_journal (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
11
archives/0.8.3_migration.sql
Normal file
11
archives/0.8.3_migration.sql
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
-- Ajout d'une clause ON DELETE SET NULL sur la table cotisations
|
||||||
|
ALTER TABLE cotisations_membres RENAME TO cotisations_membres_old;
|
||||||
|
|
||||||
|
-- Création des tables mises à jour (et de leurs index)
|
||||||
|
.read 0.8.3_schema.sql
|
||||||
|
|
||||||
|
-- Copie des données
|
||||||
|
INSERT INTO cotisations_membres SELECT * FROM cotisations_membres_old;
|
||||||
|
|
||||||
|
-- Suppression des anciennes tables
|
||||||
|
DROP TABLE cotisations_membres_old;
|
388
archives/0.8.3_schema.sql
Normal file
388
archives/0.8.3_schema.sql
Normal file
|
@ -0,0 +1,388 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS config (
|
||||||
|
-- Configuration de Garradin
|
||||||
|
cle TEXT PRIMARY KEY NOT NULL,
|
||||||
|
valeur TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
-- On stocke ici les ID de catégorie de compta correspondant aux types spéciaux
|
||||||
|
-- compta_categorie_cotisations => id_categorie
|
||||||
|
-- compta_categorie_dons => id_categorie
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_categories
|
||||||
|
-- Catégories de membres
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
nom TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
|
||||||
|
droit_wiki INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_membres INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_compta INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_inscription INTEGER NOT NULL DEFAULT 0,
|
||||||
|
droit_connexion INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_config INTEGER NOT NULL DEFAULT 0,
|
||||||
|
cacher INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
id_cotisation_obligatoire INTEGER NULL REFERENCES cotisations (id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Membres de l'asso
|
||||||
|
-- Table dynamique générée par l'application
|
||||||
|
-- voir Garradin\Membres\Champs.php
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_sessions
|
||||||
|
-- Sessions
|
||||||
|
(
|
||||||
|
selecteur TEXT NOT NULL,
|
||||||
|
hash TEXT NOT NULL,
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
expire INT NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (selecteur, id_membre)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS cotisations
|
||||||
|
-- Types de cotisations et activités
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
id_categorie_compta INTEGER NULL REFERENCES compta_categories (id) ON DELETE SET NULL, -- NULL si le type n'est pas associé automatiquement à la compta
|
||||||
|
|
||||||
|
intitule TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
montant REAL NOT NULL,
|
||||||
|
|
||||||
|
duree INTEGER NULL, -- En jours
|
||||||
|
debut TEXT NULL, -- timestamp
|
||||||
|
fin TEXT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS cotisations_membres
|
||||||
|
-- Enregistrement des cotisations et activités
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS cm_unique ON cotisations_membres (id_membre, id_cotisation, date);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_operations
|
||||||
|
-- Liaison des enregistrement des paiements en compta
|
||||||
|
(
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_operation INTEGER NOT NULL REFERENCES compta_journal (id) ON DELETE CASCADE,
|
||||||
|
id_cotisation INTEGER NULL REFERENCES cotisations_membres (id) ON DELETE SET NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (id_membre, id_operation)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS rappels
|
||||||
|
-- Rappels de devoir renouveller une cotisation
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
delai INTEGER NOT NULL, -- Délai en jours pour envoyer le rappel
|
||||||
|
|
||||||
|
sujet TEXT NOT NULL,
|
||||||
|
texte TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS rappels_envoyes
|
||||||
|
-- Enregistrement des rappels envoyés à qui et quand
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE,
|
||||||
|
id_rappel INTEGER NULL REFERENCES rappels (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date),
|
||||||
|
|
||||||
|
media INTEGER NOT NULL -- Média utilisé pour le rappel : 1 = email, 2 = courrier, 3 = autre
|
||||||
|
);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- WIKI
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS wiki_pages
|
||||||
|
-- Pages du wiki
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
uri TEXT NOT NULL, -- URI unique (équivalent NomPageWiki)
|
||||||
|
titre TEXT NOT NULL,
|
||||||
|
date_creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_creation) IS NOT NULL AND datetime(date_creation) = date_creation),
|
||||||
|
date_modification TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_modification) IS NOT NULL AND datetime(date_modification) = date_modification),
|
||||||
|
parent INTEGER NOT NULL DEFAULT 0, -- ID de la page parent
|
||||||
|
revision INTEGER NOT NULL DEFAULT 0, -- Numéro de révision (commence à 0 si pas de texte, +1 à chaque changement du texte)
|
||||||
|
droit_lecture INTEGER NOT NULL DEFAULT 0, -- Accès en lecture (-1 = public [site web], 0 = tous ceux qui ont accès en lecture au wiki, 1+ = ID de groupe)
|
||||||
|
droit_ecriture INTEGER NOT NULL DEFAULT 0 -- Accès en écriture (0 = tous ceux qui ont droit d'écriture sur le wiki, 1+ = ID de groupe)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS wiki_uri ON wiki_pages (uri);
|
||||||
|
|
||||||
|
CREATE VIRTUAL TABLE IF NOT EXISTS wiki_recherche USING fts4
|
||||||
|
-- Table dupliquée pour chercher une page
|
||||||
|
(
|
||||||
|
id INT PRIMARY KEY NOT NULL, -- Clé externe obligatoire
|
||||||
|
titre TEXT NOT NULL,
|
||||||
|
contenu TEXT NULL, -- Contenu de la dernière révision
|
||||||
|
FOREIGN KEY (id) REFERENCES wiki_pages(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS wiki_revisions
|
||||||
|
-- Révisions du contenu des pages
|
||||||
|
(
|
||||||
|
id_page INTEGER NOT NULL REFERENCES wiki_pages (id) ON DELETE CASCADE,
|
||||||
|
revision INTEGER NULL,
|
||||||
|
|
||||||
|
id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL,
|
||||||
|
|
||||||
|
contenu TEXT NOT NULL,
|
||||||
|
modification TEXT NULL, -- Description des modifications effectuées
|
||||||
|
chiffrement INTEGER NOT NULL DEFAULT 0, -- 1 si le contenu est chiffré, 0 sinon
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date),
|
||||||
|
|
||||||
|
PRIMARY KEY(id_page, revision)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS wiki_revisions_id_page ON wiki_revisions (id_page);
|
||||||
|
CREATE INDEX IF NOT EXISTS wiki_revisions_id_auteur ON wiki_revisions (id_auteur);
|
||||||
|
|
||||||
|
-- Triggers pour synchro avec table wiki_pages
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_delete AFTER DELETE ON wiki_pages
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM wiki_recherche WHERE id = old.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_update AFTER UPDATE OF id, titre ON wiki_pages
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET id = new.id, titre = new.titre WHERE id = old.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Trigger pour mettre à jour le contenu de la table de recherche lors d'une nouvelle révision
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_insert AFTER INSERT ON wiki_revisions WHEN new.chiffrement != 1
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET contenu = new.contenu WHERE id = new.id_page;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Si le contenu est chiffré, la recherche n'affiche pas de contenu
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_chiffre AFTER INSERT ON wiki_revisions WHEN new.chiffrement = 1
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET contenu = '' WHERE id = new.id_page;
|
||||||
|
END;
|
||||||
|
|
||||||
|
/*
|
||||||
|
CREATE TABLE wiki_suivi
|
||||||
|
-- Suivi des pages
|
||||||
|
(
|
||||||
|
id_membre INTEGER NOT NULL,
|
||||||
|
id_page INTEGER NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (id_membre, id_page),
|
||||||
|
|
||||||
|
FOREIGN KEY (id_page) REFERENCES wiki_pages (id), -- Clé externe obligatoire
|
||||||
|
FOREIGN KEY (id_membre) REFERENCES membres (id) -- Clé externe obligatoire
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
|
--
|
||||||
|
-- COMPTA
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_exercices
|
||||||
|
-- Exercices
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL,
|
||||||
|
|
||||||
|
debut TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(debut) IS NOT NULL AND date(debut) = debut),
|
||||||
|
fin TEXT NULL DEFAULT NULL CHECK (fin IS NULL OR (date(fin) IS NOT NULL AND date(fin) = fin)),
|
||||||
|
|
||||||
|
cloture INTEGER NOT NULL DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_comptes
|
||||||
|
-- Plan comptable
|
||||||
|
(
|
||||||
|
id TEXT NOT NULL PRIMARY KEY, -- peut contenir des lettres, eg. 53A, 53B, etc.
|
||||||
|
parent TEXT NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL,
|
||||||
|
|
||||||
|
position INTEGER NOT NULL, -- position actif/passif/charge/produit
|
||||||
|
plan_comptable INTEGER NOT NULL DEFAULT 1, -- 1 = fait partie du plan comptable, 0 = a été ajouté par l'utilisateur
|
||||||
|
desactive INTEGER NOT NULL DEFAULT 0 -- 1 = compte historique désactivé
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_comptes_parent ON compta_comptes (parent);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_comptes_bancaires
|
||||||
|
-- Comptes bancaires
|
||||||
|
(
|
||||||
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
banque TEXT NOT NULL,
|
||||||
|
|
||||||
|
iban TEXT NULL,
|
||||||
|
bic TEXT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(id) REFERENCES compta_comptes(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_projets
|
||||||
|
-- Projets (compta analytique)
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_journal
|
||||||
|
-- Journal des opérations comptables
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL,
|
||||||
|
remarques TEXT NULL,
|
||||||
|
numero_piece TEXT NULL, -- N° de pièce comptable
|
||||||
|
|
||||||
|
montant REAL NOT NULL,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date),
|
||||||
|
moyen_paiement TEXT NULL,
|
||||||
|
numero_cheque TEXT NULL,
|
||||||
|
|
||||||
|
compte_debit TEXT NULL, -- N° du compte dans le plan, NULL est utilisé pour une opération qui vient d'un exercice précédent
|
||||||
|
compte_credit TEXT NULL, -- N° du compte dans le plan
|
||||||
|
|
||||||
|
id_exercice INTEGER NULL DEFAULT NULL, -- En cas de compta simple, l'exercice est permanent (NULL)
|
||||||
|
id_auteur INTEGER NULL,
|
||||||
|
id_categorie INTEGER NULL, -- Numéro de catégorie (en mode simple)
|
||||||
|
id_projet INTEGER NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(moyen_paiement) REFERENCES compta_moyens_paiement(code),
|
||||||
|
FOREIGN KEY(compte_debit) REFERENCES compta_comptes(id),
|
||||||
|
FOREIGN KEY(compte_credit) REFERENCES compta_comptes(id),
|
||||||
|
FOREIGN KEY(id_exercice) REFERENCES compta_exercices(id),
|
||||||
|
FOREIGN KEY(id_auteur) REFERENCES membres(id) ON DELETE SET NULL,
|
||||||
|
FOREIGN KEY(id_categorie) REFERENCES compta_categories(id) ON DELETE SET NULL,
|
||||||
|
FOREIGN KEY(id_projet) REFERENCES compta_projets(id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_exercice ON compta_journal (id_exercice);
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_date ON compta_journal (date);
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_comptes ON compta_journal (compte_debit, compte_credit);
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_auteur ON compta_journal (id_auteur);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_moyens_paiement
|
||||||
|
-- Moyens de paiement
|
||||||
|
(
|
||||||
|
code TEXT NOT NULL PRIMARY KEY,
|
||||||
|
nom TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
--INSERT INTO compta_moyens_paiement (code, nom) VALUES ('AU', 'Autre');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CB', 'Carte bleue');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CH', 'Chèque');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('ES', 'Espèces');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('PR', 'Prélèvement');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('TI', 'TIP');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('VI', 'Virement');
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_categories
|
||||||
|
-- Catégories pour simplifier le plan comptable
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
type INTEGER NOT NULL DEFAULT 1, -- 1 = recette, -1 = dépense, 0 = autre (utilisé uniquement pour l'interface)
|
||||||
|
|
||||||
|
intitule TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
|
||||||
|
compte TEXT NOT NULL, -- Compte affecté par cette catégorie
|
||||||
|
|
||||||
|
FOREIGN KEY(compte) REFERENCES compta_comptes(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS plugins
|
||||||
|
(
|
||||||
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
|
officiel INTEGER NOT NULL DEFAULT 0,
|
||||||
|
nom TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
auteur TEXT NULL,
|
||||||
|
url TEXT NULL,
|
||||||
|
version TEXT NOT NULL,
|
||||||
|
menu INTEGER NOT NULL DEFAULT 0,
|
||||||
|
config TEXT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS plugins_signaux
|
||||||
|
-- Association entre plugins et signaux (hooks)
|
||||||
|
(
|
||||||
|
signal TEXT NOT NULL,
|
||||||
|
plugin TEXT NOT NULL REFERENCES plugins (id),
|
||||||
|
callback TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (signal, plugin)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_rapprochement
|
||||||
|
-- Rapprochement entre compta et relevés de comptes
|
||||||
|
(
|
||||||
|
id_operation INTEGER NOT NULL PRIMARY KEY REFERENCES compta_journal (id) ON DELETE CASCADE,
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date),
|
||||||
|
id_auteur INTEGER NULL REFERENCES membres (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers
|
||||||
|
-- Données sur les fichiers
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg)
|
||||||
|
type TEXT NULL, -- Type MIME
|
||||||
|
image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue
|
||||||
|
datetime TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(datetime) IS NOT NULL AND datetime(datetime) = datetime), -- Date d'ajout ou mise à jour du fichier
|
||||||
|
id_contenu INTEGER NOT NULL REFERENCES fichiers_contenu (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS fichiers_date ON fichiers (datetime);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_contenu
|
||||||
|
-- Contenu des fichiers
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier
|
||||||
|
taille INTEGER NOT NULL, -- Taille en octets
|
||||||
|
contenu BLOB NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS fichiers_hash ON fichiers_contenu (hash);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_membres
|
||||||
|
-- Associations entre fichiers et membres (photo de profil par exemple)
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES membres (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_wiki_pages
|
||||||
|
-- Associations entre fichiers et pages du wiki
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES wiki_pages (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_compta_journal
|
||||||
|
-- Associations entre fichiers et journal de compta (pièce comptable par exemple)
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES compta_journal (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
3
archives/0.8.4_migration.sql
Normal file
3
archives/0.8.4_migration.sql
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
-- Mise à jour des URI du wiki pour ne pas inclure les tirets en début et fin de chaîne
|
||||||
|
-- (problème de concordance entre API PHP et données SQLite)
|
||||||
|
UPDATE wiki_pages SET uri = trim(uri, '-') WHERE uri != trim(uri, '-');
|
35
archives/0.9.0_migration.sql
Normal file
35
archives/0.9.0_migration.sql
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
-- Désactivation de l'accès aux membres, pour les groupes qui n'avaient que le droit de lecture
|
||||||
|
-- car maintenant ce droit permet de voir les fiches de membres complètes
|
||||||
|
UPDATE membres_categories SET droit_membres = 0 WHERE droit_membres = 1;
|
||||||
|
|
||||||
|
-- Suppression de la colonne description des catégories
|
||||||
|
ALTER TABLE membres_categories RENAME TO membres_categories_old;
|
||||||
|
|
||||||
|
-- Mise à jour table compta_rapprochement: la foreign key sur membres est passée
|
||||||
|
-- à ON DELETE SET NULL
|
||||||
|
ALTER TABLE compta_rapprochement RENAME TO compta_rapprochement_old;
|
||||||
|
|
||||||
|
-- Re-créer la table
|
||||||
|
-- Créer également les nouvelles tables email
|
||||||
|
.read 0.9.0_schema.sql
|
||||||
|
|
||||||
|
-- Copie des données, sauf la colonne description
|
||||||
|
INSERT INTO membres_categories SELECT id, nom, droit_wiki,
|
||||||
|
droit_membres, droit_compta, droit_inscription,
|
||||||
|
droit_connexion, droit_config, cacher,
|
||||||
|
id_cotisation_obligatoire FROM membres_categories_old;
|
||||||
|
|
||||||
|
-- Suppression des anciennes tables
|
||||||
|
DROP TABLE membres_categories_old;
|
||||||
|
|
||||||
|
-- Migration des données
|
||||||
|
INSERT INTO compta_rapprochement SELECT * FROM compta_rapprochement_old;
|
||||||
|
DROP TABLE compta_rapprochement_old;
|
||||||
|
|
||||||
|
-- Cette variable n'est plus utilisée
|
||||||
|
DELETE FROM config WHERE cle = 'email_envoi_automatique';
|
||||||
|
|
||||||
|
ALTER TABLE plugins ADD COLUMN menu_condition TEXT NULL;
|
||||||
|
|
||||||
|
-- Supprimer le début dans le nom des plugins
|
||||||
|
UPDATE plugins_signaux SET callback = replace(callback, 'Garradin\Plugin\', '');
|
35
archives/0.9.0_schema.sql
Normal file
35
archives/0.9.0_schema.sql
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
-- Désactivation de l'accès aux membres, pour les groupes qui n'avaient que le droit de lecture
|
||||||
|
-- car maintenant ce droit permet de voir les fiches de membres complètes
|
||||||
|
UPDATE membres_categories SET droit_membres = 0 WHERE droit_membres = 1;
|
||||||
|
|
||||||
|
-- Suppression de la colonne description des catégories
|
||||||
|
ALTER TABLE membres_categories RENAME TO membres_categories_old;
|
||||||
|
|
||||||
|
-- Mise à jour table compta_rapprochement: la foreign key sur membres est passée
|
||||||
|
-- à ON DELETE SET NULL
|
||||||
|
ALTER TABLE compta_rapprochement RENAME TO compta_rapprochement_old;
|
||||||
|
|
||||||
|
-- Re-créer la table
|
||||||
|
-- Créer également les nouvelles tables email
|
||||||
|
.read schema.sql
|
||||||
|
|
||||||
|
-- Copie des données, sauf la colonne description
|
||||||
|
INSERT INTO membres_categories SELECT id, nom, droit_wiki,
|
||||||
|
droit_membres, droit_compta, droit_inscription,
|
||||||
|
droit_connexion, droit_config, cacher,
|
||||||
|
id_cotisation_obligatoire FROM membres_categories_old;
|
||||||
|
|
||||||
|
-- Suppression des anciennes tables
|
||||||
|
DROP TABLE membres_categories_old;
|
||||||
|
|
||||||
|
-- Migration des données
|
||||||
|
INSERT INTO compta_rapprochement SELECT * FROM compta_rapprochement_old;
|
||||||
|
DROP TABLE compta_rapprochement_old;
|
||||||
|
|
||||||
|
-- Cette variable n'est plus utilisée
|
||||||
|
DELETE FROM config WHERE cle = 'email_envoi_automatique';
|
||||||
|
|
||||||
|
ALTER TABLE plugins ADD COLUMN menu_condition TEXT NULL;
|
||||||
|
|
||||||
|
-- Supprimer le début dans le nom des plugins
|
||||||
|
UPDATE plugins_signaux SET callback = replace(callback, 'Garradin\Plugin\', '');
|
14
archives/0.9.1_migration.sql
Normal file
14
archives/0.9.1_migration.sql
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
-- Il manquait une clause ON DELETE SET NULL sur la foreign key
|
||||||
|
-- de cotisations quand on faisait une mise à jour depuis une
|
||||||
|
-- ancienne version
|
||||||
|
ALTER TABLE cotisations RENAME TO cotisations_old;
|
||||||
|
|
||||||
|
.read 0.9.1_schema.sql
|
||||||
|
|
||||||
|
INSERT INTO cotisations SELECT * FROM cotisations_old;
|
||||||
|
|
||||||
|
DROP TABLE cotisations_old;
|
||||||
|
|
||||||
|
-- Changer le compte des reports automatiques
|
||||||
|
UPDATE compta_journal SET compte_debit = '890' WHERE compte_debit IS NULL;
|
||||||
|
UPDATE compta_journal SET compte_credit = '890' WHERE compte_credit IS NULL;
|
400
archives/0.9.1_schema.sql
Normal file
400
archives/0.9.1_schema.sql
Normal file
|
@ -0,0 +1,400 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS config (
|
||||||
|
-- Configuration de Garradin
|
||||||
|
cle TEXT PRIMARY KEY NOT NULL,
|
||||||
|
valeur TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
-- On stocke ici les ID de catégorie de compta correspondant aux types spéciaux
|
||||||
|
-- compta_categorie_cotisations => id_categorie
|
||||||
|
-- compta_categorie_dons => id_categorie
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_categories
|
||||||
|
-- Catégories de membres
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
nom TEXT NOT NULL,
|
||||||
|
|
||||||
|
droit_wiki INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_membres INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_compta INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_inscription INTEGER NOT NULL DEFAULT 0,
|
||||||
|
droit_connexion INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_config INTEGER NOT NULL DEFAULT 0,
|
||||||
|
cacher INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
id_cotisation_obligatoire INTEGER NULL REFERENCES cotisations (id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Membres de l'asso
|
||||||
|
-- Table dynamique générée par l'application
|
||||||
|
-- voir Garradin\Membres\Champs.php
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_sessions
|
||||||
|
-- Sessions
|
||||||
|
(
|
||||||
|
selecteur TEXT NOT NULL,
|
||||||
|
hash TEXT NOT NULL,
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
expire INT NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (selecteur, id_membre)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS cotisations
|
||||||
|
-- Types de cotisations et activités
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
id_categorie_compta INTEGER NULL REFERENCES compta_categories (id) ON DELETE SET NULL, -- NULL si le type n'est pas associé automatiquement à la compta
|
||||||
|
|
||||||
|
intitule TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
montant REAL NOT NULL,
|
||||||
|
|
||||||
|
duree INTEGER NULL, -- En jours
|
||||||
|
debut TEXT NULL, -- timestamp
|
||||||
|
fin TEXT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS cotisations_membres
|
||||||
|
-- Enregistrement des cotisations et activités
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS cm_unique ON cotisations_membres (id_membre, id_cotisation, date);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_operations
|
||||||
|
-- Liaison des enregistrement des paiements en compta
|
||||||
|
(
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_operation INTEGER NOT NULL REFERENCES compta_journal (id) ON DELETE CASCADE,
|
||||||
|
id_cotisation INTEGER NULL REFERENCES cotisations_membres (id) ON DELETE SET NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (id_membre, id_operation)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS rappels
|
||||||
|
-- Rappels de devoir renouveller une cotisation
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
delai INTEGER NOT NULL, -- Délai en jours pour envoyer le rappel
|
||||||
|
|
||||||
|
sujet TEXT NOT NULL,
|
||||||
|
texte TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS rappels_envoyes
|
||||||
|
-- Enregistrement des rappels envoyés à qui et quand
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE,
|
||||||
|
id_rappel INTEGER NULL REFERENCES rappels (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date),
|
||||||
|
|
||||||
|
media INTEGER NOT NULL -- Média utilisé pour le rappel : 1 = email, 2 = courrier, 3 = autre
|
||||||
|
);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- WIKI
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS wiki_pages
|
||||||
|
-- Pages du wiki
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
uri TEXT NOT NULL, -- URI unique (équivalent NomPageWiki)
|
||||||
|
titre TEXT NOT NULL,
|
||||||
|
date_creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_creation) IS NOT NULL AND datetime(date_creation) = date_creation),
|
||||||
|
date_modification TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_modification) IS NOT NULL AND datetime(date_modification) = date_modification),
|
||||||
|
parent INTEGER NOT NULL DEFAULT 0, -- ID de la page parent
|
||||||
|
revision INTEGER NOT NULL DEFAULT 0, -- Numéro de révision (commence à 0 si pas de texte, +1 à chaque changement du texte)
|
||||||
|
droit_lecture INTEGER NOT NULL DEFAULT 0, -- Accès en lecture (-1 = public [site web], 0 = tous ceux qui ont accès en lecture au wiki, 1+ = ID de groupe)
|
||||||
|
droit_ecriture INTEGER NOT NULL DEFAULT 0 -- Accès en écriture (0 = tous ceux qui ont droit d'écriture sur le wiki, 1+ = ID de groupe)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS wiki_uri ON wiki_pages (uri);
|
||||||
|
|
||||||
|
CREATE VIRTUAL TABLE IF NOT EXISTS wiki_recherche USING fts4
|
||||||
|
-- Table dupliquée pour chercher une page
|
||||||
|
(
|
||||||
|
id INT PRIMARY KEY NOT NULL, -- Clé externe obligatoire
|
||||||
|
titre TEXT NOT NULL,
|
||||||
|
contenu TEXT NULL, -- Contenu de la dernière révision
|
||||||
|
FOREIGN KEY (id) REFERENCES wiki_pages(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS wiki_revisions
|
||||||
|
-- Révisions du contenu des pages
|
||||||
|
(
|
||||||
|
id_page INTEGER NOT NULL REFERENCES wiki_pages (id) ON DELETE CASCADE,
|
||||||
|
revision INTEGER NULL,
|
||||||
|
|
||||||
|
id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL,
|
||||||
|
|
||||||
|
contenu TEXT NOT NULL,
|
||||||
|
modification TEXT NULL, -- Description des modifications effectuées
|
||||||
|
chiffrement INTEGER NOT NULL DEFAULT 0, -- 1 si le contenu est chiffré, 0 sinon
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date),
|
||||||
|
|
||||||
|
PRIMARY KEY(id_page, revision)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS wiki_revisions_id_page ON wiki_revisions (id_page);
|
||||||
|
CREATE INDEX IF NOT EXISTS wiki_revisions_id_auteur ON wiki_revisions (id_auteur);
|
||||||
|
|
||||||
|
-- Triggers pour synchro avec table wiki_pages
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_delete AFTER DELETE ON wiki_pages
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM wiki_recherche WHERE id = old.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_update AFTER UPDATE OF id, titre ON wiki_pages
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET id = new.id, titre = new.titre WHERE id = old.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Trigger pour mettre à jour le contenu de la table de recherche lors d'une nouvelle révision
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_insert AFTER INSERT ON wiki_revisions WHEN new.chiffrement != 1
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET contenu = new.contenu WHERE id = new.id_page;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Si le contenu est chiffré, la recherche n'affiche pas de contenu
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_chiffre AFTER INSERT ON wiki_revisions WHEN new.chiffrement = 1
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET contenu = '' WHERE id = new.id_page;
|
||||||
|
END;
|
||||||
|
|
||||||
|
/*
|
||||||
|
CREATE TABLE wiki_suivi
|
||||||
|
-- Suivi des pages
|
||||||
|
(
|
||||||
|
id_membre INTEGER NOT NULL,
|
||||||
|
id_page INTEGER NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (id_membre, id_page),
|
||||||
|
|
||||||
|
FOREIGN KEY (id_page) REFERENCES wiki_pages (id), -- Clé externe obligatoire
|
||||||
|
FOREIGN KEY (id_membre) REFERENCES membres (id) -- Clé externe obligatoire
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
|
--
|
||||||
|
-- COMPTA
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_exercices
|
||||||
|
-- Exercices
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL,
|
||||||
|
|
||||||
|
debut TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(debut) IS NOT NULL AND date(debut) = debut),
|
||||||
|
fin TEXT NULL DEFAULT NULL CHECK (fin IS NULL OR (date(fin) IS NOT NULL AND date(fin) = fin)),
|
||||||
|
|
||||||
|
cloture INTEGER NOT NULL DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_comptes
|
||||||
|
-- Plan comptable
|
||||||
|
(
|
||||||
|
id TEXT NOT NULL PRIMARY KEY, -- peut contenir des lettres, eg. 53A, 53B, etc.
|
||||||
|
parent TEXT NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL,
|
||||||
|
|
||||||
|
position INTEGER NOT NULL, -- position actif/passif/charge/produit
|
||||||
|
plan_comptable INTEGER NOT NULL DEFAULT 1, -- 1 = fait partie du plan comptable, 0 = a été ajouté par l'utilisateur
|
||||||
|
desactive INTEGER NOT NULL DEFAULT 0 -- 1 = compte historique désactivé
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_comptes_parent ON compta_comptes (parent);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_comptes_bancaires
|
||||||
|
-- Comptes bancaires
|
||||||
|
(
|
||||||
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
banque TEXT NOT NULL,
|
||||||
|
|
||||||
|
iban TEXT NULL,
|
||||||
|
bic TEXT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(id) REFERENCES compta_comptes(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_projets
|
||||||
|
-- Projets (compta analytique)
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_journal
|
||||||
|
-- Journal des opérations comptables
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL,
|
||||||
|
remarques TEXT NULL,
|
||||||
|
numero_piece TEXT NULL, -- N° de pièce comptable
|
||||||
|
|
||||||
|
montant REAL NOT NULL,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date),
|
||||||
|
moyen_paiement TEXT NULL,
|
||||||
|
numero_cheque TEXT NULL,
|
||||||
|
|
||||||
|
compte_debit TEXT NULL, -- N° du compte dans le plan, NULL est utilisé pour une opération qui vient d'un exercice précédent
|
||||||
|
compte_credit TEXT NULL, -- N° du compte dans le plan
|
||||||
|
|
||||||
|
id_exercice INTEGER NULL DEFAULT NULL, -- En cas de compta simple, l'exercice est permanent (NULL)
|
||||||
|
id_auteur INTEGER NULL,
|
||||||
|
id_categorie INTEGER NULL, -- Numéro de catégorie (en mode simple)
|
||||||
|
id_projet INTEGER NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(moyen_paiement) REFERENCES compta_moyens_paiement(code),
|
||||||
|
FOREIGN KEY(compte_debit) REFERENCES compta_comptes(id),
|
||||||
|
FOREIGN KEY(compte_credit) REFERENCES compta_comptes(id),
|
||||||
|
FOREIGN KEY(id_exercice) REFERENCES compta_exercices(id),
|
||||||
|
FOREIGN KEY(id_auteur) REFERENCES membres(id) ON DELETE SET NULL,
|
||||||
|
FOREIGN KEY(id_categorie) REFERENCES compta_categories(id) ON DELETE SET NULL,
|
||||||
|
FOREIGN KEY(id_projet) REFERENCES compta_projets(id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_exercice ON compta_journal (id_exercice);
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_date ON compta_journal (date);
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_comptes ON compta_journal (compte_debit, compte_credit);
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_auteur ON compta_journal (id_auteur);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_moyens_paiement
|
||||||
|
-- Moyens de paiement
|
||||||
|
(
|
||||||
|
code TEXT NOT NULL PRIMARY KEY,
|
||||||
|
nom TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
--INSERT INTO compta_moyens_paiement (code, nom) VALUES ('AU', 'Autre');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CB', 'Carte bleue');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CH', 'Chèque');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('ES', 'Espèces');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('PR', 'Prélèvement');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('TI', 'TIP');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('VI', 'Virement');
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_categories
|
||||||
|
-- Catégories pour simplifier le plan comptable
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
type INTEGER NOT NULL DEFAULT 1, -- 1 = recette, -1 = dépense, 0 = autre (utilisé uniquement pour l'interface)
|
||||||
|
|
||||||
|
intitule TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
|
||||||
|
compte TEXT NOT NULL, -- Compte affecté par cette catégorie
|
||||||
|
|
||||||
|
FOREIGN KEY(compte) REFERENCES compta_comptes(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS plugins
|
||||||
|
(
|
||||||
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
|
officiel INTEGER NOT NULL DEFAULT 0,
|
||||||
|
nom TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
auteur TEXT NULL,
|
||||||
|
url TEXT NULL,
|
||||||
|
version TEXT NOT NULL,
|
||||||
|
menu INTEGER NOT NULL DEFAULT 0,
|
||||||
|
menu_condition TEXT NULL,
|
||||||
|
config TEXT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS plugins_signaux
|
||||||
|
-- Association entre plugins et signaux (hooks)
|
||||||
|
(
|
||||||
|
signal TEXT NOT NULL,
|
||||||
|
plugin TEXT NOT NULL REFERENCES plugins (id),
|
||||||
|
callback TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (signal, plugin)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_rapprochement
|
||||||
|
-- Rapprochement entre compta et relevés de comptes
|
||||||
|
(
|
||||||
|
id_operation INTEGER NOT NULL PRIMARY KEY REFERENCES compta_journal (id) ON DELETE CASCADE,
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date),
|
||||||
|
id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers
|
||||||
|
-- Données sur les fichiers
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg)
|
||||||
|
type TEXT NULL, -- Type MIME
|
||||||
|
image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue
|
||||||
|
datetime TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(datetime) IS NOT NULL AND datetime(datetime) = datetime), -- Date d'ajout ou mise à jour du fichier
|
||||||
|
id_contenu INTEGER NOT NULL REFERENCES fichiers_contenu (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS fichiers_date ON fichiers (datetime);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_contenu
|
||||||
|
-- Contenu des fichiers
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier
|
||||||
|
taille INTEGER NOT NULL, -- Taille en octets
|
||||||
|
contenu BLOB NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS fichiers_hash ON fichiers_contenu (hash);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_membres
|
||||||
|
-- Associations entre fichiers et membres (photo de profil par exemple)
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES membres (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_wiki_pages
|
||||||
|
-- Associations entre fichiers et pages du wiki
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES wiki_pages (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_compta_journal
|
||||||
|
-- Associations entre fichiers et journal de compta (pièce comptable par exemple)
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES compta_journal (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS recherches
|
||||||
|
-- Recherches enregistrées
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_membre INTEGER NULL REFERENCES membres (id) ON DELETE CASCADE, -- Si non NULL, alors la recherche ne sera visible que par le membre associé
|
||||||
|
intitule TEXT NOT NULL,
|
||||||
|
creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(creation) IS NOT NULL AND datetime(creation) = creation),
|
||||||
|
cible TEXT NOT NULL, -- "membres" ou "compta_journal"
|
||||||
|
type TEXT NOT NULL, -- "json" ou "sql"
|
||||||
|
contenu TEXT NOT NULL
|
||||||
|
);
|
414
archives/0.9.5_schema.sql
Normal file
414
archives/0.9.5_schema.sql
Normal file
|
@ -0,0 +1,414 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS config (
|
||||||
|
-- Configuration de Garradin
|
||||||
|
cle TEXT PRIMARY KEY NOT NULL,
|
||||||
|
valeur TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
-- On stocke ici les ID de catégorie de compta correspondant aux types spéciaux
|
||||||
|
-- compta_categorie_cotisations => id_categorie
|
||||||
|
-- compta_categorie_dons => id_categorie
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_categories
|
||||||
|
-- Catégories de membres
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
nom TEXT NOT NULL,
|
||||||
|
|
||||||
|
droit_wiki INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_membres INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_compta INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_inscription INTEGER NOT NULL DEFAULT 0,
|
||||||
|
droit_connexion INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_config INTEGER NOT NULL DEFAULT 0,
|
||||||
|
cacher INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
id_cotisation_obligatoire INTEGER NULL REFERENCES cotisations (id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Membres de l'asso
|
||||||
|
-- Table dynamique générée par l'application
|
||||||
|
-- voir Garradin\Membres\Champs.php
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_sessions
|
||||||
|
-- Sessions
|
||||||
|
(
|
||||||
|
selecteur TEXT NOT NULL,
|
||||||
|
hash TEXT NOT NULL,
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
expire INT NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (selecteur, id_membre)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS cotisations
|
||||||
|
-- Types de cotisations et activités
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
id_categorie_compta INTEGER NULL REFERENCES compta_categories (id) ON DELETE SET NULL, -- NULL si le type n'est pas associé automatiquement à la compta
|
||||||
|
|
||||||
|
intitule TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
montant REAL NOT NULL,
|
||||||
|
|
||||||
|
duree INTEGER NULL, -- En jours
|
||||||
|
debut TEXT NULL, -- timestamp
|
||||||
|
fin TEXT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS cotisations_membres
|
||||||
|
-- Enregistrement des cotisations et activités
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS cm_unique ON cotisations_membres (id_membre, id_cotisation, date);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_operations
|
||||||
|
-- Liaison des enregistrement des paiements en compta
|
||||||
|
(
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_operation INTEGER NOT NULL REFERENCES compta_journal (id) ON DELETE CASCADE,
|
||||||
|
id_cotisation INTEGER NULL REFERENCES cotisations_membres (id) ON DELETE SET NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (id_membre, id_operation)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS rappels
|
||||||
|
-- Rappels de devoir renouveller une cotisation
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
delai INTEGER NOT NULL, -- Délai en jours pour envoyer le rappel
|
||||||
|
|
||||||
|
sujet TEXT NOT NULL,
|
||||||
|
texte TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS rappels_envoyes
|
||||||
|
-- Enregistrement des rappels envoyés à qui et quand
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_cotisation INTEGER NOT NULL REFERENCES cotisations (id) ON DELETE CASCADE,
|
||||||
|
id_rappel INTEGER NULL REFERENCES rappels (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date),
|
||||||
|
|
||||||
|
media INTEGER NOT NULL -- Média utilisé pour le rappel : 1 = email, 2 = courrier, 3 = autre
|
||||||
|
);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- WIKI
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS wiki_pages
|
||||||
|
-- Pages du wiki
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
uri TEXT NOT NULL, -- URI unique (équivalent NomPageWiki)
|
||||||
|
titre TEXT NOT NULL,
|
||||||
|
date_creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_creation) IS NOT NULL AND datetime(date_creation) = date_creation),
|
||||||
|
date_modification TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_modification) IS NOT NULL AND datetime(date_modification) = date_modification),
|
||||||
|
parent INTEGER NOT NULL DEFAULT 0, -- ID de la page parent
|
||||||
|
revision INTEGER NOT NULL DEFAULT 0, -- Numéro de révision (commence à 0 si pas de texte, +1 à chaque changement du texte)
|
||||||
|
droit_lecture INTEGER NOT NULL DEFAULT 0, -- Accès en lecture (-1 = public [site web], 0 = tous ceux qui ont accès en lecture au wiki, 1+ = ID de groupe)
|
||||||
|
droit_ecriture INTEGER NOT NULL DEFAULT 0 -- Accès en écriture (0 = tous ceux qui ont droit d'écriture sur le wiki, 1+ = ID de groupe)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS wiki_uri ON wiki_pages (uri);
|
||||||
|
|
||||||
|
CREATE VIRTUAL TABLE IF NOT EXISTS wiki_recherche USING fts4
|
||||||
|
-- Table dupliquée pour chercher une page
|
||||||
|
(
|
||||||
|
id INT PRIMARY KEY NOT NULL, -- Clé externe obligatoire
|
||||||
|
titre TEXT NOT NULL,
|
||||||
|
contenu TEXT NULL, -- Contenu de la dernière révision
|
||||||
|
FOREIGN KEY (id) REFERENCES wiki_pages(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS wiki_revisions
|
||||||
|
-- Révisions du contenu des pages
|
||||||
|
(
|
||||||
|
id_page INTEGER NOT NULL REFERENCES wiki_pages (id) ON DELETE CASCADE,
|
||||||
|
revision INTEGER NULL,
|
||||||
|
|
||||||
|
id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL,
|
||||||
|
|
||||||
|
contenu TEXT NOT NULL,
|
||||||
|
modification TEXT NULL, -- Description des modifications effectuées
|
||||||
|
chiffrement INTEGER NOT NULL DEFAULT 0, -- 1 si le contenu est chiffré, 0 sinon
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date),
|
||||||
|
|
||||||
|
PRIMARY KEY(id_page, revision)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS wiki_revisions_id_page ON wiki_revisions (id_page);
|
||||||
|
CREATE INDEX IF NOT EXISTS wiki_revisions_id_auteur ON wiki_revisions (id_auteur);
|
||||||
|
|
||||||
|
-- Triggers pour synchro avec table wiki_pages
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_delete AFTER DELETE ON wiki_pages
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM wiki_recherche WHERE id = old.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_update AFTER UPDATE OF id, titre ON wiki_pages
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET id = new.id, titre = new.titre WHERE id = old.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Trigger pour mettre à jour le contenu de la table de recherche lors d'une nouvelle révision
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_insert AFTER INSERT ON wiki_revisions WHEN new.chiffrement != 1
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET contenu = new.contenu WHERE id = new.id_page;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Si le contenu est chiffré, la recherche n'affiche pas de contenu
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_chiffre AFTER INSERT ON wiki_revisions WHEN new.chiffrement = 1
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET contenu = '' WHERE id = new.id_page;
|
||||||
|
END;
|
||||||
|
|
||||||
|
/*
|
||||||
|
CREATE TABLE wiki_suivi
|
||||||
|
-- Suivi des pages
|
||||||
|
(
|
||||||
|
id_membre INTEGER NOT NULL,
|
||||||
|
id_page INTEGER NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (id_membre, id_page),
|
||||||
|
|
||||||
|
FOREIGN KEY (id_page) REFERENCES wiki_pages (id), -- Clé externe obligatoire
|
||||||
|
FOREIGN KEY (id_membre) REFERENCES membres (id) -- Clé externe obligatoire
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
|
--
|
||||||
|
-- COMPTA
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_exercices
|
||||||
|
-- Exercices
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL,
|
||||||
|
|
||||||
|
debut TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(debut) IS NOT NULL AND date(debut) = debut),
|
||||||
|
fin TEXT NULL DEFAULT NULL CHECK (fin IS NULL OR (date(fin) IS NOT NULL AND date(fin) = fin)),
|
||||||
|
|
||||||
|
cloture INTEGER NOT NULL DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_comptes
|
||||||
|
-- Plan comptable
|
||||||
|
(
|
||||||
|
id TEXT NOT NULL PRIMARY KEY, -- peut contenir des lettres, eg. 53A, 53B, etc.
|
||||||
|
parent TEXT NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL,
|
||||||
|
|
||||||
|
position INTEGER NOT NULL, -- position actif/passif/charge/produit
|
||||||
|
plan_comptable INTEGER NOT NULL DEFAULT 1, -- 1 = fait partie du plan comptable, 0 = a été ajouté par l'utilisateur
|
||||||
|
desactive INTEGER NOT NULL DEFAULT 0 -- 1 = compte historique désactivé
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_comptes_parent ON compta_comptes (parent);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_comptes_bancaires
|
||||||
|
-- Comptes bancaires
|
||||||
|
(
|
||||||
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
banque TEXT NOT NULL,
|
||||||
|
|
||||||
|
iban TEXT NULL,
|
||||||
|
bic TEXT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(id) REFERENCES compta_comptes(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_projets
|
||||||
|
-- Projets (compta analytique)
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_journal
|
||||||
|
-- Journal des opérations comptables
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
libelle TEXT NOT NULL,
|
||||||
|
remarques TEXT NULL,
|
||||||
|
numero_piece TEXT NULL, -- N° de pièce comptable
|
||||||
|
|
||||||
|
montant REAL NOT NULL,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date),
|
||||||
|
moyen_paiement TEXT NULL,
|
||||||
|
numero_cheque TEXT NULL,
|
||||||
|
|
||||||
|
compte_debit TEXT NULL, -- N° du compte dans le plan, NULL est utilisé pour une opération qui vient d'un exercice précédent
|
||||||
|
compte_credit TEXT NULL, -- N° du compte dans le plan
|
||||||
|
|
||||||
|
id_exercice INTEGER NULL DEFAULT NULL, -- En cas de compta simple, l'exercice est permanent (NULL)
|
||||||
|
id_auteur INTEGER NULL,
|
||||||
|
id_categorie INTEGER NULL, -- Numéro de catégorie (en mode simple)
|
||||||
|
id_projet INTEGER NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(moyen_paiement) REFERENCES compta_moyens_paiement(code),
|
||||||
|
FOREIGN KEY(compte_debit) REFERENCES compta_comptes(id),
|
||||||
|
FOREIGN KEY(compte_credit) REFERENCES compta_comptes(id),
|
||||||
|
FOREIGN KEY(id_exercice) REFERENCES compta_exercices(id),
|
||||||
|
FOREIGN KEY(id_auteur) REFERENCES membres(id) ON DELETE SET NULL,
|
||||||
|
FOREIGN KEY(id_categorie) REFERENCES compta_categories(id) ON DELETE SET NULL,
|
||||||
|
FOREIGN KEY(id_projet) REFERENCES compta_projets(id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_exercice ON compta_journal (id_exercice);
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_date ON compta_journal (date);
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_comptes ON compta_journal (compte_debit, compte_credit);
|
||||||
|
CREATE INDEX IF NOT EXISTS compta_operations_auteur ON compta_journal (id_auteur);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_moyens_paiement
|
||||||
|
-- Moyens de paiement
|
||||||
|
(
|
||||||
|
code TEXT NOT NULL PRIMARY KEY,
|
||||||
|
nom TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
--INSERT INTO compta_moyens_paiement (code, nom) VALUES ('AU', 'Autre');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CB', 'Carte bleue');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('CH', 'Chèque');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('ES', 'Espèces');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('PR', 'Prélèvement');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('TI', 'TIP');
|
||||||
|
INSERT OR IGNORE INTO compta_moyens_paiement (code, nom) VALUES ('VI', 'Virement');
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_categories
|
||||||
|
-- Catégories pour simplifier le plan comptable
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
type INTEGER NOT NULL DEFAULT 1, -- 1 = recette, -1 = dépense, 0 = autre (utilisé uniquement pour l'interface)
|
||||||
|
|
||||||
|
intitule TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
|
||||||
|
compte TEXT NOT NULL, -- Compte affecté par cette catégorie
|
||||||
|
|
||||||
|
FOREIGN KEY(compte) REFERENCES compta_comptes(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS plugins
|
||||||
|
(
|
||||||
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
|
officiel INTEGER NOT NULL DEFAULT 0,
|
||||||
|
nom TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
auteur TEXT NULL,
|
||||||
|
url TEXT NULL,
|
||||||
|
version TEXT NOT NULL,
|
||||||
|
menu INTEGER NOT NULL DEFAULT 0,
|
||||||
|
menu_condition TEXT NULL,
|
||||||
|
config TEXT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS plugins_signaux
|
||||||
|
-- Association entre plugins et signaux (hooks)
|
||||||
|
(
|
||||||
|
signal TEXT NOT NULL,
|
||||||
|
plugin TEXT NOT NULL REFERENCES plugins (id),
|
||||||
|
callback TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (signal, plugin)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compta_rapprochement
|
||||||
|
-- Rapprochement entre compta et relevés de comptes
|
||||||
|
(
|
||||||
|
id_operation INTEGER NOT NULL PRIMARY KEY REFERENCES compta_journal (id) ON DELETE CASCADE,
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date),
|
||||||
|
id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers
|
||||||
|
-- Données sur les fichiers
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg)
|
||||||
|
type TEXT NULL, -- Type MIME
|
||||||
|
image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue
|
||||||
|
datetime TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(datetime) IS NOT NULL AND datetime(datetime) = datetime), -- Date d'ajout ou mise à jour du fichier
|
||||||
|
id_contenu INTEGER NOT NULL REFERENCES fichiers_contenu (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS fichiers_date ON fichiers (datetime);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_contenu
|
||||||
|
-- Contenu des fichiers
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier
|
||||||
|
taille INTEGER NOT NULL, -- Taille en octets
|
||||||
|
contenu BLOB NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS fichiers_hash ON fichiers_contenu (hash);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_membres
|
||||||
|
-- Associations entre fichiers et membres (photo de profil par exemple)
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES membres (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_wiki_pages
|
||||||
|
-- Associations entre fichiers et pages du wiki
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES wiki_pages (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_compta_journal
|
||||||
|
-- Associations entre fichiers et journal de compta (pièce comptable par exemple)
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id),
|
||||||
|
id INTEGER NOT NULL REFERENCES compta_journal (id),
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS recherches
|
||||||
|
-- Recherches enregistrées
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_membre INTEGER NULL REFERENCES membres (id) ON DELETE CASCADE, -- Si non NULL, alors la recherche ne sera visible que par le membre associé
|
||||||
|
intitule TEXT NOT NULL,
|
||||||
|
creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(creation) IS NOT NULL AND datetime(creation) = creation),
|
||||||
|
cible TEXT NOT NULL, -- "membres" ou "compta_journal"
|
||||||
|
type TEXT NOT NULL, -- "json" ou "sql"
|
||||||
|
contenu TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compromised_passwords_cache
|
||||||
|
-- Cache des hash de mots de passe compromis
|
||||||
|
(
|
||||||
|
hash TEXT NOT NULL PRIMARY KEY
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compromised_passwords_cache_ranges
|
||||||
|
-- Cache des préfixes de mots de passe compromis
|
||||||
|
(
|
||||||
|
prefix TEXT NOT NULL PRIMARY KEY,
|
||||||
|
date INTEGER NOT NULL
|
||||||
|
);
|
406
archives/1.0.0_schema.sql
Normal file
406
archives/1.0.0_schema.sql
Normal file
|
@ -0,0 +1,406 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS config (
|
||||||
|
-- Configuration de Garradin
|
||||||
|
cle TEXT PRIMARY KEY NOT NULL,
|
||||||
|
valeur TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_categories
|
||||||
|
-- Catégories de membres
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
nom TEXT NOT NULL,
|
||||||
|
|
||||||
|
droit_wiki INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_membres INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_compta INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_inscription INTEGER NOT NULL DEFAULT 0,
|
||||||
|
droit_connexion INTEGER NOT NULL DEFAULT 1,
|
||||||
|
droit_config INTEGER NOT NULL DEFAULT 0,
|
||||||
|
cacher INTEGER NOT NULL DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Membres de l'asso
|
||||||
|
-- Table dynamique générée par l'application
|
||||||
|
-- voir Garradin\Membres\Champs.php
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_sessions
|
||||||
|
-- Sessions
|
||||||
|
(
|
||||||
|
selecteur TEXT NOT NULL,
|
||||||
|
hash TEXT NOT NULL,
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
expire INT NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (selecteur, id_membre)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS services
|
||||||
|
-- Types de services (cotisations)
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
|
||||||
|
duration INTEGER NULL CHECK (duration IS NULL OR duration > 0), -- En jours
|
||||||
|
start_date TEXT NULL CHECK (start_date IS NULL OR date(start_date) = start_date),
|
||||||
|
end_date TEXT NULL CHECK (end_date IS NULL OR (date(end_date) = end_date AND date(end_date) >= date(start_date)))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS services_fees
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
|
||||||
|
amount INTEGER NULL,
|
||||||
|
formula TEXT NULL, -- Formule de calcul du montant de la cotisation, si cotisation dynamique (exemple : membres.revenu_imposable * 0.01)
|
||||||
|
|
||||||
|
id_service INTEGER NOT NULL REFERENCES services (id) ON DELETE CASCADE,
|
||||||
|
id_account INTEGER NULL REFERENCES acc_accounts (id) ON DELETE SET NULL CHECK (id_account IS NULL OR id_year IS NOT NULL), -- NULL si le type n'est pas associé automatiquement à la compta
|
||||||
|
id_year INTEGER NULL REFERENCES acc_years (id) ON DELETE SET NULL -- NULL si le type n'est pas associé automatiquement à la compta
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS services_users
|
||||||
|
-- Enregistrement des cotisations et activités
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_user INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_service INTEGER NOT NULL REFERENCES services (id) ON DELETE CASCADE,
|
||||||
|
id_fee INTEGER NULL REFERENCES services_fees (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
paid INTEGER NOT NULL DEFAULT 0,
|
||||||
|
expected_amount INTEGER NULL,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date),
|
||||||
|
expiry_date TEXT NULL CHECK (date(expiry_date) IS NULL OR date(expiry_date) = expiry_date)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS su_unique ON services_users (id_user, id_service, date);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS su_service ON services_users (id_service);
|
||||||
|
CREATE INDEX IF NOT EXISTS su_fee ON services_users (id_fee);
|
||||||
|
CREATE INDEX IF NOT EXISTS su_paid ON services_users (paid);
|
||||||
|
CREATE INDEX IF NOT EXISTS su_expiry ON services_users (expiry_date);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS services_reminders
|
||||||
|
-- Rappels de devoir renouveller une cotisation
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_service INTEGER NOT NULL REFERENCES services (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
delay INTEGER NOT NULL, -- Délai en jours pour envoyer le rappel
|
||||||
|
|
||||||
|
subject TEXT NOT NULL,
|
||||||
|
body TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS services_reminders_sent
|
||||||
|
-- Enregistrement des rappels envoyés à qui et quand
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
id_user INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_service INTEGER NOT NULL REFERENCES services (id) ON DELETE CASCADE,
|
||||||
|
id_reminder INTEGER NOT NULL REFERENCES services_reminders (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS srs_index ON services_reminders_sent (id_user, id_service, id_reminder, date);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS srs_reminder ON services_reminders_sent (id_reminder);
|
||||||
|
CREATE INDEX IF NOT EXISTS srs_user ON services_reminders_sent (id_user);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- WIKI
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS wiki_pages
|
||||||
|
-- Pages du wiki
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
uri TEXT NOT NULL, -- URI unique (équivalent NomPageWiki)
|
||||||
|
titre TEXT NOT NULL,
|
||||||
|
date_creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_creation) IS NOT NULL AND datetime(date_creation) = date_creation),
|
||||||
|
date_modification TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date_modification) IS NOT NULL AND datetime(date_modification) = date_modification),
|
||||||
|
parent INTEGER NOT NULL DEFAULT 0, -- ID de la page parent
|
||||||
|
revision INTEGER NOT NULL DEFAULT 0, -- Numéro de révision (commence à 0 si pas de texte, +1 à chaque changement du texte)
|
||||||
|
droit_lecture INTEGER NOT NULL DEFAULT 0, -- Accès en lecture (-1 = public [site web], 0 = tous ceux qui ont accès en lecture au wiki, 1+ = ID de groupe)
|
||||||
|
droit_ecriture INTEGER NOT NULL DEFAULT 0 -- Accès en écriture (0 = tous ceux qui ont droit d'écriture sur le wiki, 1+ = ID de groupe)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS wiki_uri ON wiki_pages (uri);
|
||||||
|
|
||||||
|
CREATE VIRTUAL TABLE IF NOT EXISTS wiki_recherche USING fts4
|
||||||
|
-- Table dupliquée pour chercher une page
|
||||||
|
(
|
||||||
|
id INT PRIMARY KEY NOT NULL, -- Clé externe obligatoire
|
||||||
|
titre TEXT NOT NULL,
|
||||||
|
contenu TEXT NULL, -- Contenu de la dernière révision
|
||||||
|
FOREIGN KEY (id) REFERENCES wiki_pages(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS wiki_revisions
|
||||||
|
-- Révisions du contenu des pages
|
||||||
|
(
|
||||||
|
id_page INTEGER NOT NULL REFERENCES wiki_pages (id) ON DELETE CASCADE,
|
||||||
|
revision INTEGER NULL,
|
||||||
|
|
||||||
|
id_auteur INTEGER NULL REFERENCES membres (id) ON DELETE SET NULL,
|
||||||
|
|
||||||
|
contenu TEXT NOT NULL,
|
||||||
|
modification TEXT NULL, -- Description des modifications effectuées
|
||||||
|
chiffrement INTEGER NOT NULL DEFAULT 0, -- 1 si le contenu est chiffré, 0 sinon
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(date) IS NOT NULL AND datetime(date) = date),
|
||||||
|
|
||||||
|
PRIMARY KEY(id_page, revision)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS wiki_revisions_id_page ON wiki_revisions (id_page);
|
||||||
|
CREATE INDEX IF NOT EXISTS wiki_revisions_id_auteur ON wiki_revisions (id_auteur);
|
||||||
|
|
||||||
|
-- Triggers pour synchro avec table wiki_pages
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_delete AFTER DELETE ON wiki_pages
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM wiki_recherche WHERE id = old.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_update AFTER UPDATE OF id, titre ON wiki_pages
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET id = new.id, titre = new.titre WHERE id = old.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Trigger pour mettre à jour le contenu de la table de recherche lors d'une nouvelle révision
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_insert AFTER INSERT ON wiki_revisions WHEN new.chiffrement != 1
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET contenu = new.contenu WHERE id = new.id_page;
|
||||||
|
END;
|
||||||
|
|
||||||
|
-- Si le contenu est chiffré, la recherche n'affiche pas de contenu
|
||||||
|
CREATE TRIGGER IF NOT EXISTS wiki_recherche_contenu_chiffre AFTER INSERT ON wiki_revisions WHEN new.chiffrement = 1
|
||||||
|
BEGIN
|
||||||
|
UPDATE wiki_recherche SET contenu = '' WHERE id = new.id_page;
|
||||||
|
END;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- COMPTA
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS acc_charts
|
||||||
|
-- Plans comptables : il peut y en avoir plusieurs
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
country TEXT NOT NULL,
|
||||||
|
code TEXT NULL, -- NULL = plan comptable créé par l'utilisateur
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
archived INTEGER NOT NULL DEFAULT 0 -- 1 = archivé, non-modifiable
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS acc_accounts
|
||||||
|
-- Comptes des plans comptables
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_chart INTEGER NOT NULL REFERENCES acc_charts ON DELETE CASCADE,
|
||||||
|
|
||||||
|
code TEXT NOT NULL, -- peut contenir des lettres, eg. 53A, 53B, etc.
|
||||||
|
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
|
||||||
|
position INTEGER NOT NULL, -- position actif/passif/charge/produit
|
||||||
|
type INTEGER NOT NULL DEFAULT 0, -- Type de compte spécial : banque, caisse, en attente d'encaissement, etc.
|
||||||
|
user INTEGER NOT NULL DEFAULT 1 -- 1 = fait partie du plan comptable original, 0 = a été ajouté par l'utilisateur
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS acc_accounts_codes ON acc_accounts (code, id_chart);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_accounts_type ON acc_accounts (type);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_accounts_position ON acc_accounts (position);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS acc_years
|
||||||
|
-- Exercices
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
|
||||||
|
start_date TEXT NOT NULL CHECK (date(start_date) IS NOT NULL AND date(start_date) = start_date),
|
||||||
|
end_date TEXT NOT NULL CHECK (date(end_date) IS NOT NULL AND date(end_date) = end_date),
|
||||||
|
|
||||||
|
closed INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
id_chart INTEGER NOT NULL REFERENCES acc_charts (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TRIGGER IF NOT EXISTS acc_years_delete BEFORE DELETE ON acc_years BEGIN
|
||||||
|
UPDATE services_fees SET id_account = NULL, id_year = NULL WHERE id_year = OLD.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_years_closed ON acc_years (closed);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS acc_transactions
|
||||||
|
-- Opérations comptables
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
type INTEGER NOT NULL DEFAULT 0, -- Type d'écriture, 0 = avancée (normale)
|
||||||
|
status INTEGER NOT NULL DEFAULT 0, -- Statut (bitmask)
|
||||||
|
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
notes TEXT NULL,
|
||||||
|
reference TEXT NULL, -- N° de pièce comptable
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date),
|
||||||
|
|
||||||
|
validated INTEGER NOT NULL DEFAULT 0, -- 1 = écriture validée, non modifiable
|
||||||
|
|
||||||
|
hash TEXT NULL,
|
||||||
|
prev_hash TEXT NULL,
|
||||||
|
|
||||||
|
id_year INTEGER NOT NULL REFERENCES acc_years(id),
|
||||||
|
id_creator INTEGER NULL REFERENCES membres(id) ON DELETE SET NULL,
|
||||||
|
id_related INTEGER NULL REFERENCES acc_transactions(id) ON DELETE SET NULL -- écriture liée (par ex. remboursement d'une dette)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_year ON acc_transactions (id_year);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_date ON acc_transactions (date);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_related ON acc_transactions (id_related);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_type ON acc_transactions (type, id_year);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_status ON acc_transactions (status);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS acc_transactions_lines
|
||||||
|
-- Lignes d'écritures d'une opération
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
id_transaction INTEGER NOT NULL REFERENCES acc_transactions (id) ON DELETE CASCADE,
|
||||||
|
id_account INTEGER NOT NULL REFERENCES acc_accounts (id), -- N° du compte dans le plan comptable
|
||||||
|
|
||||||
|
credit INTEGER NOT NULL,
|
||||||
|
debit INTEGER NOT NULL,
|
||||||
|
|
||||||
|
reference TEXT NULL, -- Référence de paiement, eg. numéro de chèque
|
||||||
|
label TEXT NULL,
|
||||||
|
|
||||||
|
reconciled INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
id_analytical INTEGER NULL REFERENCES acc_accounts(id) ON DELETE SET NULL,
|
||||||
|
|
||||||
|
CONSTRAINT line_check1 CHECK ((credit * debit) = 0),
|
||||||
|
CONSTRAINT line_check2 CHECK ((credit + debit) > 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_lines_transaction ON acc_transactions_lines (id_transaction);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_lines_account ON acc_transactions_lines (id_account);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_lines_analytical ON acc_transactions_lines (id_analytical);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_lines_reconciled ON acc_transactions_lines (reconciled);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS acc_transactions_users
|
||||||
|
-- Liaison des écritures et des membres
|
||||||
|
(
|
||||||
|
id_user INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_transaction INTEGER NOT NULL REFERENCES acc_transactions (id) ON DELETE CASCADE,
|
||||||
|
id_service_user INTEGER NULL REFERENCES services_users (id) ON DELETE SET NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (id_user, id_transaction)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_users_service ON acc_transactions_users (id_service_user);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS plugins
|
||||||
|
(
|
||||||
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
|
officiel INTEGER NOT NULL DEFAULT 0,
|
||||||
|
nom TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
auteur TEXT NULL,
|
||||||
|
url TEXT NULL,
|
||||||
|
version TEXT NOT NULL,
|
||||||
|
menu INTEGER NOT NULL DEFAULT 0,
|
||||||
|
menu_condition TEXT NULL,
|
||||||
|
config TEXT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS plugins_signaux
|
||||||
|
-- Association entre plugins et signaux (hooks)
|
||||||
|
(
|
||||||
|
signal TEXT NOT NULL,
|
||||||
|
plugin TEXT NOT NULL REFERENCES plugins (id),
|
||||||
|
callback TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (signal, plugin)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers
|
||||||
|
-- Données sur les fichiers
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
nom TEXT NOT NULL, -- nom de fichier (par exemple image1234.jpeg)
|
||||||
|
type TEXT NULL, -- Type MIME
|
||||||
|
image INTEGER NOT NULL DEFAULT 0, -- 1 = image reconnue
|
||||||
|
datetime TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(datetime) IS NOT NULL AND datetime(datetime) = datetime), -- Date d'ajout ou mise à jour du fichier
|
||||||
|
id_contenu INTEGER NOT NULL REFERENCES fichiers_contenu (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS fichiers_date ON fichiers (datetime);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_contenu
|
||||||
|
-- Contenu des fichiers
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
hash TEXT NOT NULL, -- Hash SHA1 du contenu du fichier
|
||||||
|
taille INTEGER NOT NULL, -- Taille en octets
|
||||||
|
contenu BLOB NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS fichiers_hash ON fichiers_contenu (hash);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_membres
|
||||||
|
-- Associations entre fichiers et membres (photo de profil par exemple)
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id) ON DELETE CASCADE,
|
||||||
|
id INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_wiki_pages
|
||||||
|
-- Associations entre fichiers et pages du wiki
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id) ON DELETE CASCADE,
|
||||||
|
id INTEGER NOT NULL REFERENCES wiki_pages (id) ON DELETE CASCADE,
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS fichiers_acc_transactions
|
||||||
|
-- Associations entre fichiers et journal de compta (pièce comptable par exemple)
|
||||||
|
(
|
||||||
|
fichier INTEGER NOT NULL REFERENCES fichiers (id) ON DELETE CASCADE,
|
||||||
|
id INTEGER NOT NULL REFERENCES acc_transactions (id) ON DELETE CASCADE,
|
||||||
|
PRIMARY KEY(fichier, id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS recherches
|
||||||
|
-- Recherches enregistrées
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_membre INTEGER NULL REFERENCES membres (id) ON DELETE CASCADE, -- Si non NULL, alors la recherche ne sera visible que par le membre associé
|
||||||
|
intitule TEXT NOT NULL,
|
||||||
|
creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(creation) IS NOT NULL AND datetime(creation) = creation),
|
||||||
|
cible TEXT NOT NULL, -- "membres" ou "compta"
|
||||||
|
type TEXT NOT NULL, -- "json" ou "sql"
|
||||||
|
contenu TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compromised_passwords_cache
|
||||||
|
-- Cache des hash de mots de passe compromis
|
||||||
|
(
|
||||||
|
hash TEXT NOT NULL PRIMARY KEY
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compromised_passwords_cache_ranges
|
||||||
|
-- Cache des préfixes de mots de passe compromis
|
||||||
|
(
|
||||||
|
prefix TEXT NOT NULL PRIMARY KEY,
|
||||||
|
date INTEGER NOT NULL
|
||||||
|
);
|
1760
archives/plan_comptable.json
Normal file
1760
archives/plan_comptable.json
Normal file
File diff suppressed because it is too large
Load diff
141
build/debian/config.debian.php
Normal file
141
build/debian/config.debian.php
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Paheko;
|
||||||
|
|
||||||
|
const SQLITE_JOURNAL_MODE = 'WAL';
|
||||||
|
const ENABLE_UPGRADES = false;
|
||||||
|
|
||||||
|
if (shell_exec('which pdftotext')) {
|
||||||
|
define('Paheko\PDFTOTEXT_COMMAND', 'pdftotext');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shell_exec('which ssconvert')) {
|
||||||
|
define('Paheko\CALC_CONVERT_COMMAND', 'ssconvert');
|
||||||
|
}
|
||||||
|
elseif (shell_exec('which unoconv')) {
|
||||||
|
define('Paheko\CALC_CONVERT_COMMAND', 'unoconv');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($_ENV['PAHEKO_STANDALONE']))
|
||||||
|
{
|
||||||
|
$home = $_ENV['HOME'];
|
||||||
|
|
||||||
|
// Config directory
|
||||||
|
if (empty($_ENV['XDG_CONFIG_HOME']))
|
||||||
|
{
|
||||||
|
$_ENV['XDG_CONFIG_HOME'] = $home . '/.config';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rename Garradin to Paheko
|
||||||
|
if (file_exists($_ENV['XDG_CONFIG_HOME'] . '/garradin')) {
|
||||||
|
rename($_ENV['XDG_CONFIG_HOME'] . '/garradin', $_ENV['XDG_CONFIG_HOME'] . '/paheko');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_exists($_ENV['XDG_CONFIG_HOME'] . '/paheko'))
|
||||||
|
{
|
||||||
|
mkdir($_ENV['XDG_CONFIG_HOME'] . '/paheko', 0700, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists($_ENV['XDG_CONFIG_HOME'] . '/paheko/config.local.php')) {
|
||||||
|
require_once $_ENV['XDG_CONFIG_HOME'] . '/paheko/config.local.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data directory: where the data will go
|
||||||
|
if (empty($_ENV['XDG_DATA_HOME']))
|
||||||
|
{
|
||||||
|
$_ENV['XDG_DATA_HOME'] = $home . '/.local/share';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists($_ENV['XDG_DATA_HOME'] . '/garradin')) {
|
||||||
|
rename($_ENV['XDG_DATA_HOME'] . '/garradin', $_ENV['XDG_DATA_HOME'] . '/paheko');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_exists($_ENV['XDG_DATA_HOME'] . '/paheko')) {
|
||||||
|
mkdir($_ENV['XDG_DATA_HOME'] . '/paheko', 0700, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('Paheko\DATA_ROOT')) {
|
||||||
|
define('Paheko\DATA_ROOT', $_ENV['XDG_DATA_HOME'] . '/paheko');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache directory: temporary stuff
|
||||||
|
if (empty($_ENV['XDG_CACHE_HOME']))
|
||||||
|
{
|
||||||
|
$_ENV['XDG_CACHE_HOME'] = $home . '/.cache';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists($_ENV['XDG_CACHE_HOME'] . '/garradin')) {
|
||||||
|
rename($_ENV['XDG_CACHE_HOME'] . '/garradin', $_ENV['XDG_CACHE_HOME'] . '/paheko');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_exists($_ENV['XDG_CACHE_HOME'] . '/paheko'))
|
||||||
|
{
|
||||||
|
mkdir($_ENV['XDG_CACHE_HOME'] . '/paheko', 0700, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('Paheko\CACHE_ROOT')) {
|
||||||
|
define('Paheko\CACHE_ROOT', $_ENV['XDG_CACHE_HOME'] . '/paheko');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('Paheko\DB_FILE')) {
|
||||||
|
$last_file = $_ENV['XDG_CONFIG_HOME'] . '/paheko/last';
|
||||||
|
|
||||||
|
if ($_ENV['PAHEKO_STANDALONE'] != 1)
|
||||||
|
{
|
||||||
|
$last_sqlite = trim($_ENV['PAHEKO_STANDALONE']);
|
||||||
|
}
|
||||||
|
else if (file_exists($last_file))
|
||||||
|
{
|
||||||
|
$last_sqlite = trim(file_get_contents($last_file));
|
||||||
|
$last_sqlite = str_replace('.local/share/garradin', '.local/share/paheko', $last_sqlite);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$last_sqlite = $_ENV['XDG_DATA_HOME'] . '/paheko/association.sqlite';
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents($last_file, $last_sqlite);
|
||||||
|
|
||||||
|
define('Paheko\DB_FILE', $last_sqlite);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('Paheko\LOCAL_LOGIN')) {
|
||||||
|
define('Paheko\LOCAL_LOGIN', -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (file_exists('/etc/paheko/config.php')) {
|
||||||
|
require_once '/etc/paheko/config.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('Paheko\DATA_ROOT')) {
|
||||||
|
define('Paheko\DATA_ROOT', '/var/lib/paheko');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('Paheko\CACHE_ROOT')) {
|
||||||
|
define('Paheko\CACHE_ROOT', '/var/cache/paheko');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists(DATA_ROOT . '/plugins')) {
|
||||||
|
define('Paheko\PLUGINS_ROOT', DATA_ROOT . '/plugins');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
define('Paheko\PLUGINS_ROOT', __DIR__ . '/plugins');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('Paheko\SECRET_KEY')) {
|
||||||
|
if (file_exists(CACHE_ROOT . '/key')) {
|
||||||
|
define('Paheko\SECRET_KEY', trim(file_get_contents(CACHE_ROOT . '/key')));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
define('Paheko\SECRET_KEY', base64_encode(random_bytes(64)));
|
||||||
|
file_put_contents(CACHE_ROOT . '/key', SECRET_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable PDF for CLI server
|
||||||
|
if (PHP_SAPI == 'cli-server' && !defined('Paheko\PDF_COMMAND') && !file_exists(PLUGINS_ROOT . '/dompdf')) {
|
||||||
|
define('Paheko\PDF_COMMAND', null);
|
||||||
|
}
|
||||||
|
|
174
build/debian/makedeb.sh
Executable file
174
build/debian/makedeb.sh
Executable file
|
@ -0,0 +1,174 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Ripped from fossil makdedeb.sh
|
||||||
|
|
||||||
|
DEB_REV=${1-1} # .deb package build/revision number.
|
||||||
|
PACKAGE_DEBNAME=paheko
|
||||||
|
THISDIR=${PWD}
|
||||||
|
|
||||||
|
DEB_ARCH_NAME=all
|
||||||
|
|
||||||
|
PACKAGE_VERSION=`cat ../../src/VERSION`
|
||||||
|
|
||||||
|
[ ! -f ../paheko-${PACKAGE_VERSION}.tar.gz ] && (cd ../../src; make release)
|
||||||
|
|
||||||
|
tar xzvf ../paheko-${PACKAGE_VERSION}.tar.gz -C /tmp
|
||||||
|
|
||||||
|
SRCDIR="/tmp/paheko-${PACKAGE_VERSION}"
|
||||||
|
|
||||||
|
test -e ${SRCDIR} || {
|
||||||
|
echo "This script must be run from a BUILT copy of the source tree."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBROOT=$PWD/deb.tmp
|
||||||
|
test -d ${DEBROOT} && rm -fr ${DEBROOT}
|
||||||
|
|
||||||
|
DEBLOCALPREFIX=${DEBROOT}/usr
|
||||||
|
BINDIR=${DEBLOCALPREFIX}/bin
|
||||||
|
mkdir -p ${BINDIR}
|
||||||
|
mkdir -p ${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME}
|
||||||
|
cp ${THISDIR}/paheko ${BINDIR}
|
||||||
|
|
||||||
|
mkdir -p "${DEBLOCALPREFIX}/share/menu"
|
||||||
|
cp ${THISDIR}/paheko.menu "${DEBLOCALPREFIX}/share/menu/paheko"
|
||||||
|
mkdir -p "${DEBLOCALPREFIX}/share/applications"
|
||||||
|
cp ${THISDIR}/paheko.desktop "${DEBLOCALPREFIX}/share/applications/"
|
||||||
|
|
||||||
|
CODEDIR=${DEBLOCALPREFIX}/share/${PACKAGE_DEBNAME}
|
||||||
|
mkdir -p ${CODEDIR}
|
||||||
|
cp -r ${SRCDIR}/* ${CODEDIR}
|
||||||
|
cp ${THISDIR}/config.debian.php ${CODEDIR}/config.local.php
|
||||||
|
mv ${CODEDIR}/data/plugins ${CODEDIR}/plugins
|
||||||
|
rm -rf ${CODEDIR}/*.sqlite ${CODEDIR}/data
|
||||||
|
cp ${THISDIR}/paheko.png "${CODEDIR}"
|
||||||
|
|
||||||
|
mkdir -p "${DEBROOT}/var/lib/${PACKAGE_DEBNAME}"
|
||||||
|
mkdir -p "${DEBROOT}/var/cache/${PACKAGE_DEBNAME}"
|
||||||
|
mkdir -p "${DEBROOT}/etc/${PACKAGE_DEBNAME}"
|
||||||
|
|
||||||
|
# Cleaning files that will be copied to /usr/share/doc
|
||||||
|
#rm -f ${CODEDIR}/../{README.md,COPYING}
|
||||||
|
|
||||||
|
cd $DEBROOT || {
|
||||||
|
echo "Debian dest dir [$DEBROOT] not found. :("
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
rm -fr DEBIAN
|
||||||
|
mkdir DEBIAN
|
||||||
|
|
||||||
|
PACKAGE_DEB_VERSION=${PACKAGE_VERSION}
|
||||||
|
DEBFILE=${THISDIR}/${PACKAGE_DEBNAME}-${PACKAGE_DEB_VERSION}.deb
|
||||||
|
PACKAGE_TIME=$(/bin/date)
|
||||||
|
|
||||||
|
rm -f ${DEBFILE}
|
||||||
|
echo "Creating .deb package [${DEBFILE}]..."
|
||||||
|
|
||||||
|
echo "Generating md5 sums..."
|
||||||
|
find ${DEBLOCALPREFIX} -type f -exec md5sum {} \; > DEBIAN/md5sums
|
||||||
|
|
||||||
|
true && {
|
||||||
|
echo "Generating Debian-specific files..."
|
||||||
|
cp ${THISDIR}/../../COPYING ${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME}/copyright
|
||||||
|
} || {
|
||||||
|
echo "Fail."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
true && {
|
||||||
|
cat <<EOF > DEBIAN/postinst
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
chown www-data:www-data /var/lib/paheko /var/cache/paheko
|
||||||
|
chown root:www-data /etc/paheko
|
||||||
|
chmod g=rX,o= /etc/paheko
|
||||||
|
chmod ug=rwX,o= /var/lib/paheko /var/cache/paheko
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x DEBIAN/postinst
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
true && {
|
||||||
|
CHANGELOG=${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME}/changelog.gz
|
||||||
|
cat <<EOF | gzip -c > ${CHANGELOG}
|
||||||
|
${PACKAGE_DEBNAME} ${PACKAGE_DEB_VERSION}; urgency=low
|
||||||
|
|
||||||
|
This release has no changes over the core source distribution. It has
|
||||||
|
simply been Debianized.
|
||||||
|
|
||||||
|
Packaged by ${USER} <http://dev.kd2.org/paheko/> on
|
||||||
|
${PACKAGE_TIME}.
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# doc.
|
||||||
|
DOCDIR=${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME}
|
||||||
|
|
||||||
|
true && {
|
||||||
|
echo "Generating doc..."
|
||||||
|
cp ${THISDIR}/../../README.md ${DOCDIR}
|
||||||
|
a2x --doctype manpage --format manpage ${THISDIR}/manpage.txt
|
||||||
|
mkdir -p ${DEBLOCALPREFIX}/share/man/man1
|
||||||
|
gzip -c ${THISDIR}/paheko.1 > ${DEBLOCALPREFIX}/share/man/man1/${PACKAGE_DEBNAME}.1.gz
|
||||||
|
rm -f ${THISDIR}/paheko.1
|
||||||
|
} || {
|
||||||
|
echo "Fail."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
true && {
|
||||||
|
CONTROL=DEBIAN/control
|
||||||
|
echo "Generating ${CONTROL}..."
|
||||||
|
cat <<EOF > ${CONTROL}
|
||||||
|
Package: ${PACKAGE_DEBNAME}
|
||||||
|
Section: web
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: Paheko <paheko@paheko.eu>
|
||||||
|
Architecture: ${DEB_ARCH_NAME}
|
||||||
|
Depends: dash | bash, php-cli (>=7.4), php-sqlite3, php-intl, php-mbstring, sensible-utils
|
||||||
|
Version: ${PACKAGE_DEB_VERSION}
|
||||||
|
Suggests: php-imagick
|
||||||
|
Replaces: garradin (<< 1.2.3~)
|
||||||
|
Breaks: garradin (<< 1.2.3~)
|
||||||
|
Homepage: https://fossil.kd2.org/paheko/
|
||||||
|
Description: Paheko is a tool to manage non-profit organizations.
|
||||||
|
It's only available in french.
|
||||||
|
Description-fr: Gestionnaire d'association en interface web ou CLI.
|
||||||
|
Paheko est un gestionnaire d'association à but non lucratif.
|
||||||
|
Il permet de gérer les membres, leur adhésion et leurs contributions financières.
|
||||||
|
Les membres peuvent se connecter eux-même et modifier leurs informations
|
||||||
|
ou communiquer entre eux par e-mail. Une gestion précise des droits et
|
||||||
|
autorisations est possible. Il est également possible de faire des
|
||||||
|
envois de mails en groupe.
|
||||||
|
.
|
||||||
|
Un module de comptabilité à double entrée assure une gestion financière
|
||||||
|
complète digne d'un vrai logiciel de comptabilité : suivi des opérations,
|
||||||
|
graphiques, bilan annuel, compte de résultat, exercices, etc.
|
||||||
|
.
|
||||||
|
Il y a également la possibilité de publier un site web simple,
|
||||||
|
et un gestionnaire de documents permettant de gérer les fichiers de
|
||||||
|
l'association.
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
true && {
|
||||||
|
fakeroot dpkg-deb -b ${DEBROOT} ${DEBFILE}
|
||||||
|
echo "Package file created:"
|
||||||
|
ls -la ${DEBFILE}
|
||||||
|
dpkg-deb --info ${DEBFILE}
|
||||||
|
}
|
||||||
|
|
||||||
|
cd - >/dev/null
|
||||||
|
true && {
|
||||||
|
echo "Cleaning up..."
|
||||||
|
rm -fr ${DEBROOT}
|
||||||
|
rm -rf ${SRCDIR}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done :)"
|
106
build/debian/manpage.txt
Normal file
106
build/debian/manpage.txt
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
PAHEKO(1)
|
||||||
|
=========
|
||||||
|
:doctype: manpage
|
||||||
|
|
||||||
|
|
||||||
|
NAME
|
||||||
|
----
|
||||||
|
paheko - Gestionnaire d'association à but non lucratif
|
||||||
|
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
--------
|
||||||
|
*paheko* ['OPTIONS'] ['COMMANDE'] ['BASE']
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
-----------
|
||||||
|
Lancer paheko(1) sans argument lance le serveur web intégré sur
|
||||||
|
l'adresse localhost:8081 et le navigateur web par défaut.
|
||||||
|
|
||||||
|
*BASE* défini le chemin de la base de données (fichier .sqlite) à
|
||||||
|
utiliser. Par défaut, si aucune base n'est spécifiée, c'est le fichier
|
||||||
|
'association.sqlite' situé dans le répertoire des données qui est
|
||||||
|
utilisé.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
-------
|
||||||
|
*-p, --port*='PORT'::
|
||||||
|
Défini le port utilisé par le serveur web.
|
||||||
|
Par défaut c'est le port 8081 qui est utilisé.
|
||||||
|
|
||||||
|
*-b, --bind*='IP'::
|
||||||
|
Adresse IP où sera exposé le serveur web.
|
||||||
|
Par défaut c'est 127.0.0.1 qui est utilisé.
|
||||||
|
|
||||||
|
Utiliser 0.0.0.0 pour que le serveur web soit accessible d'autres
|
||||||
|
machines. (Attention cela peut présenter un risque de sécurité.)
|
||||||
|
|
||||||
|
*-v, --verbose*::
|
||||||
|
Affiche les messages du serveur web.
|
||||||
|
|
||||||
|
*-h, --help*::
|
||||||
|
Affiche un message d'aide sur l'utilisation de la commande.
|
||||||
|
|
||||||
|
COMMANDES
|
||||||
|
---------
|
||||||
|
*server*::
|
||||||
|
Lance le serveur web autonome de Paheko sans lancer de navigateur
|
||||||
|
web.
|
||||||
|
|
||||||
|
*ui*::
|
||||||
|
Lance le serveur web autonome et le navigateur par défaut.
|
||||||
|
|
||||||
|
EXIT STATUS
|
||||||
|
-----------
|
||||||
|
*0*::
|
||||||
|
Succès
|
||||||
|
|
||||||
|
*1*::
|
||||||
|
Erreur
|
||||||
|
|
||||||
|
EMPLACEMENTS DE STOCKAGE
|
||||||
|
------------------------
|
||||||
|
Les données sont stockées dans $XDG_DATA_HOME/paheko.
|
||||||
|
Généralement c'est ~/.local/share/paheko
|
||||||
|
|
||||||
|
CONFIGURATION
|
||||||
|
-------------
|
||||||
|
Il est possible de créer un fichier de configuration dans
|
||||||
|
$XDG_CONFIG_HOME/paheko/config.local.php
|
||||||
|
|
||||||
|
Voir la documentation pour plus de détails sur les constantes
|
||||||
|
de configuration acceptées.
|
||||||
|
|
||||||
|
INSTALLATION SERVEUR WEB
|
||||||
|
------------------------
|
||||||
|
Il est possible d'utiliser ce package avec Apache pour héberger
|
||||||
|
une instance Paheko.
|
||||||
|
|
||||||
|
La procédure est détaillée ici :
|
||||||
|
https://fossil.kd2.org/paheko/wiki?name=Installation%20sous%20Debian-Ubuntu
|
||||||
|
|
||||||
|
Les données et plugins seront stockés dans le répertoire
|
||||||
|
/var/lib/paheko
|
||||||
|
|
||||||
|
BUGS
|
||||||
|
----
|
||||||
|
Voir https://fossil.kd2.org/paheko/ pour un accès au bugtracker.
|
||||||
|
|
||||||
|
|
||||||
|
AUTEUR
|
||||||
|
------
|
||||||
|
Paheko est développé par bohwaz et d'autres contributeurs.
|
||||||
|
|
||||||
|
|
||||||
|
RESSOURCES
|
||||||
|
----------
|
||||||
|
|
||||||
|
Site principal : <https://fossil.kd2.org/paheko/>
|
||||||
|
|
||||||
|
|
||||||
|
COPYING
|
||||||
|
-------
|
||||||
|
Copyright \(C) 2011-2023 BohwaZ. Free use of this software is
|
||||||
|
granted under the terms of the GNU Affero General Public License v3
|
||||||
|
(AGPL).
|
123
build/debian/paheko
Executable file
123
build/debian/paheko
Executable file
|
@ -0,0 +1,123 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
ROOT=/usr/share/paheko/www
|
||||||
|
#ROOT=~/fossil/paheko/src/www
|
||||||
|
ROUTER=${ROOT}/_route.php
|
||||||
|
PORT=8081
|
||||||
|
ADDRESS="127.0.0.1"
|
||||||
|
VERBOSE=0
|
||||||
|
PID_FILE="${XDG_RUNTIME_DIR}/paheko/pid"
|
||||||
|
|
||||||
|
[ ! -d `dirname $PID_FILE` ] && mkdir -p `dirname $PID_FILE`
|
||||||
|
|
||||||
|
# Execute getopt
|
||||||
|
ARGS=`getopt -o "pb:vh" -l "port:,bind:,verbose,help" -n "paheko" -- "$@"`
|
||||||
|
|
||||||
|
# Bad arguments
|
||||||
|
if [ $? -ne 0 ];
|
||||||
|
then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# A little magic
|
||||||
|
eval set -- "$ARGS"
|
||||||
|
|
||||||
|
# Now go through all the options
|
||||||
|
while true;
|
||||||
|
do
|
||||||
|
case "$1" in
|
||||||
|
-p|--port)
|
||||||
|
PORT=$2
|
||||||
|
shift;;
|
||||||
|
|
||||||
|
-b|--bind)
|
||||||
|
ADDRESS=$2
|
||||||
|
shift;;
|
||||||
|
|
||||||
|
-v|--verbose)
|
||||||
|
VERBOSE=1
|
||||||
|
shift;;
|
||||||
|
|
||||||
|
-h|--help)
|
||||||
|
cat <<EOF
|
||||||
|
Usage : $0 [COMMANDE] [PROJET]
|
||||||
|
|
||||||
|
Où COMMANDE peut être :
|
||||||
|
|
||||||
|
server [-p|--port PORT] [-b|--bind IP]
|
||||||
|
Démarre un serveur web Paheko sur le port spécifié
|
||||||
|
(8081 par défaut) et l'IP spécifiée (127.0.0.1 par défaut)
|
||||||
|
|
||||||
|
ui [-p|--port PORT] [-b|--bind IP]
|
||||||
|
Idem que 'server' mais démarre ensuite le navigateur web par défaut
|
||||||
|
et connecte automatiquement avec le premier administrateur
|
||||||
|
de l'association.
|
||||||
|
|
||||||
|
Si aucune COMMANDE n'est donnée, Paheko utilisera 'ui' par défaut.
|
||||||
|
|
||||||
|
PROJET est le chemin menant à un projet Paheko précis
|
||||||
|
(fichier .sqlite). Si aucun projet n'est indiqué, le
|
||||||
|
dernier projet ouvert sera rouvert. Si aucun projet n'a jamais été
|
||||||
|
ouvert un nouveau projet sera créé.
|
||||||
|
|
||||||
|
Options :
|
||||||
|
|
||||||
|
-p|--port PORT
|
||||||
|
Spécifie le port pour le mode ui ou le mode serveur.
|
||||||
|
|
||||||
|
-b|--bind IP
|
||||||
|
Spécifie l'adresse IP du serveur web.
|
||||||
|
|
||||||
|
-v|--verbose
|
||||||
|
Affiche les requêtes reçues sur le serveur web.
|
||||||
|
|
||||||
|
-h|--help
|
||||||
|
Affiche ce message.
|
||||||
|
EOF
|
||||||
|
exit
|
||||||
|
shift;;
|
||||||
|
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
break;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
CMD="$1"
|
||||||
|
|
||||||
|
[ "$CMD" = "" ] && {
|
||||||
|
CMD="ui"
|
||||||
|
}
|
||||||
|
|
||||||
|
PROJECT="$2"
|
||||||
|
|
||||||
|
[ "$PROJECT" = "" ] && PROJECT="1"
|
||||||
|
|
||||||
|
export PAHEKO_STANDALONE="$PROJECT"
|
||||||
|
|
||||||
|
[ -f $PID_FILE ] && kill `cat $PID_FILE` > /dev/null 2>&1 && rm -f $PID_FILE
|
||||||
|
|
||||||
|
PHP_CLI_SERVER_WORKER=2
|
||||||
|
|
||||||
|
[ $VERBOSE = 1 ] && {
|
||||||
|
php -S ${ADDRESS}:${PORT} -t ${ROOT} -d variables_order=EGPCS ${ROUTER} &
|
||||||
|
} || {
|
||||||
|
php -S ${ADDRESS}:${PORT} -t ${ROOT} -d variables_order=EGPCS ${ROUTER} > /dev/null 2>&1 &
|
||||||
|
}
|
||||||
|
|
||||||
|
php_pid=$!
|
||||||
|
|
||||||
|
echo $php_pid > $PID_FILE
|
||||||
|
|
||||||
|
sleep .5
|
||||||
|
|
||||||
|
[ "$CMD" = "ui" ] && {
|
||||||
|
URL="http://${ADDRESS}:${PORT}/admin/"
|
||||||
|
[ "$DISPLAY" != "" ] && {
|
||||||
|
sensible-browser ${URL} &
|
||||||
|
} || {
|
||||||
|
www-browser ${URL} &
|
||||||
|
}
|
||||||
|
} || {
|
||||||
|
wait $php_pid
|
||||||
|
}
|
6
build/debian/paheko.desktop
Normal file
6
build/debian/paheko.desktop
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=Paheko
|
||||||
|
Exec=paheko
|
||||||
|
Icon=paheko
|
||||||
|
Type=Application
|
||||||
|
Categories=Office;Finance;Database
|
3
build/debian/paheko.menu
Normal file
3
build/debian/paheko.menu
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
?package(paheko):needs="X11" section="Applications/Office"\
|
||||||
|
title="Paheko" command="/usr/bin/paheko"\
|
||||||
|
icon="/usr/share/paheko/paheko.png"
|
BIN
build/debian/paheko.png
Normal file
BIN
build/debian/paheko.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
81
build/windows/Makefile
Normal file
81
build/windows/Makefile
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
.PHONY := php installer clean publish
|
||||||
|
PHP_ARCHIVE := https://windows.php.net/downloads/releases/php-8.2.10-nts-Win32-vs16-x64.zip
|
||||||
|
|
||||||
|
all: installer
|
||||||
|
|
||||||
|
php.zip:
|
||||||
|
wget ${PHP_ARCHIVE} -O php.zip
|
||||||
|
|
||||||
|
php: php.zip
|
||||||
|
mkdir -p install_dir/php
|
||||||
|
unzip -o php.zip -d install_dir/php > /dev/null
|
||||||
|
|
||||||
|
# Remove unused files
|
||||||
|
@cd install_dir/php && rm -rf \
|
||||||
|
phpdbg.exe \
|
||||||
|
php8phpdbg.dll \
|
||||||
|
php8embed.lib \
|
||||||
|
php-cgi.exe \
|
||||||
|
php.ini-* \
|
||||||
|
dev \
|
||||||
|
phar* \
|
||||||
|
nghttp2.dll \
|
||||||
|
libpq.dll \
|
||||||
|
libenchant
|
||||||
|
|
||||||
|
# Remove unused extensions
|
||||||
|
@cd install_dir/php/ext && rm -f \
|
||||||
|
php_bz2.dll \
|
||||||
|
php_com_dotnet.dll \
|
||||||
|
php_curl.dll \
|
||||||
|
php_dba.dll \
|
||||||
|
php_dl_test.dll \
|
||||||
|
php_enchant.dll \
|
||||||
|
php_exif.dll \
|
||||||
|
php_ffi.dll \
|
||||||
|
php_ftp.dll \
|
||||||
|
php_gmp.dll \
|
||||||
|
php_imap.dll \
|
||||||
|
php_ldap.dll \
|
||||||
|
php_mysqli.dll \
|
||||||
|
php_oci8_19.dll \
|
||||||
|
php_odbc.dll \
|
||||||
|
php_opcache.dll \
|
||||||
|
php_pdo_firebird.dll \
|
||||||
|
php_pdo_mysql.dll \
|
||||||
|
php_pdo_oci.dll \
|
||||||
|
php_pdo_odbc.dll \
|
||||||
|
php_pdo_pgsql.dll \
|
||||||
|
php_pdo_sqlite.dll \
|
||||||
|
php_pgsql.dll \
|
||||||
|
php_shmop.dll \
|
||||||
|
php_snmp.dll \
|
||||||
|
php_soap.dll \
|
||||||
|
php_sysvshm.dll \
|
||||||
|
php_xsl.dll \
|
||||||
|
php_zend_test.dll
|
||||||
|
|
||||||
|
du -hs install_dir/php
|
||||||
|
|
||||||
|
installer: clean php
|
||||||
|
$(eval VERSION=$(shell cat ../../src/VERSION))
|
||||||
|
# NSIS only accepts numbers as version
|
||||||
|
$(eval NSIS_VERSION=$(shell sed -E 's/-(alpha|beta|rc)[0-9]+//' ../../src/VERSION))
|
||||||
|
mkdir -p install_dir
|
||||||
|
cp ../paheko-${VERSION}.tar.gz install_dir/
|
||||||
|
cd install_dir && tar xzf paheko-${VERSION}.tar.gz && mv paheko-${VERSION} paheko
|
||||||
|
cp config.local.php install_dir/paheko/
|
||||||
|
cp php.ini install_dir/php
|
||||||
|
cp launch.bat install_dir
|
||||||
|
cp paheko.ico install_dir
|
||||||
|
rm -f install_dir/paheko-${VERSION}.tar.gz
|
||||||
|
makensis -V3 -DNVERSION=${NSIS_VERSION} -DVERSION=${VERSION} paheko.nsis
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf install_dir
|
||||||
|
|
||||||
|
publish:
|
||||||
|
$(eval VERSION=$(shell cat ../../src/VERSION))
|
||||||
|
fossil uv ls | grep '^paheko-.*\.exe' | xargs fossil uv rm
|
||||||
|
fossil uv add paheko-${VERSION}.exe
|
||||||
|
fossil uv sync
|
5
build/windows/README.md
Normal file
5
build/windows/README.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Paheko Windows build
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
NSIS: `apt install nsis`
|
34
build/windows/config.local.php
Normal file
34
build/windows/config.local.php
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Paheko;
|
||||||
|
|
||||||
|
if (!empty(getenv('LOCALAPPDATA'))) {
|
||||||
|
// Store data in user AppData directory
|
||||||
|
define('Paheko\DATA_ROOT', trim(getenv('LOCALAPPDATA'), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'Paheko');
|
||||||
|
|
||||||
|
if (!file_exists(DATA_ROOT)) {
|
||||||
|
@mkdir(DATA_ROOT, 0700, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
define('Paheko\PLUGINS_ROOT', __DIR__ . '/data/plugins');
|
||||||
|
|
||||||
|
// Store secret key in user directory
|
||||||
|
if (!defined('Paheko\SECRET_KEY')) {
|
||||||
|
if (file_exists(DATA_ROOT . '/key')) {
|
||||||
|
define('Paheko\SECRET_KEY', trim(file_get_contents(DATA_ROOT . '/key')));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
define('Paheko\SECRET_KEY', base64_encode(random_bytes(16)));
|
||||||
|
file_put_contents(DATA_ROOT . '/key', SECRET_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always log in as admin user
|
||||||
|
const LOCAL_LOGIN = -1;
|
||||||
|
|
||||||
|
// Disable PDF export
|
||||||
|
const PDF_COMMAND = null;
|
||||||
|
|
||||||
|
// Disable e-mails as Windows is not able to send e-mails
|
||||||
|
const DISABLE_EMAIL = true;
|
15
build/windows/launch.bat
Normal file
15
build/windows/launch.bat
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
@start "" http://127.0.0.1:8082/
|
||||||
|
|
||||||
|
@echo =================================================
|
||||||
|
@echo.
|
||||||
|
@echo Demarrage du serveur PHP de Paheko.
|
||||||
|
@echo.
|
||||||
|
@echo Paheko est disponible a l'adresse suivante :
|
||||||
|
@echo http://127.0.0.1:8082/
|
||||||
|
@echo.
|
||||||
|
@echo Fermer cette fenetre pour arreter le serveur.
|
||||||
|
@echo.
|
||||||
|
@echo =================================================
|
||||||
|
@echo.
|
||||||
|
|
||||||
|
php\php.exe -S 127.0.0.1:8082 -t paheko/www paheko/www/_route.php 2> NUL
|
BIN
build/windows/paheko.ico
Normal file
BIN
build/windows/paheko.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 122 KiB |
175
build/windows/paheko.nsis
Normal file
175
build/windows/paheko.nsis
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
# From https://www.conjur.org/blog/building-a-windows-installer-from-a-linux-ci-pipeline/
|
||||||
|
!define APP_NAME "Paheko"
|
||||||
|
!define COMP_NAME "Paheko.cloud"
|
||||||
|
#!define WEB_SITE "https://paheko.cloud/"
|
||||||
|
#!define VERSION "0.0.0.1"
|
||||||
|
!define COPYRIGHT "Paheko"
|
||||||
|
!define DESCRIPTION "Gestion d'association simple et efficace"
|
||||||
|
!define INSTALLER_NAME "paheko-${VERSION}.exe"
|
||||||
|
!define MAIN_APP_EXE "launch.bat"
|
||||||
|
!define ICON "paheko.ico"
|
||||||
|
#!define BANNER "[CHANGEME Installer Banner Filename .bmp]"
|
||||||
|
#!define LICENSE_TXT "[CHANGEME License Text Document]"
|
||||||
|
|
||||||
|
!define INSTALL_DIR "$PROGRAMFILES64\${APP_NAME}"
|
||||||
|
!define INSTALL_TYPE "SetShellVarContext all"
|
||||||
|
!define REG_ROOT "HKLM"
|
||||||
|
!define REG_APP_PATH "Software\Microsoft\Windows\CurrentVersion\App Paths\${MAIN_APP_EXE}"
|
||||||
|
!define UNINSTALL_PATH "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}"
|
||||||
|
!define REG_START_MENU "Start Menu Folder"
|
||||||
|
|
||||||
|
var SM_Folder
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
VIProductVersion "${NVERSION}.0"
|
||||||
|
VIAddVersionKey "ProductName" "${APP_NAME}"
|
||||||
|
VIAddVersionKey "CompanyName" "${COMP_NAME}"
|
||||||
|
VIAddVersionKey "LegalCopyright" "${COPYRIGHT}"
|
||||||
|
VIAddVersionKey "FileDescription" "${DESCRIPTION}"
|
||||||
|
VIAddVersionKey "FileVersion" "${VERSION}"
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
SetCompressor /SOLID Lzma
|
||||||
|
Name "${APP_NAME}"
|
||||||
|
Caption "${APP_NAME}"
|
||||||
|
OutFile "${INSTALLER_NAME}"
|
||||||
|
BrandingText "${APP_NAME}"
|
||||||
|
#InstallDirRegKey "${REG_ROOT}" "${REG_APP_PATH}" ""
|
||||||
|
InstallDir "${INSTALL_DIR}"
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
!define MUI_ICON "${ICON}"
|
||||||
|
!define MUI_UNICON "${ICON}"
|
||||||
|
Icon "${ICON}"
|
||||||
|
|
||||||
|
!ifdef BANNER
|
||||||
|
!define MUI_WELCOMEFINISHPAGE_BITMAP "${BANNER}"
|
||||||
|
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "${BANNER}"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
!include "MUI2.nsh"
|
||||||
|
|
||||||
|
!define MUI_ABORTWARNING
|
||||||
|
!define MUI_UNABORTWARNING
|
||||||
|
|
||||||
|
!insertmacro MUI_PAGE_WELCOME
|
||||||
|
|
||||||
|
!ifdef LICENSE_TXT
|
||||||
|
!insertmacro MUI_PAGE_LICENSE "${LICENSE_TXT}"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!insertmacro MUI_PAGE_DIRECTORY
|
||||||
|
|
||||||
|
!ifdef REG_START_MENU
|
||||||
|
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "${APP_NAME}"
|
||||||
|
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "${REG_ROOT}"
|
||||||
|
!define MUI_STARTMENUPAGE_REGISTRY_KEY "${UNINSTALL_PATH}"
|
||||||
|
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${REG_START_MENU}"
|
||||||
|
!insertmacro MUI_PAGE_STARTMENU Application $SM_Folder
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!insertmacro MUI_PAGE_INSTFILES
|
||||||
|
|
||||||
|
!insertmacro MUI_PAGE_FINISH
|
||||||
|
|
||||||
|
!insertmacro MUI_UNPAGE_CONFIRM
|
||||||
|
|
||||||
|
!insertmacro MUI_UNPAGE_INSTFILES
|
||||||
|
|
||||||
|
!insertmacro MUI_UNPAGE_FINISH
|
||||||
|
|
||||||
|
!insertmacro MUI_LANGUAGE "French"
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
Section -MainProgram
|
||||||
|
${INSTALL_TYPE}
|
||||||
|
|
||||||
|
SetOverwrite ifnewer
|
||||||
|
SetOutPath "$INSTDIR"
|
||||||
|
File /r "install_dir\\"
|
||||||
|
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
Section -Icons_Reg
|
||||||
|
SetOutPath "$INSTDIR"
|
||||||
|
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||||
|
|
||||||
|
!ifdef REG_START_MENU
|
||||||
|
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
|
||||||
|
CreateDirectory "$SMPROGRAMS\$SM_Folder"
|
||||||
|
CreateShortCut "$SMPROGRAMS\$SM_Folder\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}" "" "$INSTDIR\paheko.ico"
|
||||||
|
CreateShortCut "$DESKTOP\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}" "" "$INSTDIR\paheko.ico"
|
||||||
|
CreateShortCut "$SMPROGRAMS\$SM_Folder\Desinstaller ${APP_NAME}.lnk" "$INSTDIR\uninstall.exe"
|
||||||
|
|
||||||
|
!ifdef WEB_SITE
|
||||||
|
WriteIniStr "$INSTDIR\${APP_NAME} website.url" "InternetShortcut" "URL" "${WEB_SITE}"
|
||||||
|
CreateShortCut "$SMPROGRAMS\$SM_Folder\${APP_NAME} Website.lnk" "$INSTDIR\${APP_NAME} website.url"
|
||||||
|
!endif
|
||||||
|
!insertmacro MUI_STARTMENU_WRITE_END
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!ifndef REG_START_MENU
|
||||||
|
CreateDirectory "$SMPROGRAMS\${APP_NAME}"
|
||||||
|
CreateShortCut "$SMPROGRAMS\${APP_NAME}\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}" "" "$INSTDIR\paheko.ico"
|
||||||
|
CreateShortCut "$DESKTOP\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}" "" "$INSTDIR\paheko.ico"
|
||||||
|
CreateShortCut "$SMPROGRAMS\${APP_NAME}\Desinstaller ${APP_NAME}.lnk" "$INSTDIR\uninstall.exe"
|
||||||
|
|
||||||
|
!ifdef WEB_SITE
|
||||||
|
WriteIniStr "$INSTDIR\${APP_NAME} website.url" "InternetShortcut" "URL" "${WEB_SITE}"
|
||||||
|
CreateShortCut "$SMPROGRAMS\${APP_NAME}\${APP_NAME} Website.lnk" "$INSTDIR\${APP_NAME} website.url"
|
||||||
|
!endif
|
||||||
|
!endif
|
||||||
|
|
||||||
|
WriteRegStr ${REG_ROOT} "${REG_APP_PATH}" "" "$INSTDIR\${MAIN_APP_EXE}"
|
||||||
|
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayName" "${APP_NAME}"
|
||||||
|
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "UninstallString" "$INSTDIR\uninstall.exe"
|
||||||
|
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayIcon" "$INSTDIR\paheko.ico"
|
||||||
|
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayVersion" "${VERSION}"
|
||||||
|
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "Publisher" "${COMP_NAME}"
|
||||||
|
|
||||||
|
!ifdef WEB_SITE
|
||||||
|
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "URLInfoAbout" "${WEB_SITE}"
|
||||||
|
!endif
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
Section Uninstall
|
||||||
|
${INSTALL_TYPE}
|
||||||
|
|
||||||
|
RmDir /r "$INSTDIR"
|
||||||
|
|
||||||
|
!ifdef REG_START_MENU
|
||||||
|
!insertmacro MUI_STARTMENU_GETFOLDER "Application" $SM_Folder
|
||||||
|
Delete "$SMPROGRAMS\$SM_Folder\${APP_NAME}.lnk"
|
||||||
|
Delete "$SMPROGRAMS\$SM_Folder\Desinstaller ${APP_NAME}.lnk"
|
||||||
|
!ifdef WEB_SITE
|
||||||
|
Delete "$SMPROGRAMS\$SM_Folder\${APP_NAME} Website.lnk"
|
||||||
|
!endif
|
||||||
|
Delete "$DESKTOP\${APP_NAME}.lnk"
|
||||||
|
|
||||||
|
RmDir "$SMPROGRAMS\$SM_Folder"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!ifndef REG_START_MENU
|
||||||
|
Delete "$SMPROGRAMS\${APP_NAME}\${APP_NAME}.lnk"
|
||||||
|
Delete "$SMPROGRAMS\${APP_NAME}\Desinstaller ${APP_NAME}.lnk"
|
||||||
|
!ifdef WEB_SITE
|
||||||
|
Delete "$SMPROGRAMS\${APP_NAME}\${APP_NAME} Website.lnk"
|
||||||
|
!endif
|
||||||
|
Delete "$DESKTOP\${APP_NAME}.lnk"
|
||||||
|
|
||||||
|
RmDir "$SMPROGRAMS\${APP_NAME}"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}"
|
||||||
|
DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}"
|
||||||
|
SectionEnd
|
95
build/windows/php.ini
Normal file
95
build/windows/php.ini
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
[PHP]
|
||||||
|
engine = On
|
||||||
|
short_open_tag = Off
|
||||||
|
precision = 14
|
||||||
|
output_buffering = 4096
|
||||||
|
zlib.output_compression = Off
|
||||||
|
implicit_flush = Off
|
||||||
|
unserialize_callback_func =
|
||||||
|
serialize_precision = -1
|
||||||
|
disable_functions =
|
||||||
|
disable_classes =
|
||||||
|
zend.enable_gc = On
|
||||||
|
zend.exception_ignore_args = Off
|
||||||
|
zend.exception_string_param_max_len = 15
|
||||||
|
expose_php = On
|
||||||
|
max_execution_time = 30
|
||||||
|
max_input_time = 60
|
||||||
|
memory_limit = 128M
|
||||||
|
error_reporting = E_ALL
|
||||||
|
display_errors = On
|
||||||
|
display_startup_errors = On
|
||||||
|
log_errors = On
|
||||||
|
ignore_repeated_errors = Off
|
||||||
|
ignore_repeated_source = Off
|
||||||
|
report_memleaks = On
|
||||||
|
variables_order = "GPCS"
|
||||||
|
request_order = "GP"
|
||||||
|
register_argc_argv = Off
|
||||||
|
auto_globals_jit = On
|
||||||
|
post_max_size = 256M
|
||||||
|
auto_prepend_file =
|
||||||
|
auto_append_file =
|
||||||
|
default_mimetype = "text/html"
|
||||||
|
default_charset = "UTF-8"
|
||||||
|
doc_root =
|
||||||
|
user_dir =
|
||||||
|
extension_dir = "ext"
|
||||||
|
enable_dl = Off
|
||||||
|
file_uploads = On
|
||||||
|
upload_max_filesize = 256M
|
||||||
|
max_file_uploads = 20
|
||||||
|
allow_url_fopen = On
|
||||||
|
allow_url_include = Off
|
||||||
|
default_socket_timeout = 60
|
||||||
|
|
||||||
|
extension=fileinfo
|
||||||
|
extension=gd
|
||||||
|
extension=gettext
|
||||||
|
extension=intl
|
||||||
|
extension=mbstring
|
||||||
|
extension=openssl
|
||||||
|
extension=sodium
|
||||||
|
extension=sqlite3
|
||||||
|
extension=tidy
|
||||||
|
|
||||||
|
[CLI Server]
|
||||||
|
cli_server.color = On
|
||||||
|
|
||||||
|
[mail function]
|
||||||
|
SMTP = localhost
|
||||||
|
smtp_port = 25
|
||||||
|
mail.add_x_header = Off
|
||||||
|
|
||||||
|
[bcmath]
|
||||||
|
bcmath.scale = 0
|
||||||
|
|
||||||
|
[Session]
|
||||||
|
session.save_handler = files
|
||||||
|
session.use_strict_mode = 0
|
||||||
|
session.use_cookies = 1
|
||||||
|
session.use_only_cookies = 1
|
||||||
|
session.name = PHPSESSID
|
||||||
|
session.auto_start = 0
|
||||||
|
session.cookie_lifetime = 0
|
||||||
|
session.cookie_path = /
|
||||||
|
session.cookie_domain =
|
||||||
|
session.cookie_httponly =
|
||||||
|
session.cookie_samesite =
|
||||||
|
session.serialize_handler = php
|
||||||
|
session.gc_probability = 1
|
||||||
|
session.gc_divisor = 1000
|
||||||
|
session.gc_maxlifetime = 1440
|
||||||
|
session.referer_check =
|
||||||
|
session.cache_limiter = nocache
|
||||||
|
session.cache_expire = 180
|
||||||
|
session.use_trans_sid = 0
|
||||||
|
session.sid_length = 26
|
||||||
|
session.trans_sid_tags = "a=href,area=href,frame=src,form="
|
||||||
|
session.sid_bits_per_character = 5
|
||||||
|
|
||||||
|
[Assertion]
|
||||||
|
zend.assertions = -1
|
||||||
|
|
||||||
|
[Tidy]
|
||||||
|
tidy.clean_output = Off
|
390
doc/admin/api.md
Normal file
390
doc/admin/api.md
Normal file
|
@ -0,0 +1,390 @@
|
||||||
|
Une API de type REST est disponible dans Paheko.
|
||||||
|
|
||||||
|
Pour accéder à l'API il faut un identifiant et un mot de passe, à créer dans le menu ==Configuration==, onglet ==Fonctions avancées==, puis ==API==.
|
||||||
|
|
||||||
|
L'API peut ensuite recevoir des requêtes REST sur l'URL `https://adresse_association/api/{chemin}/`.
|
||||||
|
|
||||||
|
Remplacer =={chemin}== par un des chemins de l'API (voir ci-dessous). La méthode HTTP à utiliser est spécifiée pour chaque chemin.
|
||||||
|
|
||||||
|
Pour les requêtes de type `POST`, les paramètres peuvent être envoyés par le client sous forme de formulaire HTTP classique (`application/x-www-form-urlencoded`) ou sous forme d'objet JSON. Dans ce cas le `Content-Type` doit être positionné sur `application/json`.
|
||||||
|
|
||||||
|
Les réponses sont faites en JSON par défaut.
|
||||||
|
|
||||||
|
<<toc level=3>>
|
||||||
|
|
||||||
|
# Utiliser l'API
|
||||||
|
|
||||||
|
N'importe quel client HTTP capable de gérer TLS (HTTPS) et l'authentification basique fonctionnera.
|
||||||
|
|
||||||
|
En ligne de commande il est possible d'utiliser `curl`. Exemple pour télécharger la base de données :
|
||||||
|
|
||||||
|
```
|
||||||
|
curl https://test:coucou@[identifiant_association].paheko.cloud/api/download -o association.sqlite
|
||||||
|
```
|
||||||
|
|
||||||
|
On peut aussi utiliser `wget` en n'oubliant pas l'option `--auth-no-challenge` sinon l'authentification ne fonctionnera pas :
|
||||||
|
|
||||||
|
```
|
||||||
|
wget https://test:coucou@[identifiant_association].paheko.cloud/api/download --auth-no-challenge -O association.sqlite
|
||||||
|
```
|
||||||
|
|
||||||
|
Exemple pour créer une écriture sous forme de formulaire :
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -v "http://test:test@[identifiant_association].paheko.cloud/api/accounting/transaction" -F id_year=1 -F label=Test -F "date=01/02/2023" …
|
||||||
|
```
|
||||||
|
|
||||||
|
Ou sous forme d'objet JSON :
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -v "http://test:test@[identifiant_association].paheko.cloud/api/accounting/transaction" -H 'Content-Type: application/json' -d '{"id_year":1, "label": "Test écriture", "date": "01/02/2023"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# Authentification
|
||||||
|
|
||||||
|
Il ne faut pas oublier de fournir le nom d'utilisateur et mot de passe en HTTP :
|
||||||
|
|
||||||
|
```
|
||||||
|
curl http://test:abcd@paheko.monasso.tld/api/download/
|
||||||
|
```
|
||||||
|
|
||||||
|
# Erreurs
|
||||||
|
|
||||||
|
En cas d'erreur un code HTTP 4XX sera fourni, et le contenu sera un objet JSON avec une clé `error` contenant le message d'erreur.
|
||||||
|
|
||||||
|
# Chemins
|
||||||
|
|
||||||
|
## sql (POST)
|
||||||
|
|
||||||
|
Permet d'exécuter une requête SQL `SELECT` (uniquement, pas de requête UPDATE, DELETE, INSERT, etc.) sur la base de données. La requête SQL doit être passée dans le corps de la requête HTTP, ou dans le paramètre `sql`. Le résultat est retourné dans la clé `results` de l'objet JSON.
|
||||||
|
|
||||||
|
S'il n'y a pas de limite à la requête, une limite à 1000 résultats sera ajoutée obligatoirement.
|
||||||
|
|
||||||
|
```
|
||||||
|
curl https://test:abcd@paheko.monasso.tld/api/sql/ -d 'SELECT * FROM membres LIMIT 5;'
|
||||||
|
```
|
||||||
|
|
||||||
|
**ATTENTION :** Les requêtes en écriture (`INSERT, DELETE, UPDATE, CREATE TABLE`, etc.) ne sont pas acceptées, il n'est pas possible de modifier la base de données directement via Paheko, afin d'éviter les soucis de données corrompues.
|
||||||
|
|
||||||
|
Depuis la version 1.2.8, il est possible d'utiliser le paramètre `format` pour choisir le format renvoyé :
|
||||||
|
|
||||||
|
* `json` (défaut) : renvoie un objet JSON, dont la clé est `"results"` et contient un tableau de la liste des membres trouvés
|
||||||
|
* `csv` : renvoie un fichier CSV
|
||||||
|
* `ods` : renvoie un tableau LibreOffice Calc (ODS)
|
||||||
|
* `xlsx` : renvoie un tableau Excel (XLSX)
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
curl https://test:abcd@paheko.monasso.tld/api/sql/ -F sql='SELECT * FROM membres LIMIT 5;' -F format=csv
|
||||||
|
```
|
||||||
|
|
||||||
|
## Téléchargements
|
||||||
|
|
||||||
|
### download (GET)
|
||||||
|
|
||||||
|
Télécharger la base de données complète. Renvoie directement le fichier SQLite de la base de données.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
curl https://test:abcd@paheko.monasso.tld/api/download -o db.sqlite
|
||||||
|
```
|
||||||
|
|
||||||
|
### download/files (GET)
|
||||||
|
|
||||||
|
*(Depuis la version 1.3.4)*
|
||||||
|
|
||||||
|
Télécharger un fichier ZIP contenant tous les fichiers (documents, fichiers des écritures, des membres, modules modifiés, etc.).
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
curl https://test:abcd@paheko.monasso.tld/api/download/files -o backup_files.zip
|
||||||
|
```
|
||||||
|
|
||||||
|
## Site web
|
||||||
|
|
||||||
|
### web/list (GET)
|
||||||
|
|
||||||
|
Renvoie la liste des pages du site web.
|
||||||
|
|
||||||
|
### web/attachment/{PAGE_URI}/{FILENAME} (GET)
|
||||||
|
|
||||||
|
Renvoie le fichier joint correspondant à la page et nom de fichier indiqués.
|
||||||
|
|
||||||
|
### web/page/{PAGE_URI} (GET)
|
||||||
|
|
||||||
|
Renvoie un objet JSON avec toutes les infos de la page donnée.
|
||||||
|
|
||||||
|
Rajouter le paramètre `?html` à l'URL pour obtenir en plus une clé `html` dans l'objet JSON qui contiendra la page au format HTML.
|
||||||
|
|
||||||
|
### web/html/{PAGE_URI} (GET)
|
||||||
|
|
||||||
|
Renvoie uniquement le contenu de la page au format HTML.
|
||||||
|
|
||||||
|
## Membres
|
||||||
|
|
||||||
|
### user/import (PUT)
|
||||||
|
|
||||||
|
Permet d'importer un fichier de tableur (CSV/XLSX/ODS) de la liste des membres, comme si c'était fait depuis l'interface de Paheko.
|
||||||
|
|
||||||
|
Cette route nécessite une clé d'API ayant les droits d'administration, car importer un fichier peut permettre de modifier l'identifiant de connexion d'un administrateur et donc potentiellement d'obtenir l'accès à l'interface d'administration.
|
||||||
|
|
||||||
|
Paheko s'attend à ce que la première est ligne du tableau contienne le nom des colonnes, et que le nom des colonnes correspond au nom des champs de la fiche membre (ou à leur nom unique). Par exemple si votre fiche membre contient les champs *Nom et prénom* et *Adresse postale*, alors le fichier fourni devra ressembler à ceci :
|
||||||
|
|
||||||
|
| Nom et prénom | Adresse postale |
|
||||||
|
| :- | :- |
|
||||||
|
| Ada Lovelace | 42 rue du binaire, 21000 DIJON |
|
||||||
|
|
||||||
|
Ou à ceci :
|
||||||
|
|
||||||
|
| nom_prenom | adresse_postale |
|
||||||
|
| :- | :- |
|
||||||
|
| Ada Lovelace | 42 rue du binaire, 21000 DIJON |
|
||||||
|
|
||||||
|
La méthode renvoie un code HTTP `200 OK` si l'import s'est bien passé, sinon un code 400 et un message d'erreur JSON dans le corps de la réponse.
|
||||||
|
|
||||||
|
Utilisez la route `user/import/preview` avant pour vérifier que l'import correspond à ce que vous attendez.
|
||||||
|
|
||||||
|
Exemple pour modifier le nom du membre n°42 :
|
||||||
|
|
||||||
|
```
|
||||||
|
echo 'numero,nom' > membres.csv
|
||||||
|
echo '42,"Nouveau nom"' >> membres.csv
|
||||||
|
curl https://test:abcd@monpaheko.tld/api/user/import -T membres.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Paramètres
|
||||||
|
|
||||||
|
Les paramètres sont à spécifier dans l'URL, dans la query string.
|
||||||
|
|
||||||
|
Depuis la version 1.2.8 il est possible d'utiliser un paramètre supplémentaire `mode` contenant une de ces options pour spécifier le mode d'import :
|
||||||
|
|
||||||
|
* `auto` (défaut si le mode n'est pas spécifié) : met à jour la fiche d'un membre si son numéro existe, sinon crée un membre si le numéro de membre indiqué n'existe pas ou n'est pas renseigné
|
||||||
|
* `create` : ne fait que créer de nouvelles fiches de membre, si le numéro de membre existe déjà une erreur sera produite
|
||||||
|
* `update` : ne fait que mettre à jour les fiches de membre en utilisant le numéro de membre comme référence, si le numéro de membre n'existe pas une erreur sera produite
|
||||||
|
|
||||||
|
Depuis la version 1.3.0 il est possible de spécifier :
|
||||||
|
|
||||||
|
* le nombre de lignes à ignorer avec le paramètre `skip_lines=X` : elles ne seront pas importées. Par défaut la première ligne est ignorée.
|
||||||
|
* la correspondance des colonnes avec des paramètres `column[x]` ou `x` est le numéro de la colonne (la numérotation commence à zéro), et la valeur contient le nom unique du champ de la fiche membre.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
curl https://test:abcd@monpaheko.tld/api/user/import?mode=create&column[0]=nom_prenom&column[1]=code_postal&skip_lines=0 -T membres.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
### user/import (POST)
|
||||||
|
|
||||||
|
Identique à la même méthode en `PUT`, mais les paramètres sont passés dans le corps de la requête, avec le fichier, dont le nom sera alors `file`.
|
||||||
|
|
||||||
|
```
|
||||||
|
curl https://test:abcd@monpaheko.tld/api/user/import \
|
||||||
|
-F mode=create \
|
||||||
|
-F 'column[0]=nom_prenom' \
|
||||||
|
-F 'column[1]=code_postal' \
|
||||||
|
-F skip_lines=0 \
|
||||||
|
-F file=@membres.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
### user/import/preview (PUT)
|
||||||
|
|
||||||
|
Identique à `user/import`, mais l'import n'est pas enregistré, et la route renvoie les modifications qui seraient effectuées en important le fichier :
|
||||||
|
|
||||||
|
* `errors` : liste des erreurs d'import
|
||||||
|
* `created` : liste des membres ajoutés, chaque objet contenant tous les champs de la fiche membre qui serait créée
|
||||||
|
* `modified` : liste des membres modifiés, chaque membre aura une clé `id` et une clé `name`, ainsi qu'un objet `changed` contenant la liste des champs modifiés. Chaque champ modifié aura 2 propriétés `old` et `new`, contenant respectivement l'ancienne valeur du champ et la nouvelle.
|
||||||
|
* `unchanged` : liste des membres mentionnés dans l'import, mais qui ne seront pas affectés. Pour chaque membre une clé `name` et une clé `id` indiquant le nom et l'identifiant unique numérique du membre
|
||||||
|
|
||||||
|
Note : si `errors` n'est pas vide, alors il sera impossible d'importer le fichier avec `user/import`.
|
||||||
|
|
||||||
|
Exemple de retour :
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"created": [
|
||||||
|
{
|
||||||
|
"numero": 3434351,
|
||||||
|
"nom": "Bla Bli Blu"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"modified": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "Ada Lovelace",
|
||||||
|
"changed": {
|
||||||
|
"nom": {
|
||||||
|
"old": "Ada Lvelavce",
|
||||||
|
"new": "Ada Lovelace"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"unchanged": [
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "Paul Muad'Dib"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### user/import/preview (POST)
|
||||||
|
|
||||||
|
Idem quel la méthode en `PUT` mais accepte les paramètres dans le corps de la requête (voir ci-dessus).
|
||||||
|
|
||||||
|
## Activités
|
||||||
|
|
||||||
|
### services/subscriptions/import (PUT)
|
||||||
|
|
||||||
|
_(Depuis Paheko 1.3.2)_
|
||||||
|
|
||||||
|
Permet d'importer les inscriptions des membres aux activités à partir d'un fichier CSV. Les activités et tarifs doivent déjà exister avant l'import.
|
||||||
|
|
||||||
|
Les colonnes suivantes peuvent être utilisées :
|
||||||
|
|
||||||
|
* Numéro de membre`**`
|
||||||
|
* Activité`**`
|
||||||
|
* Tarif
|
||||||
|
* Date d'inscription`**`
|
||||||
|
* Date d'expiration
|
||||||
|
* Montant à régler
|
||||||
|
* Payé ?
|
||||||
|
|
||||||
|
Les colonnes suivies de deux astérisques (`**`) sont obligatoires.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
echo '"Numéro de membre","Activité","Tarif","Date d'inscription","Date d'expiration","Montant à régler","Payé ?"' > /tmp/inscriptions.csv
|
||||||
|
echo '42,"Cours de théâtre","Tarif adulte","01/09/2023","01/07/2023","123,50","Non"' >> /tmp/inscriptions.csv
|
||||||
|
curl https://test:abcd@monpaheko.tld/api/services/subscriptions/import -T /tmp/inscriptions.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
## Erreurs
|
||||||
|
|
||||||
|
Paheko dispose d'un système dédié à la gestion des erreurs internes, compatible avec les formats des logiciels AirBrake et errbit.
|
||||||
|
|
||||||
|
### errors/report (POST)
|
||||||
|
|
||||||
|
Permet d'envoyer un rapport d'erreur (au format airbrake/errbit/Paheko), comme si c'était une erreur locale.
|
||||||
|
|
||||||
|
### errors/log (GET)
|
||||||
|
|
||||||
|
Renvoie le log d'erreurs système, au format airbrake/errbit ([voir la doc AirBrake pour un exemple du format](https://airbrake.io/docs/api/#create-notice-v3))
|
||||||
|
|
||||||
|
## Comptabilité
|
||||||
|
|
||||||
|
### accounting/years (GET)
|
||||||
|
|
||||||
|
Renvoie la liste des exercices.
|
||||||
|
|
||||||
|
### accounting/charts (GET)
|
||||||
|
|
||||||
|
Renvoie la liste des plans comptables.
|
||||||
|
|
||||||
|
### accounting/charts/{ID_CHART}/accounts (GET)
|
||||||
|
|
||||||
|
Renvoie la liste des comptes pour le plan comptable indiqué (voir `id_chart` dans la liste des exercices).
|
||||||
|
|
||||||
|
### accounting/years/{ID_YEAR}/journal (GET)
|
||||||
|
|
||||||
|
Renvoie le journal général des écritures de l'exercice indiqué.
|
||||||
|
|
||||||
|
Note : il est possible d'utiliser `current` comme paramètre pour `{ID_YEAR}` pour désigner l'exercice ouvert en cours. S'il y a plusieurs exercices ouverts, alors le plus ancien sera choisi.
|
||||||
|
|
||||||
|
### accounting/years/{ID_YEAR}/account/journal (GET)
|
||||||
|
|
||||||
|
Renvoie le journal des écritures d'un compte pour l'exercice indiqué.
|
||||||
|
|
||||||
|
Le compte est spécifié soit via le paramètre `code`, soit via le paramètre `id`. Exemple : `/accounting/years/4/account/journal?code=512A`
|
||||||
|
|
||||||
|
Note : il est possible d'utiliser `current` comme paramètre pour `{ID_YEAR}` pour désigner l'exercice ouvert en cours. S'il y a plusieurs exercices ouverts, alors le plus ancien sera choisi.
|
||||||
|
|
||||||
|
### accounting/transaction/{ID_TRANSACTION} (GET)
|
||||||
|
|
||||||
|
Renvoie les détails de l'écriture indiquée.
|
||||||
|
|
||||||
|
### accounting/transaction/{ID_TRANSACTION} (POST)
|
||||||
|
|
||||||
|
Modifie l'écriture indiquée. Voir plus bas le format attendu.
|
||||||
|
|
||||||
|
### accounting/transaction/{ID_TRANSACTION}/users (GET)
|
||||||
|
|
||||||
|
Renvoie la liste des membres liés à une écriture.
|
||||||
|
|
||||||
|
### accounting/transaction/{ID_TRANSACTION}/users (POST)
|
||||||
|
|
||||||
|
Met à jour la liste des membres liés à une écriture, en utilisant les ID de membres passés dans un tableau nommé `users`.
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -v "http://…/api/accounting/transaction/9337/users" -F 'users[]=2'
|
||||||
|
```
|
||||||
|
|
||||||
|
### accounting/transaction/{ID_TRANSACTION}/users (DELETE)
|
||||||
|
|
||||||
|
Efface la liste des membres liés à une écriture.
|
||||||
|
|
||||||
|
### accounting/transaction/{ID_TRANSACTION}/subscriptions (GET)
|
||||||
|
|
||||||
|
(Depuis la version 1.3.6)
|
||||||
|
|
||||||
|
Renvoie la liste des inscriptions (aux activités) liées à une écriture.
|
||||||
|
|
||||||
|
### accounting/transaction/{ID_TRANSACTION}/subscriptions (POST)
|
||||||
|
|
||||||
|
(Depuis la version 1.3.6)
|
||||||
|
|
||||||
|
Met à jour la liste des inscriptions liées à une écriture, en utilisant les ID d'inscriptions passés dans un tableau nommé `subscriptions`.
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -v "http://…/api/accounting/transaction/9337/subscriptions" -F 'subscriptions[]=2'
|
||||||
|
```
|
||||||
|
|
||||||
|
### accounting/transaction/{ID_TRANSACTION}/subscriptions (DELETE)
|
||||||
|
|
||||||
|
(Depuis la version 1.3.6)
|
||||||
|
|
||||||
|
Efface la liste des inscriptions liées à une écriture.
|
||||||
|
|
||||||
|
### accounting/transaction (POST)
|
||||||
|
|
||||||
|
Crée une nouvelle écriture, renvoie les détails si l'écriture a été créée. Voir plus bas le format attendu.
|
||||||
|
|
||||||
|
#### Structure pour créer / modifier une écriture
|
||||||
|
|
||||||
|
Les champs à spécifier pour créer ou modifier une écriture sont les suivants :
|
||||||
|
|
||||||
|
* `id_year`
|
||||||
|
* `date` (format YYYY-MM-DD)
|
||||||
|
* `type` peut être un type d'écriture simplifié (2 lignes) : `EXPENSE` (dépense), `REVENUE` (recette), `TRANSFER` (virement), `DEBT` (dette), `CREDIT` (créance), ou `ADVANCED` pour une écriture multi-ligne
|
||||||
|
* `amount` (uniquement pour les écritures simplifiées) : contient le montant de l'écriture
|
||||||
|
* `credit` (uniquement pour les écritures simplifiées) : contient le numéro du compte porté au crédit
|
||||||
|
* `debit` (uniquement pour les écritures simplifiées) : contient le numéro du compte porté au débit
|
||||||
|
* `lines` (pour les écritures multi-lignes) : un tableau dont chaque ligne doit contenir :
|
||||||
|
* `account` (numéro du compte) ou `id_account` (ID unique du compte)
|
||||||
|
* `credit` : montant à inscrire au crédit (doit être zéro ou non renseigné si `debit` est renseigné, et vice-versa)
|
||||||
|
* `debit` : montant à inscrire au débit
|
||||||
|
* `label` (facultatif) : libellé de la ligne
|
||||||
|
* `reference` (facultatif) : référence de la ligne (aussi appelé référence du paiement pour les écritures simplifiées)
|
||||||
|
* `id_project` : ID unique du projet à affecter
|
||||||
|
|
||||||
|
Champs optionnels :
|
||||||
|
|
||||||
|
* `reference` : numéro de pièce comptable
|
||||||
|
* `notes` : remarques (texte multi ligne)
|
||||||
|
* `id_project` : ID unique du projet à affecter (pour les écritures simplifiées uniquement)
|
||||||
|
* `payment_reference` (uniquement pour les écritures simplifiées) : référence de paiement
|
||||||
|
* `linked_users` : Tableau des IDs des membres à lier à l'écriture *(depuis 1.3.3)*
|
||||||
|
* `linked_transactions` : Tableau des IDs des écritures à lier à l'écriture *(depuis 1.3.5)*
|
||||||
|
* `linked_subscriptions` : Tableau des IDs des inscriptions à lier à l'écriture *(depuis 1.3.6)*
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -F 'id_year=12' -F 'label=Test' -F 'date=01/02/2022' -F 'type=EXPENSE' -F 'amount=42' -F 'debit=512A' -F 'credit=601' …
|
||||||
|
```
|
493
doc/admin/brindille.md
Normal file
493
doc/admin/brindille.md
Normal file
|
@ -0,0 +1,493 @@
|
||||||
|
Title: Documentation du langage Brindille dans Paheko
|
||||||
|
|
||||||
|
{{{.nav
|
||||||
|
* [Modules](modules.html)
|
||||||
|
* **[Documentation Brindille](brindille.html)**
|
||||||
|
* [Fonctions](brindille_functions.html)
|
||||||
|
* [Sections](brindille_sections.html)
|
||||||
|
* [Filtres](brindille_modifiers.html)
|
||||||
|
}}}
|
||||||
|
|
||||||
|
<<toc aside>>
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
La syntaxe utilisée dans les squelettes du site web et des modules s'appelle **Brindille**.
|
||||||
|
|
||||||
|
Si vous avez déjà fait de la programmation, elle ressemble à un mélange de Mustache, Smarty, Twig et PHP.
|
||||||
|
|
||||||
|
Son but est de permettre une grande flexibilité, sans avoir à utiliser un "vrai" langage de programmation, mais en s'en rapprochant suffisamment quand même.
|
||||||
|
|
||||||
|
## Fichiers
|
||||||
|
|
||||||
|
Un fichier texte contenant du code Brindille est appelé un **squelette**.
|
||||||
|
|
||||||
|
Seuls les fichiers ayant une des extensions `.tpl`, `.html`, `.htm`, `.skel` ou `.xml` seront traités par Brindille.
|
||||||
|
De même, les fichiers qui n'ont pas d'extension seront également traités par Brindille.
|
||||||
|
|
||||||
|
Les autres types de fichiers seront renvoyés sans traitement, comme des fichiers "bruts". En d'autres termes, il n'est pas possible de mettre du code *Brindille* dans des fichiers qui ne sont pas des fichiers textes.
|
||||||
|
|
||||||
|
# Syntaxe de base
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
|
||||||
|
En programmation, une variable est une référence vers une donnée stockée en mémoire.
|
||||||
|
|
||||||
|
Dans Brindille, une variable commence par le symbole dollar `$` et suivi d'un nom.
|
||||||
|
|
||||||
|
Le nom est composé de lettres minuscules (sans accents), de chiffres et de tirets bas (`[a-z0-9_]`).
|
||||||
|
|
||||||
|
Exemples de variables :
|
||||||
|
|
||||||
|
```
|
||||||
|
$config
|
||||||
|
$compte_32
|
||||||
|
$nom_de_variable_long
|
||||||
|
```
|
||||||
|
|
||||||
|
### Types de variables
|
||||||
|
|
||||||
|
Dans Brindille, une variable peut avoir un des types suivants :
|
||||||
|
|
||||||
|
* `null` : utilisé pour une variable qui n'est pas définie, ou une variable définie qui n'a pas de valeur
|
||||||
|
* `boolean` : valeur booléenne, peut seulement avoir `true` ou `false` comme valeur
|
||||||
|
* `integer` : nombre entier (sans virgule). Exemple : `4200`.
|
||||||
|
* `float` : nombre à virgule flottante, exemple `3.14`. Leur usage est déconseillé, car les erreurs de calcul sont possibles, les ordinateurs ne sachant pas compter de manière précise avec les nombres à virgule flottante. Exemple : `0.2+0.3` est différent de `0.5`.
|
||||||
|
* `string` : chaîne de texte (aussi appelé chaîne de caractères, car c'est une suite de caractères). Exemple : `coucou`.
|
||||||
|
* `array` : tableau.
|
||||||
|
|
||||||
|
### Tableaux
|
||||||
|
|
||||||
|
Les tableaux sont une sorte de dictionnaire, ou pour chaque entrée (appelée "clé") on peut associer une valeur. qui peut être de n'importe lequel des types listés ci-dessus, y compris un autre tableau.
|
||||||
|
|
||||||
|
Les tableaux peuvent être de deux types :
|
||||||
|
|
||||||
|
1. tableau indexé (liste) : dans ce cas les clés ne sont pas choisies, on ajoute simplement des valeurs, et l'ordinateur incrémente le numéro de la clé à chaque nouvelle entrée dans le tableau. La numérotation commence au chiffre zéro.
|
||||||
|
2. tableau associatif (dictionnaire) : les clés sont des nombres ou des chaînes de texte, et permettent, comme dans un dictionnaire, de choisir la clé.
|
||||||
|
|
||||||
|
Exemple de tableau indexé :
|
||||||
|
|
||||||
|
```
|
||||||
|
[
|
||||||
|
0 => 'Texte 1',
|
||||||
|
1 => 'Texte 2'
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Exemple de tableau associatif :
|
||||||
|
|
||||||
|
```
|
||||||
|
[
|
||||||
|
'un' => 'Texte 1',
|
||||||
|
'deux' => 'Texte 2'
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Affichage de variable
|
||||||
|
|
||||||
|
Une variable est affichée à l'aide de la syntaxe : `{{$date}}` affichera la valeur brute de la date par exemple : `2020-01-31 16:32:00`.
|
||||||
|
|
||||||
|
La variable peut être modifiée à l'aide de filtres de modification, qui sont ajoutés avec le symbole de la barre verticale (pipe `|`) : `{{$date|date_long}}` affichera une date au format long : `jeudi 7 mars 2021`.
|
||||||
|
|
||||||
|
Ces filtres peuvent accepter des paramètres, séparés par deux points `:`. Exemple : `{{$date|date:"d/m/Y"}}` affichera `31/01/2020`.
|
||||||
|
|
||||||
|
Par défaut la variable sera recherchée dans le contexte actuel de la section, si elle n'est pas trouvée elle sera recherchée dans le contexte parent (section parente), etc. jusqu'à trouver la variable.
|
||||||
|
|
||||||
|
### Protection contre le HTML (échappement)
|
||||||
|
|
||||||
|
Par défaut le filtre `escape` est appliqué à toutes les variables affichées, pour protéger les variables contre les injections de code HTML.
|
||||||
|
|
||||||
|
Ce filtre modifie (on dit qu'il "échappe") les caractères HTML `<>&"'` présents dans une chaîne de texte en entités HTML, évitant que le HTML éventuellement présent dans la chaîne de texte soit interprété par le navigateur.
|
||||||
|
|
||||||
|
Ce filtre est appliqué en dernier, après les autres filtres. Il est possible de contourner cet automatisme en rajoutant le filtre `escape` ou `raw` explicitement. `raw` désactive tout échappement, alors que `escape` est utilisé pour changer l'ordre d'échappement. Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign text = "Coucou\nça va ?" }}
|
||||||
|
{{$text|escape|nl2br}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Donnera bien `Coucou<br />ça va ?`. Si on n'avait pas indiqué le filtre `escape` le résultat serait `Coucou<br />ça va ?`.
|
||||||
|
|
||||||
|
### Variables de tableaux
|
||||||
|
|
||||||
|
Il est possible de faire référence à une clé d'un tableau avec la notation à points : `{{$article.date}}` renverra la clé `date` du tableau stocké dans la variable `$article`.
|
||||||
|
|
||||||
|
### Échappement des caractères spéciaux dans les chaînes de caractère
|
||||||
|
|
||||||
|
Pour inclure un caractère spécial (retour de ligne, guillemets ou apostrophe) dans une chaîne de caractère il suffit d'utiliser un antislash :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign text="Retour \n à la ligne"}}
|
||||||
|
{{:assign text="Utiliser des \"apostrophes\"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ordre de recherche des variables
|
||||||
|
|
||||||
|
Par défaut les variables sont recherchées dans l'ordre inverse, c'est à dire que sont d'abord recherchées les variables avec le nom demandé dans la section courante. Si la variable n'existe pas dans la section courante, alors elle est recherchée dans la section parente, et ainsi de suite jusqu'à ce que la variable soit trouvée, où qu'il n'y ait plus de section parente.
|
||||||
|
|
||||||
|
Prenons cet exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#articles uri="Actualite"}}
|
||||||
|
<h1>{{$title}}</h1>
|
||||||
|
{{#images parent=$path limit=1}}
|
||||||
|
<img src="{{$thumb_url}}" alt="{{$title}}" />
|
||||||
|
{{/images}}
|
||||||
|
{{/articles}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Dans la section `articles`, `$title` est une variable de l'article, donc la variable est celle de l'article.
|
||||||
|
|
||||||
|
Dans la section `images`, les images n'ayant pas de titre, la variable sera celle de l'article de la section parente, alors que `$thumb_url` sera lié à l'image.
|
||||||
|
|
||||||
|
## Conflit de noms de variables
|
||||||
|
|
||||||
|
Imaginons que nous voulions mettre un lien vers l'article sur l'image de l'exemple précédent :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#articles uri="Actualite"}}
|
||||||
|
<h1>{{$title}}</h1>
|
||||||
|
{{#images parent=$path limit=1}}
|
||||||
|
|
||||||
|
{{/images}}
|
||||||
|
{{/articles}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Problème, ici `$url` fera référence à l'URL de l'image elle-même, et non pas l'URL de l'article.
|
||||||
|
|
||||||
|
La solution est d'ajouter un point au début du nom de variable : `{{$.url}}`.
|
||||||
|
|
||||||
|
Un point au début d'un nom de variable signifie que la variable est recherchée à partir de la section précédente. Il est possible d'utiliser plusieurs points, chaque point correspond à un niveau à remonter. Ainsi `$.url` cherchera la variable dans la section parente (et ses sections parentes si elle n'existe pas, etc.). De même, `$..url` cherchera dans la section parente de la section parente.
|
||||||
|
|
||||||
|
## Création manuelle de variable
|
||||||
|
|
||||||
|
### Variable simple
|
||||||
|
|
||||||
|
La création d'une variable se fait via l'appel de la fonction `{{:assign}}`.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign source='wiki'}}
|
||||||
|
{{* est identique à : *}}
|
||||||
|
{{:assign var='source' value='wiki'}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Un deuxième appel à `{{:assign}}` avec le même nom de variable écrase la valeur précédente
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var='source' value='wiki'}}
|
||||||
|
{{:assign var='source' value='documentation'}}
|
||||||
|
|
||||||
|
{{$source}}
|
||||||
|
{{* => Affiche documentation *}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nom de variable dynamique
|
||||||
|
|
||||||
|
Il est possible de créer une variable dont une partie du nom est dynamique.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign type='user'}}
|
||||||
|
{{:assign var='allowed_%s'|args:$type value='jeanne'}}
|
||||||
|
{{:assign type='side'}}
|
||||||
|
{{:assign var='allowed_%s'|args:$type value='admin'}}
|
||||||
|
|
||||||
|
{{$allowed_user}} => jeanne
|
||||||
|
{{$allowed_side}} => admin
|
||||||
|
```
|
||||||
|
|
||||||
|
[Documentation complète de la fonction {{:assign}}](brindille_functions.html#assign).
|
||||||
|
|
||||||
|
### Tableaux *(array)*
|
||||||
|
|
||||||
|
Pour créer des tableaux, il suffit d'utiliser des points `.` dans le nom de la variable (ex : `colors.yellow`). Il n'y a pas besoin d'initialiser le tableau avant de le remplir.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var='colors.admin' value='blue'}}
|
||||||
|
{{:assign var='colors.website' value='grey'}}
|
||||||
|
{{:assign var='colors.debug' value='yellow'}}
|
||||||
|
```
|
||||||
|
|
||||||
|
On accède ensuite à la valeur d'un élément du tableau avec la même syntaxe : `{{$colors.website}}`
|
||||||
|
|
||||||
|
Méthode rapide de création du même tableau :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var='colors' admin='blue' website='grey' debug='yellow'}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Pour ajouter un élément à la suite du tableau sans spécifier de clef *(push)*, il suffit de terminer le nom de la variable par un point `.` sans suffixe.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{* Ajouter les valeurs 17, 43 et 214 dans $processed_ids *}}
|
||||||
|
|
||||||
|
{{:assign var='processed_ids.' value=17}}
|
||||||
|
{{:assign var='processed_ids.' value=43}}
|
||||||
|
{{:assign var='processed_ids.' value=214}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Donnera le tableau suivant :
|
||||||
|
|
||||||
|
```
|
||||||
|
[
|
||||||
|
0 => 17,
|
||||||
|
1 => 43,
|
||||||
|
2 => 214
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Clef dynamique de tableau
|
||||||
|
|
||||||
|
Il est possible d'accéder dynamiquement à un des éléments d'un tableau de la manière suivante :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign location='admin'}}
|
||||||
|
{{:assign var='location_color' from='colors.%s'|args:$location}}
|
||||||
|
|
||||||
|
{{$location_color}} => blue
|
||||||
|
```
|
||||||
|
|
||||||
|
Exemple plus complexe :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var='type_whitelist.text' value=1}}
|
||||||
|
{{:assign var='type_whitelist.html' value=1}}
|
||||||
|
|
||||||
|
{{#foreach from=$documents item='document'}}
|
||||||
|
{{:assign var='allowed' value='type_whitelist.%s'|args:$document->type}}
|
||||||
|
{{if $allowed !== null}}
|
||||||
|
{{:include file='document/'|cat:$type:'.tpl' keep='document'}}
|
||||||
|
{{/if}}
|
||||||
|
{{/foreach}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est également possible de créer un membre dynamique d'un tableau en conjuguant les syntaxes précédentes.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var='type_whitelist.%s'|args:$type value=1}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conditions
|
||||||
|
|
||||||
|
Il est possible d'utiliser des conditions de type **"si"** (`if`), **"sinon si"** (`elseif`) et **"sinon"** (`else`). Celles-ci sont terminées par un block **"fin si"** (`/if`).
|
||||||
|
|
||||||
|
```
|
||||||
|
{{if $date|date:"%Y" > 2020}}
|
||||||
|
La date est en 2020
|
||||||
|
{{elseif $article.status == 'draft'}}
|
||||||
|
La page est un brouillon
|
||||||
|
{{else}}
|
||||||
|
Autre chose.
|
||||||
|
{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Une condition peut être évaluée comme *vraie*, dans ce cas la partie qui suit le bloc `{{if …}}` sera exécutée.
|
||||||
|
|
||||||
|
Si la condition est évaluée comme *fausse*, alors la partie qui suit le bloc `{{if …}}` ne sera pas exécutée. Dans ce cas, soit une condition `{{elseif …}}` suivante est vraie et exécutée, mais sinon c'est le contenu du bloc `{{else}}` qui est exécuté et affiché.
|
||||||
|
|
||||||
|
Dans une condition on peut utiliser :
|
||||||
|
|
||||||
|
* une variable : `$nom_variable`
|
||||||
|
* une variable avec des filtres : `$nom_variable|filtre1:parametre1`
|
||||||
|
* une valeur (nombre, constante) : `42`, `-42`, `42.02` `null`, `true`, `false`
|
||||||
|
* des opérateurs de comparaison
|
||||||
|
* des opérateurs logiques
|
||||||
|
|
||||||
|
Attention : on ne peut pas grouper les conditions avec des parenthèses.
|
||||||
|
|
||||||
|
Les comparaisons supportées sont les suivantes :
|
||||||
|
|
||||||
|
| Opérateur de comparaison | Explication |
|
||||||
|
| :- | :- |
|
||||||
|
| `==` | égalité faible, ne prend pas en compte le type : `1 == true` et `2 == 2.00` serons évalués comme vrais |
|
||||||
|
| `===` | égalité forte, prend en compte le type : `1 === 1` sera vrai, mais `1 === true` sera faux |
|
||||||
|
| `!=` | différent de, en comparaison faible |
|
||||||
|
| `!==` | différent de, en comparaison forte |
|
||||||
|
| `>` | supérieur à |
|
||||||
|
| `>=` | supérieur ou égal à |
|
||||||
|
| `<` | inférieur à |
|
||||||
|
| `<=` | inférieur ou égal à |
|
||||||
|
|
||||||
|
Il est aussi possible de précéder une variable de l'opérateur `!`, c'est un raccourci pour `$variable == false`.
|
||||||
|
|
||||||
|
Voir [les opérateurs de comparaison PHP pour plus de détails](https://www.php.net/manual/fr/language.operators.comparison.php).
|
||||||
|
|
||||||
|
Les opérateurs logiques supportés sont :
|
||||||
|
|
||||||
|
| Opérateur | Explication |
|
||||||
|
| :- | :- |
|
||||||
|
| `&&` | Vrai si les conditions à gauche et à droite sont vraies |
|
||||||
|
| `||` | Vrai si une des conditions à gauche ou à droite est vraie |
|
||||||
|
|
||||||
|
Exemples :
|
||||||
|
|
||||||
|
* `false && true` : sera évalué comme faux
|
||||||
|
* `false || true` : sera évalué comme vrai
|
||||||
|
|
||||||
|
|
||||||
|
### Tester si une variable existe
|
||||||
|
|
||||||
|
Brindille ne fait pas de différences entre une variable qui n'existe pas, et une variable définie à `null`.
|
||||||
|
On peut donc tester l'existence d'une variable en la comparant à `null` comme ceci :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{if $session !== null}}
|
||||||
|
Session en cours pour l'utilisateur/trice {{$session.user.name}}.
|
||||||
|
{{else}}
|
||||||
|
Session inexistante.
|
||||||
|
{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fonctions
|
||||||
|
|
||||||
|
### Fonctions natives
|
||||||
|
|
||||||
|
Une fonction va répondre à certains paramètres et renvoyer un résultat ou réaliser une action.
|
||||||
|
|
||||||
|
**Un bloc de fonction commence par le signe deux points `:`.**
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:http code=404}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Contrairement aux autres types de blocs, et comme pour les variables, il n'y a pas de bloc fermant (avec un slash `/`).
|
||||||
|
|
||||||
|
## Sections
|
||||||
|
|
||||||
|
Une section est une partie de la page qui sera répétée une fois, plusieurs fois, ou zéro fois, selon ses paramètres et le résultat (c'est une "boucle"). Une section commence par un bloc avec un signe hash (`#`) et se termine par un bloc avec un slash (`/`).
|
||||||
|
|
||||||
|
Un exemple simple avec une section qui n'aura qu'une seule répétition :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#categories uri=$_GET.uri}}
|
||||||
|
<h1>{{$title}}</h1>
|
||||||
|
{{/categories}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est possible d'utiliser une condition `{{else}}` avant la fin du bloc pour avoir du contenu alternatif si la section ne se répète pas (dans ce cas si aucune catégorie ne correspond au critère).
|
||||||
|
|
||||||
|
Un exemple de sous-section
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#categories uri=$_GET.uri}}
|
||||||
|
<h1>{{$title}}</h1>
|
||||||
|
|
||||||
|
{{#articles parent=$path order="published DESC" limit="10"}}
|
||||||
|
<h2></h2>
|
||||||
|
<p>{{$content|truncate:600:"..."}}</p>
|
||||||
|
{{else}}
|
||||||
|
<p>Aucun article trouvé.</p>
|
||||||
|
{{/articles}}
|
||||||
|
|
||||||
|
{{/categories}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Voir la référence des sections pour voir quelles sont les sections possibles et quel est leur comportement.
|
||||||
|
|
||||||
|
## Bloc litéral
|
||||||
|
|
||||||
|
Pour qu'une partie du code ne soit pas interprété, pour éviter les conflits avec certaines syntaxes, il est possible d'utiliser un bloc `literal` :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{literal}}
|
||||||
|
<script>
|
||||||
|
// Ceci ne sera pas interprété
|
||||||
|
function test (a) {{
|
||||||
|
}}
|
||||||
|
</script>
|
||||||
|
{{/literal}}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Commentaires
|
||||||
|
|
||||||
|
Les commentaires sont figurés dans des blocs qui commencent et se terminent par une étoile (`*`) :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{* Ceci est un commentaire
|
||||||
|
Il sera supprimé du résultat final
|
||||||
|
Il peut contenir du code qui ne sera pas interprété :
|
||||||
|
{{if $test}}
|
||||||
|
OK
|
||||||
|
{{/if}}
|
||||||
|
*}}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# Liste des variables définies par défaut
|
||||||
|
|
||||||
|
Ces variables sont définies tout le temps :
|
||||||
|
|
||||||
|
| Nom de la variable | Valeur |
|
||||||
|
| :- | :- |
|
||||||
|
| `$_GET` | Tableau contenant tous les paramètres passés dans la chaîne de requêtre de l'URL. |
|
||||||
|
| `$_POST` | Tableau de tous les éléments de formulaire envoyés lors d'une requête POST. |
|
||||||
|
| `$root_url` | Adresse racine du site web Paheko. |
|
||||||
|
| `$request_url` | Adresse de la page courante. |
|
||||||
|
| `$admin_url` | Adresse de la racine de l'administration Paheko. |
|
||||||
|
| `$visitor_lang` | Langue préférée du visiteur, sur 2 lettres (exemple : `fr`, `en`, etc.). |
|
||||||
|
| `$logged_user` | Informations sur le membre actuellement connecté dans l'administration (vide si non connecté). |
|
||||||
|
| `$dialog` | Vaut `TRUE` si la page est dans un dialogue (iframe sous forme de pop-in dans l'administration). |
|
||||||
|
| `$now` | Contient la date et heure courante. |
|
||||||
|
| `$config.org_name` | Nom de l'association |
|
||||||
|
| `$config.org_email` | Adresse e-mail de l'association |
|
||||||
|
| `$config.org_phone` | Numéro de téléphone de l'association |
|
||||||
|
| `$config.org_address` | Adresse postale de l'association |
|
||||||
|
| `$config.org_web` | Adresse du site web de l'association |
|
||||||
|
| `$config.files.logo` | Adresse du logo de l'association, si définit dans la personnalisation |
|
||||||
|
| `$config.files.favicon` | Adresse de l'icône de favoris de l'association, si défini dans la personnalisation |
|
||||||
|
| `$config.files.signature` | Adresse de l'image de signature, si défini dans la personnalisation |
|
||||||
|
|
||||||
|
À celles-ci s'ajoutent [les variables spéciales des modules](modules.html#variables_speciales) lorsque le script est chargé dans un module.
|
||||||
|
|
||||||
|
# Erreurs
|
||||||
|
|
||||||
|
Si une erreur survient dans un squelette, que ça soit au niveau d'une erreur de syntaxe, ou une erreur dans une fonction, filtre ou section, alors elle sera affichée selon les règles suivantes :
|
||||||
|
|
||||||
|
* si le membre connecté est administrateur, une erreur est affichée avec le code du squelette ;
|
||||||
|
* sinon l'erreur est affichée sans le code.
|
||||||
|
|
||||||
|
|
||||||
|
# Avertissement sur la sécurité des requêtes SQL
|
||||||
|
|
||||||
|
Attention, en utilisant la section `{{#select ...}}`, ou une des sections SQL (voir plus bas), avec des paramètres qui ne seraient pas protégés, il est possible qu'une personne mal intentionnée ait accès à des parties de la base de données à laquelle vous ne désirez pas donner accès.
|
||||||
|
|
||||||
|
Pour protéger contre cela il est essentiel d'utiliser les paramètres nommés.
|
||||||
|
|
||||||
|
Exemple de requête dangereuse :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#sql select="*" tables="users" where="id = %s"|args:$_GET.id}}
|
||||||
|
...
|
||||||
|
{{/sql}}
|
||||||
|
```
|
||||||
|
|
||||||
|
On se dit que la requête finale sera donc : `SELECT * FROM users WHERE id = 42;` si le numéro 42 est passé dans le paramètre `id` de la page.
|
||||||
|
|
||||||
|
Imaginons qu'une personne mal-intentionnée indique dans le paramètre `id` de la page la chaîne de caractère suivante : `0 OR 1`. Dans ce cas la requête exécutée sera `SELECT * FROM users WHERE id = 0 OR 1;`. Cela aura pour effet de lister tous les membres, au lieu d'un seul.
|
||||||
|
|
||||||
|
Pour protéger contre cela il convient d'utiliser un paramètre nommé :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#sql select="*" tables="users" where="id = :id" :id=$_GET.id}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Dans ce cas la requête malveillante générée sera `SELECT * FROM users WHERE id = '0 OR 1';`. Ce qui aura pour effet de ne lister aucun membre.
|
||||||
|
|
||||||
|
## Mesures prises pour la sécurité des données
|
||||||
|
|
||||||
|
Dans Brindille, il n'est pas possible de modifier ou supprimer des éléments dans la base de données avec les requêtes SQL directement. Seules les requêtes SQL en lecture (`SELECT`) sont permises.
|
||||||
|
|
||||||
|
Cependant certaines fonctions permettent de modifier ou créer des éléments précis (écritures par exemple), ce qui peut avoir un effet de remplir ou modifier des données par une personne mal-intentionnée, donc attention à leur utilisation.
|
||||||
|
|
||||||
|
Les autres mesures prises sont :
|
||||||
|
|
||||||
|
* impossibilité d'accéder à certaines données sensibles (mot de passe, logs de connexion, etc.)
|
||||||
|
* incitation forte à utiliser les paramètres nommés dans la documentation
|
||||||
|
* protection automatique des variables dans la section `{{#select}}`
|
||||||
|
* fourniture de fonctions pour protéger les chaînes de caractères contre l'injection SQL
|
828
doc/admin/brindille_functions.md
Normal file
828
doc/admin/brindille_functions.md
Normal file
|
@ -0,0 +1,828 @@
|
||||||
|
Title: Référence des fonctions Brindille
|
||||||
|
|
||||||
|
{{{.nav
|
||||||
|
* [Modules](modules.html)
|
||||||
|
* [Documentation Brindille](brindille.html)
|
||||||
|
* **[Fonctions](brindille_functions.html)**
|
||||||
|
* [Sections](brindille_sections.html)
|
||||||
|
* [Filtres](brindille_modifiers.html)
|
||||||
|
}}}
|
||||||
|
|
||||||
|
<<toc aside>>
|
||||||
|
|
||||||
|
# Fonctions généralistes
|
||||||
|
|
||||||
|
## assign
|
||||||
|
|
||||||
|
Permet d'assigner une valeur dans une variable.
|
||||||
|
|
||||||
|
| Paramètre | Optionnel / obligatoire ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `.` | optionnel | Assigner toutes les variables du contexte (section) actuel |
|
||||||
|
| `var` | optionnel | Nom de la variable à créer ou modifier |
|
||||||
|
| `value` | optionnel | Valeur de la variable |
|
||||||
|
| `from` | optionnel | Recopier la valeur depuis la variable ayant le nom fourni dans ce paramètre. |
|
||||||
|
|
||||||
|
Tous les autres paramètres sont considérés comme des variables à assigner.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign blabla="Coucou"}}
|
||||||
|
|
||||||
|
{{$blabla}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est possible d'assigner toutes les variables d'une section dans une variable en utilisant le paramètre point `.` (`.="nom_de_variable"`). Cela permet de capturer le contenu d'une section pour le réutiliser à un autre endroit.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#pages uri="Informations" limit=1}}
|
||||||
|
{{:assign .="infos"}}
|
||||||
|
{{/pages}}
|
||||||
|
|
||||||
|
{{$infos.title}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est aussi possible de remonter dans les sections parentes en utilisant plusieurs points. Ainsi deux points remonteront à la section parente, trois points à la section parente de la section parente, etc.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#foreach from=$infos item="info"}}
|
||||||
|
{{#foreach from=$info item="sous_info"}}
|
||||||
|
{{if $sous_info.titre == 'Coucou'}}
|
||||||
|
{{:assign ..="info_importante"}}
|
||||||
|
{{/if}}
|
||||||
|
{{/foreach}}
|
||||||
|
{{/foreach}}
|
||||||
|
|
||||||
|
{{$info_importante.titre}}
|
||||||
|
```
|
||||||
|
|
||||||
|
En utilisant le paramètre spécial `var`, tous les autres paramètres passés sont ajoutés à la variable donnée en valeur :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="tableau" label="Coucou" name="Pif le chien"}}
|
||||||
|
{{$tableau.label}}
|
||||||
|
{{$tableau.name}}
|
||||||
|
```
|
||||||
|
|
||||||
|
De la même manière on peut écraser une variable avec le paramètre spécial `value`:
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="tableau" value=$infos}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est également possible de créer des tableaux avec la syntaxe `.` dans le nom de la variable :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="liste.comptes.530" label="Caisse"}}
|
||||||
|
{{:assign var="liste.comptes.512" label="Banque"}}
|
||||||
|
|
||||||
|
{{#foreach from=$liste.comptes}}
|
||||||
|
{{$key}} = {{$value.label}}
|
||||||
|
{{/foreach}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est possible de rajouter des éléments à un tableau simplement en utilisant un point seul :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="liste.comptes." label="530 - Caisse"}}
|
||||||
|
{{:assign var="liste.comptes." label="512 - Banque"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Enfin, il est possible de faire référence à une variable de manière dynamique en utilisant le paramètre spécial `from` :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="tableau" a="Coucou" b="Test !"}}
|
||||||
|
{{:assign var="titre" from="tableau.%s"|args:"b"}}
|
||||||
|
{{$titre}} -> Affichera "Test !", soit la valeur de {{$tableau.b}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## break
|
||||||
|
|
||||||
|
Interrompt une section.
|
||||||
|
|
||||||
|
## continue
|
||||||
|
|
||||||
|
Passe à l'itération suivante d'une section. Le code situé entre cette instruction et la fin de la section ne sera pas exécuté.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#foreach from=$list item="event"}}
|
||||||
|
{{if $event.date == '2023-01-01'}}
|
||||||
|
{{:continue}}
|
||||||
|
{{/if}}
|
||||||
|
{{$event.title}}
|
||||||
|
{{/foreach}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est possible de passer à l'itération suivante d'une section parente en utilisant un chiffre en paramètre :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#foreach from=$list item="event"}}
|
||||||
|
{{$event.title}}
|
||||||
|
{{#foreach from=$event.people item="person"}}
|
||||||
|
{{if $person.name == 'bohwaz'}}
|
||||||
|
{{:continue 2}}
|
||||||
|
{{/if}}
|
||||||
|
- {{$person.name}}
|
||||||
|
{{/foreach}}
|
||||||
|
{{/foreach}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## debug
|
||||||
|
|
||||||
|
Cette fonction permet d'afficher le contenu d'une ou plusieurs variables :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:debug test=$title}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Affichera :
|
||||||
|
|
||||||
|
```
|
||||||
|
array(1) {
|
||||||
|
["test"] => string(6) "coucou"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Si aucun paramètre n'est spécifié, alors toutes les variables définies sont renvoyées. Utile pour découvrir quelles sont les variables accessibles dans une section par exemple.
|
||||||
|
|
||||||
|
|
||||||
|
## error
|
||||||
|
|
||||||
|
Affiche un message d'erreur et arrête le traitement à cet endroit.
|
||||||
|
|
||||||
|
| Paramètre | Optionnel / obligatoire ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `message` | **obligatoire** | Message d'erreur à afficher |
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{if $_POST.nombre != 42}}
|
||||||
|
{{:error message="Le nombre indiqué n'est pas 42"}}
|
||||||
|
{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## form_errors
|
||||||
|
|
||||||
|
Affiche les erreurs du formulaire courant (au format HTML).
|
||||||
|
|
||||||
|
## http
|
||||||
|
|
||||||
|
Permet de modifier les entêtes HTTP renvoyés par la page. Cette fonction doit être appelée au tout début du squelette, avant tout autre code ou ligne vide.
|
||||||
|
|
||||||
|
| Paramètre | Optionnel / obligatoire ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `code` | *optionnel* | Modifie le code HTTP renvoyé. [Liste des codes HTTP](https://fr.wikipedia.org/wiki/Liste_des_codes_HTTP) |
|
||||||
|
| `redirect` | *optionnel* | Rediriger vers l'adresse URL indiquée en valeur. |
|
||||||
|
| `type` | *optionnel* | Modifie le type MIME renvoyé |
|
||||||
|
| `download` | *optionnel* | Force la page à être téléchargée sous le nom indiqué. |
|
||||||
|
| `inline` | *optionnel* | Force la page à être affichée, et peut ensuite être téléchargée sous le nom indiqué (utile pour la généraion de PDF : permet d'afficher le PDF dans le navigateur avant de le télécharger). |
|
||||||
|
|
||||||
|
Note : si le type `application/pdf` est indiqué (ou juste `pdf`), la page sera convertie en PDF à la volée. Il est possible de forcer le téléchargement du fichier en utilisant le paramètre `download`.
|
||||||
|
|
||||||
|
Exemples :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:http code=404}}
|
||||||
|
{{:http redirect="/Nos-Activites/"}}
|
||||||
|
{{:http redirect="https://mon-site-web.tld/"}}
|
||||||
|
{{:http type="application/svg+xml"}}
|
||||||
|
{{:http type="pdf" download="liste_membres_ca.pdf"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## include
|
||||||
|
|
||||||
|
Permet d'inclure un autre squelette.
|
||||||
|
|
||||||
|
Paramètres :
|
||||||
|
|
||||||
|
| Paramètre | Optionnel / obligatoire ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `file` | **obligatoire** | Nom du squelette à inclure |
|
||||||
|
| `keep` | *optionnel* | Liste de noms de variables à conserver |
|
||||||
|
| `capture` | *optionnel* | Si renseigné, au lieu d'afficher le squelette, son contenu sera enregistré dans la variable de ce nom. |
|
||||||
|
| … | *optionnel* | Tout autre paramètre sera utilisé comme variable qui n'existea qu'à l'intérieur du squelette inclus. |
|
||||||
|
|
||||||
|
```
|
||||||
|
{{* Affiche le contenu du squelette "navigation.html" dans le même répertoire que le squelette d'origine *}}
|
||||||
|
{{:include file="./navigation.html"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Par défaut, les variables du squelette parent sont transmis au squelette inclus, mais les variables définies dans le squelette inclus ne sont pas transmises au squelette parent. Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{* Squelette page.html *}}
|
||||||
|
{{:assign title="Super titre !"}}
|
||||||
|
{{:include file="./_head.html"}}
|
||||||
|
{{$nav}}
|
||||||
|
```
|
||||||
|
```
|
||||||
|
{{* Squelette _head.html *}}
|
||||||
|
<h1>{{$title}}</h1>
|
||||||
|
{{:assign nav="Accueil > %s"|args:$title}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Dans ce cas, la dernière ligne du premier squelette (`{{$nav}}`) n'affichera rien, car la variable définie dans le second squelette n'en sortira pas. Pour indiquer qu'une variable doit être transmise au squelette parent, il faut utiliser le paramètre `keep`:
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:include file="./_head.html" keep="nav"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
On peut spécifier plusieurs noms de variables, séparés par des virgules, et utiliser la notation à points :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:include file="./_head.html" keep="nav,article.title,name"}}
|
||||||
|
{{$nav}}
|
||||||
|
{{$article.title}}
|
||||||
|
{{$name}}
|
||||||
|
```
|
||||||
|
|
||||||
|
On peut aussi capturer le résultat d'un squelette dans une variable :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:include file="./_test.html" capture="test"}}
|
||||||
|
{{:assign var="test" value=$test|replace:'TITRE':'Ceci est un titre'}}
|
||||||
|
{{$test}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est possible d'assigner de nouvelles variables au contexte du include en les déclarant comme paramètres tout comme on le ferait avec `{{:assign}}` :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:include file="./_head.html" title='%s documentation'|args:$doc.label visitor=$user}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## captcha
|
||||||
|
|
||||||
|
Permet de générer une question qui doit être répondue correctement par l'utilisateur pour valider une action. Utile pour empêcher les robots spammeurs d'effectuer une action.
|
||||||
|
|
||||||
|
L'utilisation simplifiée utilise un de ces deux paramètres :
|
||||||
|
|
||||||
|
| Paramètre | Fonction |
|
||||||
|
| :- | :- |
|
||||||
|
| `html` | Si `true`, crée un élément de formulaire HTML et le texte demandant à l'utilisateur de répondre à la question |
|
||||||
|
| `verify` | Si `true`, vérifie que l'utilisateur a correctement répondu à la question |
|
||||||
|
|
||||||
|
L'utilisation avancée utilise d'abord ces deux paramètres :
|
||||||
|
|
||||||
|
| Paramètre | Fonction |
|
||||||
|
| :- | :- |
|
||||||
|
| `assign_hash` | Nom de la variable où assigner le hash (à mettre dans un `<input type="hidden" />`) |
|
||||||
|
| `assign_number` | Nom de la variable où assigner le nombre de la question (à afficher à l'utilisateur) |
|
||||||
|
|
||||||
|
Puis on vérifie :
|
||||||
|
|
||||||
|
| Paramètre | Fonction |
|
||||||
|
| :- | :- |
|
||||||
|
| `verify_hash` | Valeur qui servira comme hash de vérification (valeur du `<input type="hidden" />`) |
|
||||||
|
| `verify_number` | Valeur qui représente la réponse de l'utilisateur |
|
||||||
|
| `assign_error` | Si spécifié, le message d'erreur sera placé dans cette variable, sinon il sera affiché directement. |
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{if $_POST.send}}
|
||||||
|
{{:captcha verify_hash=$_POST.h verify_number=$_POST.n assign_error="error"}}
|
||||||
|
{{if $error}}
|
||||||
|
<p class="alert">Mauvaise réponse</p>
|
||||||
|
{{else}}
|
||||||
|
...
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<form method="post" action="">
|
||||||
|
{{:captcha assign_hash="hash" assign_number="number"}}
|
||||||
|
<p>Merci de recopier le nombre suivant en chiffres : <tt>{{$number}}</tt></p>
|
||||||
|
<p>
|
||||||
|
<input type="text" name="n" placeholder="1234" />
|
||||||
|
<input type="hidden" name="h" value="{{$hash}}" />
|
||||||
|
<input type="submit" name="send" />
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
```
|
||||||
|
|
||||||
|
## mail
|
||||||
|
|
||||||
|
Permet d'envoyer un e-mail à une ou des adresses indiquées (sous forme de tableau).
|
||||||
|
|
||||||
|
Restrictions :
|
||||||
|
|
||||||
|
* le message est toujours envoyé en format texte ;
|
||||||
|
* l'expéditeur est toujours l'adresse de l'association ;
|
||||||
|
* l'envoi est limité à une seule adresse e-mail externe (adresse qui n'est pas celle d'un membre) dans une page ;
|
||||||
|
* l'envoi est limité à maximum 10 adresses e-mails internes (adresses de membres) dans une page ;
|
||||||
|
* un message envoyé à une adresse e-mail externe ne peut pas contenir une adresse web (`https://...`) autre que celle de l'association.
|
||||||
|
|
||||||
|
Note : il est également conseillé d'utiliser la fonction `captcha` pour empêcher l'envoi de spam.
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `to` | **obligatoire** | Adresse email destinataire (seule l'adresse e-mail elle-même est acceptée, pas de nom) |
|
||||||
|
| `subject` | **obligatoire** | Sujet du message |
|
||||||
|
| `body` | **obligatoire** | Corps du message |
|
||||||
|
| `block_urls` | *optionnel* | (`true` ou `false`) Permet de bloquer l'envoi si le message contient une adresse `https://…` |
|
||||||
|
| `attach_file` | *optionnel* | Chemin vers un ou plusieurs documents à joindre au message (situé dans les documents) |
|
||||||
|
| `attach_from` | *optionnel* | Chemin vers un ou plusieurs squelettes à joindre au message (par exemple pour joindre un document généré) |
|
||||||
|
|
||||||
|
Pour le destinataire, il est possible de spécifier un tableau :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="recipients[]" value="membre1@framasoft.net"}}
|
||||||
|
{{:assign var="recipients[]" value="membre2@chatons.org"}}
|
||||||
|
{{:mail to=$recipients subject="Coucou" body="Contenu du message\nNouvelle ligne"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Exemple de formulaire de contact :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{if !$_POST.email|check_email}}
|
||||||
|
<p class="alert">L'adresse e-mail indiquée est invalide.</p>
|
||||||
|
{{elseif $_POST.message|trim == ''}}
|
||||||
|
<p class="alert">Le message est vide</p>
|
||||||
|
{{elseif $_POST.send}}
|
||||||
|
{{:captcha verify=true}}
|
||||||
|
{{:mail to=$config.org_email subject="Formulaire de contact" body="%s a écrit :\n\n%s"|args:$_POST.email:$_POST.message block_urls=true}}
|
||||||
|
<p class="ok">Votre message nous a bien été transmis !</p>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<form method="post" action="">
|
||||||
|
<dl>
|
||||||
|
<dt><label>Votre e-mail : <input type="email" required name="email" /></label></dt>
|
||||||
|
<dt><label>Votre message : <textarea required name="message" cols="50" rows="5"></textarea></label></dt>
|
||||||
|
<dt>{{:captcha html=true}}</dt>
|
||||||
|
</dl>
|
||||||
|
<p><input type="submit" name="send" value="Envoyer !" /></p>
|
||||||
|
</form>
|
||||||
|
```
|
||||||
|
|
||||||
|
## redirect
|
||||||
|
|
||||||
|
Redirige vers une nouvelle page.
|
||||||
|
|
||||||
|
Avec le paramètre `force`, si la page actuelle est ouverte dans une fenêtre modale (grâce à la cible `_dialog`), alors la fenêtre modale est fermée, et la redirection se passe dans la page parente.
|
||||||
|
|
||||||
|
Avec le paramètre `to`, si la page actuelle est ouverte dans une fenêtre modal (grâce à la cible `_dialog`), alors la fenêtre modale est fermée, et la page parente est rechargée. Si la page n'est pas ouvertre dans dans une fenêtre modale, la redirection est effectuée.
|
||||||
|
|
||||||
|
Seules les adresses internes sont acceptées, il n'est pas possible de rediriger vers une adresse extérieure.
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `force` | optionnel | Adresse de redirection forcée |
|
||||||
|
| `to` | optionnel | Adresse de redirection si pas dans une fenêtre modale |
|
||||||
|
|
||||||
|
Si `to=null` est utilisé, alors la fenêtre modale sera fermée. Ou, si la page n'est pas dans une fenêtre modale, la page courante sera rechargée.
|
||||||
|
|
||||||
|
## api
|
||||||
|
|
||||||
|
Permet d'appeler l'API de Paheko, que ça soit sur l'instance locale, en cours, ou une autre instance externe.
|
||||||
|
|
||||||
|
Voir la [documentation de l'API](https://paheko.cloud/api) pour la liste des fonctions disponibles.
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `method` | obligatoire | Méthode de requête : `GET`, `POST`, etc. |
|
||||||
|
| `path` | obligatoire | Chemin de la méthode de l'API à appeler. |
|
||||||
|
| `fail` | optionnel | Booléen. Si `true`, alors une erreur sera affichée si la requête échoue. Si `false`, aucune erreur ne sera affichée. Défaut : `true`. |
|
||||||
|
| `assign` | optionnel | Capturer le résultat dans cette variable. |
|
||||||
|
| `assign_code` | optionnel | Capturer le code de retour dans cette variable. |
|
||||||
|
|
||||||
|
Par défaut, les requêtes sont réalisées sur la base de données locale, dans ce cas les paramètres suivants sont également disponibles :
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `access` | optionnel | Niveau d'autorisation de l'API (défaut : `admin`). |
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="users." value=42}}
|
||||||
|
{{:api
|
||||||
|
method="POST"
|
||||||
|
path="accounting/transaction"
|
||||||
|
assign="result"
|
||||||
|
|
||||||
|
id_year=1
|
||||||
|
type="revenue"
|
||||||
|
date="01/01/2023"
|
||||||
|
label="Don de Ada Lovelace"
|
||||||
|
reference="DON-0001"
|
||||||
|
payment_reference="Credit Mutuel 00042"
|
||||||
|
amount="51,49"
|
||||||
|
debit="756"
|
||||||
|
credit="512A"
|
||||||
|
linked_users=$users
|
||||||
|
}}
|
||||||
|
|
||||||
|
L'écriture n°{{$result.id}} a été créée.
|
||||||
|
```
|
||||||
|
|
||||||
|
Mais cette fonction permet également d'appeler une API Paheko distante, dans ce cas les paramètres suivants sont nécessaires :
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `url` | obligatoire | Adresse HTTP de l'instance Paheko distante. |
|
||||||
|
| `user` | obligatoire | Identifiant d'accès à l'API distante. |
|
||||||
|
| `password` | obligatoire | Mot de passe d'accès à l'API distante. |
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:api
|
||||||
|
method="POST"
|
||||||
|
path="sql"
|
||||||
|
sql="SELECT * FROM users;"
|
||||||
|
url="https://mon-asso.paheko.cloud/"
|
||||||
|
user="zmgyfr1qnm"
|
||||||
|
password="OAqFTLFzujJWr6lLn1Mu7w"
|
||||||
|
assign="result"
|
||||||
|
assign_code="code"
|
||||||
|
fail=false
|
||||||
|
}}
|
||||||
|
|
||||||
|
{{if $code == 200}}
|
||||||
|
Il y a {{$result.count}} résultats.
|
||||||
|
{{else}}
|
||||||
|
La requête a échoué : code {{$code}} — {{$result.error}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
# Fonctions relatives aux Modules
|
||||||
|
|
||||||
|
## save
|
||||||
|
|
||||||
|
Enregistre des données, sous la forme d'un document, dans la base de données, pour le module courant.
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `key` | optionnel | Clé unique du document |
|
||||||
|
| `id` | optionnel | Numéro unique du document |
|
||||||
|
| `validate_schema` | optionnel | Fichier de schéma JSON à utiliser pour valider les données avant enregistrement |
|
||||||
|
| `validate_only` | optionnel | Liste des paramètres à valider (par exemple pour ne faire qu'une mise à jour partielle), séparés par des virgules. |
|
||||||
|
| `assign_new_id` | optionnel | Si renseigné, le nouveau numéro unique du document sera indiqué dans cette variable. |
|
||||||
|
| … | optionnel | Autres paramètres : traités comme des valeurs à enregistrer dans le document |
|
||||||
|
|
||||||
|
Si ni `key` ni `id` ne sont indiqués, un nouveau document sera créé avec un nouveau numéro (ID) unique.
|
||||||
|
|
||||||
|
Si le document indiqué existe déjà, il sera mis à jour. Les valeurs nulles (`NULL`) seront effacées.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:save key="facture_43" nom="Atelier mobile" montant=250}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Enregistrera dans la base de données le document suivant sous la clé `facture_43` :
|
||||||
|
|
||||||
|
```
|
||||||
|
{"nom": "Atelier mobile", "montant": 250}
|
||||||
|
```
|
||||||
|
|
||||||
|
Exemple de mise à jour :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:save key="facture_43" montant=300}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Exemple de récupération du nouvel ID :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:save titre="Coucou !" assign_new_id="id"}}
|
||||||
|
Le document n°{{$id}} a bien été enregistré.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validation avec un schéma JSON
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:save titre="Coucou" texte="Très long" validate_schema="./document.schema.json"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Pour ne valider qu'une partie du schéma, par exemple si on veut faire une mise à jour du document :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:save key="test" titre="Coucou" validate_schema="./document.schema.json" validate_only="titre"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## delete
|
||||||
|
|
||||||
|
Supprime un document lié au module courant.
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `key` | optionnel | Clé unique du document |
|
||||||
|
| `id` | optionnel | Numéro unique du document |
|
||||||
|
|
||||||
|
Il est possible de spécifier d'autres paramètres, ou une clause `where` et des paramètres dont le nom commence par deux points.
|
||||||
|
|
||||||
|
* Supprimer le document avec la clé `facture_43` : `{{:delete key="facture_43"}}`
|
||||||
|
* Supprimer le document avec la clé `ABCD` et dont la propriété `type` du document correspond à la valeur `facture` : `{{:delete key="ABCD" type="facture"}}`
|
||||||
|
* Supprimer tous les documents : `{{:delete}}`
|
||||||
|
* Supprimer tous les documents ayant le type `facture` : `{{:delete type="facture"}}`
|
||||||
|
* Supprimer tous les documents de type `devis` ayant une date dans le passé : `{{:delete :type="devis" where="$$.type = :type AND $$.date < datetime()"}}`
|
||||||
|
|
||||||
|
## read
|
||||||
|
|
||||||
|
Lire un fichier stocké dans les fichiers du code du module.
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `file` | obligatoire | Chemin du fichier à lire |
|
||||||
|
| `assign` | optionnel | Variable dans laquelle placer le contenu du fichier. |
|
||||||
|
|
||||||
|
Si le paramètre `assign` n'est pas utilisé, le contenu du fichier sera affiché directement.
|
||||||
|
|
||||||
|
Exemple pour lire un fichier JSON :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#read file="baremes.json" assign="baremes"}}
|
||||||
|
{{:assign baremes=$baremes|json_decode}}
|
||||||
|
Barème kilométrique pour une voiture de 3 CV : {{$baremes.voiture.3cv}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Exemple pour lire un fichier CSV :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#read file="baremes.csv" assign="baremes"}}
|
||||||
|
{{:assign baremes=$baremes|trim|explode:"\n"}}
|
||||||
|
|
||||||
|
{{#foreach from=$baremes item="line"}}
|
||||||
|
{{:assign bareme=$line|str_getcsv}}
|
||||||
|
Nom du barème : {{$bareme.0}}
|
||||||
|
Calcul : {{$bareme.1}}
|
||||||
|
{{/foreach}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## admin_header
|
||||||
|
|
||||||
|
Affiche l'entête de l'administration de l'association.
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `title` | *optionnel* | Titre de la page |
|
||||||
|
| `layout` | *optionnel* | Aspect de la page. Peut être `public` pour une page publique simple (sans le menu), ou `raw` pour une page vierge (sans aucun menu ni autre élément). Défaut : vide (affichage du menu) |
|
||||||
|
| `current` | *optionnel* | Indique quel élément dans le menu de gauche doit être marqué comme sélectionné |
|
||||||
|
| `custom_css` | *optionnel* | Fichier CSS supplémentaire à appeler dans le `<head>` |
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:admin_header title="Gestion des dons" current="acc"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Liste des choix possibles pour `current` :
|
||||||
|
|
||||||
|
* `home` : menu Accueil
|
||||||
|
* `users` : menu Membres
|
||||||
|
* `users/new` : sous-menu "Ajouter" de Membres
|
||||||
|
* `users/services` : sous-menu "Activités et cotisations" de Membres
|
||||||
|
* `users/mailing` : sous-menu "Message collectif" de Membres
|
||||||
|
* `acc` : menu Comptabilité
|
||||||
|
* `acc/new` : sous-menu "Saisie" de Comptabilité
|
||||||
|
* `acc/accounts` : sous-menu "Comptes"
|
||||||
|
* `acc/simple` : sous-menu "Suivi des écritures"
|
||||||
|
* `acc/years` : sous-menu "Exercices et rapports"
|
||||||
|
* `docs` : menu Documents
|
||||||
|
* `web` : menu Site web
|
||||||
|
* `config` : menu Configuration
|
||||||
|
* `me` : menu "Mes infos personnelles"
|
||||||
|
* `me/services` : sous-menu "Mes activités et cotisations"
|
||||||
|
|
||||||
|
Exemple d'utilisation de `custom_css` depuis un module :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:admin_header title="Mon module" custom_css="./style.css"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## admin_footer
|
||||||
|
|
||||||
|
Affiche le pied de page de l'administration de l'association.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:admin_footer}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## delete_form
|
||||||
|
|
||||||
|
Affiche un formulaire demandant la confirmation de suppression d'un élément.
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `legend` | **obligatoire** | Libellé de l'élément `<legend>` du formulaire |
|
||||||
|
| `warning` | **obligatoire** | Libellé de la question de suppression (en gros en rouge) |
|
||||||
|
| `alert` | *optionnel* | Message d'alerte supplémentaire (bloc jaune) |
|
||||||
|
| `info` | *optionnel* | Informations liées à la suppression (expliquant ce qui va être impacté par la suppression) |
|
||||||
|
| `confirm` | *optionnel* | Libellé de la case à cocher pour la suppression, si ce paramètre est absent ou `NULL`, la case à cocher ne sera pas affichée. |
|
||||||
|
|
||||||
|
Le formulaire envoie un `POST` avec le bouton ayant le nom `delete`. Si le paramètre `confirm` est renseigné, alors la case à cochée aura le nom `confirm_delete`.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#load id=$_GET.id assign="invoice"}}
|
||||||
|
{{else}}
|
||||||
|
{{:error message="Facture introuvable"}}
|
||||||
|
{{/load}}
|
||||||
|
|
||||||
|
{{#form on="delete"}}
|
||||||
|
{{if !$_POST.confirm_delete}}
|
||||||
|
{{:error message="Merci de cocher la case"}}
|
||||||
|
{{/if}}
|
||||||
|
{{:delete id=$invoice.id}}
|
||||||
|
{{/form}}
|
||||||
|
|
||||||
|
{{:form_errors}}
|
||||||
|
|
||||||
|
{{:delete_form
|
||||||
|
legend="Suppression d'une facture"
|
||||||
|
warning="Supprimer la facture n°%d ?"|args:$invoice.id
|
||||||
|
info="Le devis lié sera également supprimé"
|
||||||
|
alert="La facture sera définitivement perdue !"
|
||||||
|
confirm="Cocher cette case pour confirmer la suppression de la facture"
|
||||||
|
}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## input
|
||||||
|
|
||||||
|
Crée un champ de formulaire HTML. Cette fonction est une extension à la balise `<input>` en HTML, mais permet plus de choses.
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `name` | **obligatoire** | Nom du champ |
|
||||||
|
| `type` | **obligatoire** | Type de champ |
|
||||||
|
| `required` | *optionnel* | Mettre à `true` si le champ est obligatoire |
|
||||||
|
| `label` | *optionnel* | Libellé du champ |
|
||||||
|
| `help` | *optionnel* | Texte d'aide, affiché sous le champ |
|
||||||
|
| `default` | *optionnel* | Valeur du champ par défaut, si le formulaire n'a pas été envoyé, et que la valeur dans `source` est vide |
|
||||||
|
| `source` | *optionnel* | Source de pré-remplissage du champ. Si le nom du champ est `montant`, alors la valeur de `[source].montant` sera affichée si présente. |
|
||||||
|
|
||||||
|
Si `label` ou `help` sont spécifiés, le champ sera intégré à une balise HTML `<dd>`, et le libellé sera intégré à une balise `<dt>`. Dans ce cas il faut donc que le champ soit dans une liste `<dl>`. Si ces deux paramètres ne sont pas spécifiés, le champ sera le seul tag HTML.
|
||||||
|
|
||||||
|
```
|
||||||
|
<dl>
|
||||||
|
{{:input name="amount" type="money" label="Montant" required=true}}
|
||||||
|
</dl>
|
||||||
|
```
|
||||||
|
|
||||||
|
Note : le champ aura comme `id` la valeur `f_[name]`. Ainsi un champ avec `amount` comme `name` aura `id="f_amount"`.
|
||||||
|
|
||||||
|
### Valeur du champ
|
||||||
|
|
||||||
|
La valeur du champ est remplie avec :
|
||||||
|
|
||||||
|
* la valeur dans `$_POST` qui correspond au `name` ;
|
||||||
|
* sinon la valeur dans `source` (tableau) avec le même nom (exemple : `$source[name]`) ;
|
||||||
|
* sinon la valeur de `default` est utilisée.
|
||||||
|
|
||||||
|
Note : le paramètre `value` n'est pas supporté sauf pour checkbox et radio.
|
||||||
|
|
||||||
|
### Types de champs supportés
|
||||||
|
|
||||||
|
* les types classiques de `input` en HTML : text, search, email, url, file, date, checkbox, radio, password, etc.
|
||||||
|
* Note : pour checkbox et radio, il faut utiliser le paramètre `value` en plus pour spécifier la valeur.
|
||||||
|
* `textarea`
|
||||||
|
* `money` créera un champ qui attend une valeur de monnaie au format décimal
|
||||||
|
* `datetime` créera un champ date et un champ texte pour entrer l'heure au format `HH:MM`
|
||||||
|
* `radio-btn` créera un champ de type radio mais sous la forme d'un gros bouton
|
||||||
|
* `select` crée un sélecteur de type `<select>`. Dans ce cas il convient d'indiquer un tableau associatif dans le paramètre `options`.
|
||||||
|
* `select_groups` crée un sélecteur de type `<select>`, mais avec des `<optgroup>`. Dans ce cas il convient d'indiquer un tableau associatif à deux niveaux dans le paramètre `options`.
|
||||||
|
* `list` crée un champ permettant de sélectionner un ou des éléments (selon si le paramètre `multiple` est `true` ou `false`) dans un formulaire externe. Le paramètre `can_delete` indique si l'utilisateur peut supprimer l'élément déjà sélectionné (si `multiple=false`). La sélection se fait à partir d'un formulaire dont l'URL doit être spécifiée dans le paramètre `target`. Les formulaires actuellement supportés sont :
|
||||||
|
* `!acc/charts/accounts/selector.php?targets=X` pour sélectionner un compte du plan comptable, où X est une liste de types de comptes qu'il faut permettre de choisir (séparés par des `:`)
|
||||||
|
* `!users/selector.php` pour sélectionner un membre
|
||||||
|
|
||||||
|
## button
|
||||||
|
|
||||||
|
Affiche un bouton, similaire à `<button>` en HTML, mais permet d'ajouter une icône par exemple.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:button type="submit" name="save" label="Créer ce membre" shape="plus" class="main"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `type` | optionnel | Type du bouton |
|
||||||
|
| `name` | optionnel | Nom du bouton |
|
||||||
|
| `label` | optionnel | Label du bouton |
|
||||||
|
| `shape` | optionnel | Affiche une icône en préfixe du label |
|
||||||
|
| `class` | optionnel | Classe CSS |
|
||||||
|
| `title` | optionnel | Attribut HTML `title` |
|
||||||
|
| `disabled` | optionnel | Désactive le bouton si `true` |
|
||||||
|
|
||||||
|
|
||||||
|
## link
|
||||||
|
|
||||||
|
Affiche un lien.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:link href="!users/new.php" label="Créer un nouveau membre"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `href` | **obligatoire** | Adresse du lien |
|
||||||
|
| `label` | **obligatoire** | Libellé du lien |
|
||||||
|
| `target` | *optionnel* | Cible du lien, utiliser `_dialog` pour que le lien s'ouvre dans une fenêtre modale. |
|
||||||
|
|
||||||
|
|
||||||
|
Préfixer l'adresse par "!" donnera une URL absolue en préfixant l'adresse par l'URL de l'administration.
|
||||||
|
Sans "!", l'adresse générée sera relative au contexte d'appel (module/plugin ou squelette site web).
|
||||||
|
|
||||||
|
|
||||||
|
## linkbutton
|
||||||
|
|
||||||
|
Affiche un lien sous forme de faux bouton, avec une icône si le paramètre `shape` est spécifié.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:linkbutton href="!users/new.php" label="Créer un nouveau membre" shape="plus"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `href` | **obligatoire* | Adresse du lien |
|
||||||
|
| `label` | **obligatoire** | Libellé du bouton |
|
||||||
|
| `target` | *optionnel* | Cible de l'ouverture du lien |
|
||||||
|
| `shape` | *optionnel* | Affiche une icône en préfixe du label |
|
||||||
|
|
||||||
|
Si on utilise `target="_dialog"` alors le lien s'ouvrira dans une fenêtre modale (iframe) par dessus la page actuelle.
|
||||||
|
|
||||||
|
Si on utilise `target="_blank"` alors le lien s'ouvrira dans un nouvel onglet.
|
||||||
|
|
||||||
|
## icon
|
||||||
|
|
||||||
|
Affiche une icône.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:icon shape="print"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `shape` | **obligatoire** | Forme de l'icône. |
|
||||||
|
|
||||||
|
|
||||||
|
### Formes d'icônes disponibles
|
||||||
|
|
||||||
|
![](shapes.png)
|
||||||
|
|
||||||
|
## user_field
|
||||||
|
|
||||||
|
Affiche un champ de la fiche membre.
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `name` | **obligatoire** | Nom du champ. |
|
||||||
|
| `value` | **obligatoire** | Valeur du champ. |
|
||||||
|
|
||||||
|
## edit_user_field
|
||||||
|
|
||||||
|
Afficher un champ de formulaire pour modifier un champ de la fiche membre.
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `name` | **obligatoire** | Nom du champ. |
|
||||||
|
| `source` | *optionnel* | Source de pré-remplissage du champ. Si le nom du champ est `montant`, alors la valeur de `[source].montant` sera utilisée comme valeur du champ. |
|
||||||
|
|
||||||
|
# Gestion de fichiers dans les modules
|
||||||
|
|
||||||
|
Les modules peuvent stocker des fichiers, mais seulement dans leur propre contexte. Un module ne peut pas gérer les fichiers du site web, des écritures comptables, des membres, ou des autres modules, il ne peut gérer que ses propres fichiers.
|
||||||
|
|
||||||
|
Quand les données d'un module sont supprimé, les fichiers du module sont aussi supprimés.
|
||||||
|
|
||||||
|
Mais si le module stocke des fichiers liés à un document JSON (par exemple dans un sous-répertoire pour chaque module), c'est au code du module de s'assurer que les fichiers seront supprimés lors de la suppression du document.
|
||||||
|
|
||||||
|
Par défaut, tous les fichiers des modules sont en accès restreint : ils ne peuvent être vus et modifiés que par les membres connectés qui sont au niveau d'accès indiqué dans les paramètres `restrict_section` et `restrict_level` du fichier `module.ini`.
|
||||||
|
|
||||||
|
Pour qu'un fichier soit visible publiquement aux personnes non connectées, il faut le placer dans le sous-répertoire `public` du module.
|
||||||
|
|
||||||
|
Attention : de par ce fonctionnement, **tous les fichiers** d'un module sont potentiellement accessibles par **tous les membres ayant accès au module** et connaissant le nom du fichier.
|
||||||
|
|
||||||
|
Il est donc recommandé de ne pas utiliser ce mécanisme pour stocker des données personnelles ou des données sensibles.
|
||||||
|
|
||||||
|
## admin_files
|
||||||
|
|
||||||
|
Affiche (dans le contexte de l'administration) la liste des fichiers dans un sous-répertoire, et éventuellement la possibilité d'en ajouter ou de les supprimer.
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `path` | optionnel | Chemin du sous-répertoire où sont stockés les fichiers |
|
||||||
|
| `upload` | optionnel | Booléen. Si `true`, l'utilisateur pourra ajouter des fichiers. (Défaut : `false`) |
|
||||||
|
| `edit` | optionnel | Booléen. Si `true`, l'utilisateur pourra modifier ou supprimer les fichiers existants. (Défaut : `false`) |
|
||||||
|
| `use_trash` | optionnel | Booléen. Si `false`, le fichier sera supprimé, sans passer par la corbeille. Défaut : `true` |
|
||||||
|
|
||||||
|
Exemple pour afficher la liste des fichiers du sous-répertoire `facture43` et permettre de rajouter de nouveaux fichiers :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:admin_files path="facture43" upload=true edit=false}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## delete_file
|
||||||
|
|
||||||
|
Supprimer un fichier ou un répertoire lié au module courant.
|
||||||
|
|
||||||
|
| Paramètre | Obligatoire ou optionnel ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `path` | obligatoire | Chemin du fichier ou répertoire |
|
||||||
|
|
||||||
|
Exemple pour supprimer un fichier seul :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:delete_file path="facture43/justificatif.pdf"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Pour supprimer un répertoire et tous les fichiers dedans :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:delete_file path="facture43"}}
|
||||||
|
```
|
785
doc/admin/brindille_modifiers.md
Normal file
785
doc/admin/brindille_modifiers.md
Normal file
|
@ -0,0 +1,785 @@
|
||||||
|
Title: Référence des filtres Brindille
|
||||||
|
|
||||||
|
{{{.nav
|
||||||
|
* [Modules](modules.html)
|
||||||
|
* [Documentation Brindille](brindille.html)
|
||||||
|
* [Fonctions](brindille_functions.html)
|
||||||
|
* [Sections](brindille_sections.html)
|
||||||
|
* **[Filtres](brindille_modifiers.html)**
|
||||||
|
}}}
|
||||||
|
|
||||||
|
<<toc aside>>
|
||||||
|
|
||||||
|
# Filtres PHP
|
||||||
|
|
||||||
|
Ces filtres viennent directement de PHP et utilisent donc les mêmes paramètres. Voir la documentation PHP pour plus de détails.
|
||||||
|
|
||||||
|
| Nom | Description | Documentation PHP |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `htmlentities` | Convertit tous les caractères éligibles en entités HTML | [Documentation PHP](https://www.php.net/htmlentities) |
|
||||||
|
| `htmlspecialchars` | Convertit les caractères spéciaux en entités HTML | [Documentation PHP](https://www.php.net/htmlspecialchars) |
|
||||||
|
| `trim` | Supprime les espaces et lignes vides au début et à la fin d'un texte | [Documentation PHP](https://www.php.net/trim) |
|
||||||
|
| `ltrim` | Supprime les espaces et lignes vides au début d'un texte | [Documentation PHP](https://www.php.net/ltrim) |
|
||||||
|
| `rtrim` | Supprime les espaces et lignes vides à la fin d'un texte | [Documentation PHP](https://www.php.net/rtrim) |
|
||||||
|
| `md5` | Génère un hash MD5 d'un texte | [Documentation PHP](https://www.php.net/md5) |
|
||||||
|
| `sha1` | Génère un hash SHA1 d'un texte | [Documentation PHP](https://www.php.net/sha1) |
|
||||||
|
| `strlen` | Nombre de caractères dans une chaîne de texte | [Documentation PHP](https://www.php.net/strlen) |
|
||||||
|
| `strpos` | Position d'un élément dans une chaîne de texte | [Documentation PHP](https://www.php.net/strpos) |
|
||||||
|
| `strrpos` | Position d'un dernier élément dans une chaîne de texte | [Documentation PHP](https://www.php.net/strrpos) |
|
||||||
|
| `substr` | Découpe une chaîne de caractère | [Documentation PHP](https://www.php.net/substr) |
|
||||||
|
| `strtotime` | Transforme une date en timestamp UNIX | [Documentation PHP](https://www.php.net/strtotime) |
|
||||||
|
| `strip_tags` | Supprime les tags HTML | [Documentation PHP](https://www.php.net/strip_tags) |
|
||||||
|
| `nl2br` | Remplace les retours à la ligne par des tags HTML `<br/>` | [Documentation PHP](https://www.php.net/nl2br) |
|
||||||
|
| `wordwrap` | Ajoute des retours à la ligne tous les 75 caractères | [Documentation PHP](https://www.php.net/wordwrap) |
|
||||||
|
| `abs` | Renvoie la valeur absolue d'un nombre (exemple : -42 sera transformé en 42) | [Documentation PHP](https://www.php.net/abs) |
|
||||||
|
| `gettype` | Renvoie le type d'une variable | |
|
||||||
|
| `intval` | Transforme une valeur en entier (integer) | [Documentation PHP](https://www.php.net/intval) |
|
||||||
|
| `boolval` | Transforme une valeur en booléen (true ou false) | [Documentation PHP](https://www.php.net/boolval) |
|
||||||
|
| `floatval` | Transforme une valeur en nombre flottant (à virgule) | [Documentation PHP](https://www.php.net/floatval) |
|
||||||
|
| `strval` | Transforme une valeur en chaîne de texte | [Documentation PHP](https://www.php.net/strval) |
|
||||||
|
| `arrayval` | Transforme une valeur en tableau | [Documentation PHP](https://www.php.net/manual/fr/language.types.type-juggling.php) |
|
||||||
|
| `json_decode` | Transforme une chaîne JSON en valeur | [Documentation PHP](https://www.php.net/json_decode) |
|
||||||
|
| `json_encode` | Transforme une valeur en chaîne JSON | [Documentation PHP](https://www.php.net/json_encode) |
|
||||||
|
| `http_build_query` | Transformer un tableau en chaîne *query string* pour URL | [Documentation PHP](https://www.php.net/http_build_query) |
|
||||||
|
| `str_getcsv` | Transformer une chaîne de texte de format CSV en tableau | [Documentation PHP](https://www.php.net/str_getcsv) |
|
||||||
|
|
||||||
|
# Filtres utiles pour les e-mails
|
||||||
|
|
||||||
|
## check_email
|
||||||
|
|
||||||
|
Permet de vérifier la validité d'une adresse email. Cette fonction vérifie la syntaxe de l'adresse mais aussi que le nom de domaine indiqué possède bien un enregistrement de type MX.
|
||||||
|
|
||||||
|
Renvoie `true` si l'adresse est valide.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{if !$_POST.email|check_email}}
|
||||||
|
<p class="alert">L'adresse e-mail indiquée est invalide.</p>
|
||||||
|
{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## protect_contact
|
||||||
|
|
||||||
|
Crée un lien protégé pour une adresse email, pour éviter que l'adresse ne soit recueillie par les robots spammeurs (empêche également le copier-coller et le lien ne fonctionnera pas avec javascript désactivé).
|
||||||
|
|
||||||
|
# Filtres de tableaux
|
||||||
|
|
||||||
|
## has
|
||||||
|
|
||||||
|
Renvoie vrai si le tableau contient l'élément passé en paramètre.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="table" a="bleu" b="orange"}}
|
||||||
|
{{if $table|has:"bleu"}}
|
||||||
|
Oui, il y a du bleu
|
||||||
|
{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## in
|
||||||
|
|
||||||
|
Renvoie vrai si l'élément fait partie du tableau passé en paramètre.
|
||||||
|
|
||||||
|
C'est exactement la même chose que `has`, mais exprimé à l'envers.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="table" a="bleu" b="orange"}}
|
||||||
|
{{if "bleu"|in:$table}}
|
||||||
|
Oui, il y a du bleu
|
||||||
|
{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## has_key
|
||||||
|
|
||||||
|
Renvoie vrai si le tableau contient la clé passée en paramètre.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="table" a="bleu" b="orange"}}
|
||||||
|
{{if $table|has_key:"b"}}
|
||||||
|
Oui, il y a la clé "b"
|
||||||
|
{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## key_in
|
||||||
|
|
||||||
|
Renvoie vrai si la clé fait partie du tableau passé en paramètre.
|
||||||
|
|
||||||
|
C'est exactement la même chose que `has_key`, mais exprimé à l'envers.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="table" a="bleu" b="orange"}}
|
||||||
|
{{if "b"|key_in:$table}}
|
||||||
|
Oui, il y a la clé "b"
|
||||||
|
{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## keys
|
||||||
|
|
||||||
|
Renvoie les clés du tableau, sous forme de tableau.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="table" a="bleu" b="orange"}}
|
||||||
|
{{:assign var="cles" value=$table|keys}}
|
||||||
|
{{$cles|implode:","}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Donnera :
|
||||||
|
|
||||||
|
```
|
||||||
|
a,b
|
||||||
|
```
|
||||||
|
|
||||||
|
## values
|
||||||
|
|
||||||
|
Renvoie les valeurs du tableau, sous forme de tableau.
|
||||||
|
|
||||||
|
Cela revient en fait à supprimer les clés associatives.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="table" a="bleu" b="orange"}}
|
||||||
|
{{#foreach from=$table key="cle" item="valeur"}}
|
||||||
|
{{$cle}} = {{$valeur}}
|
||||||
|
{{/foreach}}
|
||||||
|
--
|
||||||
|
{{:assign var="valeurs" value=$table|values}}
|
||||||
|
{{#foreach from=$valeurs key="cle" item="valeur"}}
|
||||||
|
{{$cle}} = {{$valeur}}
|
||||||
|
{{/foreach}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Donnera :
|
||||||
|
|
||||||
|
```
|
||||||
|
a = bleu
|
||||||
|
b = orange
|
||||||
|
--
|
||||||
|
0 = bleu
|
||||||
|
1 = orange
|
||||||
|
```
|
||||||
|
|
||||||
|
## count
|
||||||
|
|
||||||
|
Compte le nombre d'entrées dans un tableau.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{$products|count}}
|
||||||
|
= 5
|
||||||
|
```
|
||||||
|
|
||||||
|
## explode
|
||||||
|
|
||||||
|
Sépare une chaîne de texte en tableau à partir d'une chaîne de séparation.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="table" value="a,b,c"|explode:","}}
|
||||||
|
- {{$table.0}}
|
||||||
|
- {{$table.1}}
|
||||||
|
- {{$table.2}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Affichera :
|
||||||
|
|
||||||
|
```
|
||||||
|
- a
|
||||||
|
- b
|
||||||
|
- c
|
||||||
|
```
|
||||||
|
|
||||||
|
## implode
|
||||||
|
|
||||||
|
Réunit un tableau sous forme de chaîne de texte en utilisant éventuellement une chaîne de liaison entre chaque élément du tableau.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="table" a="bleu" b="orange"}}
|
||||||
|
{{$table|implode}}
|
||||||
|
{{$table|implode:" - "}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Affichera :
|
||||||
|
|
||||||
|
```
|
||||||
|
bleuorange
|
||||||
|
bleu - orange
|
||||||
|
```
|
||||||
|
|
||||||
|
## map
|
||||||
|
|
||||||
|
Applique un filtre sur chaque élément du tableau.
|
||||||
|
|
||||||
|
Le premier paramètre doit être le nom du filtre. Les autres paramètres seront passés au filtre.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="table" a="01" b="02"}}
|
||||||
|
{{:assign var="table" value=$table|map:intval}}
|
||||||
|
- {{$table.a}}
|
||||||
|
- {{$table.b}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Affichera :
|
||||||
|
|
||||||
|
```
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
```
|
||||||
|
|
||||||
|
## ksort, sort
|
||||||
|
|
||||||
|
Trie un tableau par ordre alpha-numérique, sans tenir compte des majuscules/minuscules. `ksort` trie le tableau en utilisant les clés, et `sort` trie le tableau en utilisant les valeurs.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="table" b="3" a="2" c="1"}}
|
||||||
|
{{$table|sort|implode:","}}
|
||||||
|
{{$table|ksort|implode:","}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Affichera :
|
||||||
|
|
||||||
|
```
|
||||||
|
1,2,3
|
||||||
|
2,3,1
|
||||||
|
```
|
||||||
|
|
||||||
|
## max, min
|
||||||
|
|
||||||
|
Renvoie respectivement la valeur la plus haute ou la plus basse d'un tableau de valeurs numériques.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="table" b="3" a="2" c="1"}}
|
||||||
|
{{$table|max}}
|
||||||
|
{{$table|min}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Affichera :
|
||||||
|
|
||||||
|
```
|
||||||
|
3
|
||||||
|
1
|
||||||
|
```
|
||||||
|
|
||||||
|
# Filtres de texte
|
||||||
|
|
||||||
|
## args
|
||||||
|
|
||||||
|
Remplace des arguments dans le texte selon le schéma utilisé par [sprintf](https://www.php.net/sprintf).
|
||||||
|
|
||||||
|
```
|
||||||
|
{{"Il y a %d résultats dans la recherche sur le terme '%s'."|args:$results_count:$query}}
|
||||||
|
= Il y a 5 résultat dans la recherche sur le terme 'test'.
|
||||||
|
```
|
||||||
|
|
||||||
|
## cat
|
||||||
|
|
||||||
|
Concaténer un texte avec un autre.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{"Tangerine"|cat:" Dream"}}
|
||||||
|
= Tangerine Dream
|
||||||
|
```
|
||||||
|
|
||||||
|
## count_words
|
||||||
|
|
||||||
|
Compte le nombre de mots dans un texte.
|
||||||
|
|
||||||
|
## escape
|
||||||
|
|
||||||
|
Échappe le contenu pour un usage dans un document HTML. Ce filtre est appliqué par défaut à tout ce qui est affiché (variables, etc.) sauf à utiliser le filtre `raw` (voir plus bas).
|
||||||
|
|
||||||
|
## excerpt
|
||||||
|
|
||||||
|
Produit un extrait d'un texte.
|
||||||
|
|
||||||
|
Supprime les tags HTML, tronque au nombre de caractères indiqué en second argument (si rien n'est indiqué, alors 600 est utilisé), et englobe dans un paragraphe `<p>...</p>`.
|
||||||
|
|
||||||
|
Équivalent de :
|
||||||
|
|
||||||
|
```
|
||||||
|
<p>{{$html|strip_tags|truncate:600|nl2br}}</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
## extract_leading_number
|
||||||
|
|
||||||
|
Extrait le numéro au début d'une chaîne de texte.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign title="02. Cours sur la physique nucléaire"}}
|
||||||
|
{{$title|extract_leading_number}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Affichera :
|
||||||
|
|
||||||
|
```
|
||||||
|
02
|
||||||
|
```
|
||||||
|
|
||||||
|
## format_phone_number
|
||||||
|
|
||||||
|
Formatte un numéro de téléphone selon le format du pays de l'association.
|
||||||
|
|
||||||
|
Seule la France est supportée pour le moment.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign number="0102030405"}}
|
||||||
|
{{$number|format_phone_number}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Affichera :
|
||||||
|
|
||||||
|
```
|
||||||
|
01 02 03 04 05
|
||||||
|
```
|
||||||
|
|
||||||
|
## markdown
|
||||||
|
|
||||||
|
Transforme un texte en HTML en utilisant la syntaxe Markdown.
|
||||||
|
|
||||||
|
Il est conseillé de rajouter le filtre `|raw` pour ne pas échapper le HTML produit, si on veut afficher le texte formatté dans une page HTML.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{$texte|markdown|raw}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## raw
|
||||||
|
|
||||||
|
Passer ce filtre désactive la protection automatique contre le HTML (échappement) dans le texte. À utiliser en connaissance de cause avec les contenus qui contiennent du HTML et sont déjà filtrés !
|
||||||
|
|
||||||
|
```
|
||||||
|
{{"<b>Test"}} = <b>Test
|
||||||
|
{{"<b>Test"|raw}} = <b>Test
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## replace
|
||||||
|
|
||||||
|
Remplace des parties du texte par une autre partie.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{"Tata yoyo"|replace:"yoyo":"yaya"}}
|
||||||
|
= Tata yaya
|
||||||
|
```
|
||||||
|
|
||||||
|
## regexp_replace
|
||||||
|
|
||||||
|
Remplace des valeurs en utilisant une expression rationnelles (regexp) ([documentation PHP](https://www.php.net/manual/fr/regexp.introduction.php)).
|
||||||
|
|
||||||
|
```
|
||||||
|
{{"Tartagueule"|regexp_replace:"/ta/i":"tou"}}
|
||||||
|
= tourtougueule
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## remove_leading_number
|
||||||
|
|
||||||
|
Supprime le numéro au début d'un titre.
|
||||||
|
|
||||||
|
Cela permet de définir un ordre spécifique aux pages et catégories dans les listes.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{"03. Beau titre"|remove_leading_number}}
|
||||||
|
Beau titre
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## truncate
|
||||||
|
|
||||||
|
Tronque un texte à une longueur définie.
|
||||||
|
|
||||||
|
| Argument | Fonction | Valeur par défaut (si omis) |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| 1 | longueur en nombre de caractères | 80 |
|
||||||
|
| 2 | texte à placer à la fin (si tronqué) | … |
|
||||||
|
| 3 | coupure stricte, si `true` alors un mot pourra être coupé en deux, si `false` le texte sera coupé au dernier mot complet | `false` |
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign texte="Ceci n'est pas un texte."}}
|
||||||
|
{{$texte|truncate:19:"(...)":true}}
|
||||||
|
{{$texte|truncate:19:"":false}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Affichera :
|
||||||
|
|
||||||
|
```
|
||||||
|
Ceci n'est pas un (...)
|
||||||
|
Ceci n'est pas un t
|
||||||
|
```
|
||||||
|
|
||||||
|
## typo
|
||||||
|
|
||||||
|
Formatte un texte selon les règles typographiques françaises : ajoute des espaces insécables devant ou derrière les ponctuations françaises (`« » ? ! :`).
|
||||||
|
|
||||||
|
## urlencode
|
||||||
|
|
||||||
|
Encode une chaîne de texte pour utilisation dans une adresse URL (alias de `rawurlencode` en PHP).
|
||||||
|
|
||||||
|
## xml_escape
|
||||||
|
|
||||||
|
Échappe le contenu pour un usage dans un document XML.
|
||||||
|
|
||||||
|
## Autres filtres de texte
|
||||||
|
|
||||||
|
Les filtres suivants modifient la casse (majuscule/minuscules) d'un texte et ne fonctionneront correctement que si l'extension `mbstring` est installée sur le serveur. Sinon les lettres accentuées ne seront pas modifiées.
|
||||||
|
|
||||||
|
Note : il est donc préférable d'utiliser la propriété CSS [`text-transform`](https://developer.mozilla.org/en-US/docs/Web/CSS/text-transform) pour modifier la casse si l'usage n'est que pour l'affichage, et non pas pour enregistrer les données.
|
||||||
|
|
||||||
|
* `tolower` : transforme un texte en minuscules
|
||||||
|
* `toupper` : transforme un texte en majuscules
|
||||||
|
* `ucfirst` : met la première lettre du texte en majuscule
|
||||||
|
* `ucwords` : met la première lettre de chaque mot en majuscule
|
||||||
|
* `lcfirst` : met la première lettre du texte en minuscule
|
||||||
|
|
||||||
|
# Filtres sur les sommes en devises
|
||||||
|
|
||||||
|
## money
|
||||||
|
|
||||||
|
Formatte une valeur de monnaie pour l'affichage.
|
||||||
|
|
||||||
|
Une valeur de monnaie doit **toujours** inclure les cents (exprimée sous forme d'entier). Ainsi `15,02` doit être exprimée sous la forme `1502`.
|
||||||
|
|
||||||
|
Paramètres optionnels :
|
||||||
|
|
||||||
|
1. `true` (défaut) pour ne rien afficher si la valeur est zéro, ou `false` pour afficher `0,00`
|
||||||
|
2. `true` pour afficher le signe `+` si le nombre est positif (`-` est toujours affiché si le nombre est négatif)
|
||||||
|
|
||||||
|
```
|
||||||
|
{{* 12 345,67 = 1234567 *}}
|
||||||
|
{{:assign amount=1234567}}
|
||||||
|
{{$amount|money}}
|
||||||
|
12 345,67
|
||||||
|
```
|
||||||
|
|
||||||
|
## money_currency
|
||||||
|
|
||||||
|
Comme `money` (même paramètres), formatte une valeur de monnaie (entier) pour affichage, mais en ajoutant la devise.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign amount=1502}}
|
||||||
|
{{$amount|money_currency}}
|
||||||
|
15,02 €
|
||||||
|
```
|
||||||
|
|
||||||
|
## money_html
|
||||||
|
|
||||||
|
Idem que `money`, mais pour l'affichage en HTML :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{* 12 345,67 = 1234567 *}}
|
||||||
|
{{:assign amount=1234567}}
|
||||||
|
{{$amount|money_html}}
|
||||||
|
<span class="money">12 345,67</span>
|
||||||
|
```
|
||||||
|
|
||||||
|
## money_currency_html
|
||||||
|
|
||||||
|
Idem que `money_currency`, mais pour l'affichage en HTML :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign amount=1502}}
|
||||||
|
{{$amount|money_currency_html}}
|
||||||
|
<span class="money">15,02 €</span>
|
||||||
|
```
|
||||||
|
|
||||||
|
## money_raw
|
||||||
|
|
||||||
|
Formatte une valeur de monnaie (entier) de manière brute : les milliers n'auront pas de séparateur.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign amount=1234567}}
|
||||||
|
{{$amount|money_raw}}
|
||||||
|
12345,67
|
||||||
|
```
|
||||||
|
|
||||||
|
## money_int
|
||||||
|
|
||||||
|
Transforme un nombre à partir d'une chaîne de caractère (par exemple `12345,67`) en entier (`1234567`) pour stocker une valeur de monnaie.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign montant=$_POST.montant|trim|money_int}}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Filtres SQL
|
||||||
|
|
||||||
|
## quote_sql
|
||||||
|
|
||||||
|
Protège une chaîne contre les attaques SQL, pour l'utilisation dans une condition.
|
||||||
|
|
||||||
|
**Note : il est FORTEMENT déconseillé d'intégrer directement des sources extérieures dans les requêtes SQL, il est préférable d'utiliser les paramètres dans la boucle `sql` et ses dérivées, comme ceci : `{{#sql select="id, nom" tables="users" where="lettre_infos = :lettre" :lettre=$_GET.lettre}}`.**
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign nom=$_GET.nom|quote_sql}}
|
||||||
|
{{#sql select="id, nom" tables="users" where="nom = %s"|args:$nom}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## quote_sql_identifier
|
||||||
|
|
||||||
|
La même chose que `quote_sql`, mais pour les identifiants (par exemple nom de table ou de colonne).
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign colonne=$_GET.colonne|quote_sql_identifier}}
|
||||||
|
{{#sql select="id, %s"|args:$colonne tables="users"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est possible d'utiliser un préfixe en argument, utile par exemple quand on a plusieurs tables avec le même nom de colonne :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign colonne=$_GET.colonne|quote_sql_identifier:"u1"}}
|
||||||
|
{{#sql select="u1.id, %s"|args:$colonne tables="users AS u1 INNER JOIN users AS u2 ON u2.id_parent = u1.id"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## sql_where
|
||||||
|
|
||||||
|
Permet de créer une partie d'une clause SQL `WHERE` complexe.
|
||||||
|
|
||||||
|
Le premier paramètre est le nom de la colonne (sans préfixe).
|
||||||
|
|
||||||
|
Paramètres :
|
||||||
|
|
||||||
|
1. Comparateur : `=, !=, IN, NOT IN, >, >=, <, <=`
|
||||||
|
2. Valeur à comparer (peut être un tableau)
|
||||||
|
|
||||||
|
Exemple pour afficher la liste des membres des catégories n°1 et n°2:
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="list." value=1}}
|
||||||
|
{{:assign var="list." value=2}}
|
||||||
|
{{#sql select="nom" tables="users" where="id_category"|sql_where:'IN':$id_list}}
|
||||||
|
{{$nom}}
|
||||||
|
{{/sql}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Le requête SQL générée sera alors `SELECT nom FROM users WHERE id_category IN (1, 2)`.
|
||||||
|
|
||||||
|
## sql_user_fields
|
||||||
|
|
||||||
|
Permet de récupérer le contenu de champs de la fiche utilisateur pour une requête SQL.
|
||||||
|
|
||||||
|
C'est particulièrement utile si le module permet de sélectionner dans sa configuration une liste de champs de membre (par exemple pour la carte de membre, ou les reçus fiscaux).
|
||||||
|
|
||||||
|
Si un champ mentionné n'existe plus dans les fiches de membres, il sera ignoré.
|
||||||
|
|
||||||
|
* Le premier paramètre est la liste des champs (tableau ou chaîne de texte)
|
||||||
|
* Le second est le préfixe à utiliser (alias de la table membres), optionnel
|
||||||
|
* Le troisième est la chaîne de texte à utiliser pour coller les champs entre eux
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="champs_adresse." value="rue"}}
|
||||||
|
{{:assign var="champs_adresse." value="ville"}}
|
||||||
|
{{:assign var="champs_adresse_sql" value=$champs_adresse|sql_user_fields:"u":" - "}}
|
||||||
|
{{#select !champs_adresse_sql AS adresse FROM users AS u; !champs_adresse_sql=$champs_adresse_sql}}
|
||||||
|
{{$adresse}}
|
||||||
|
{{/select}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Affichera :
|
||||||
|
|
||||||
|
```
|
||||||
|
30 rue de Machin Chose — Dijon
|
||||||
|
```
|
||||||
|
|
||||||
|
Et la clause SQL générée sera :
|
||||||
|
|
||||||
|
```
|
||||||
|
LTRIM(COALESCE(' - ' || u.rue, '') || COALESCE(' - ' || u.ville), ' - ')
|
||||||
|
```
|
||||||
|
|
||||||
|
# Filtres de date
|
||||||
|
|
||||||
|
## date
|
||||||
|
|
||||||
|
Formatte une date selon le format spécifié en premier paramètre.
|
||||||
|
|
||||||
|
Le format est identique au [format utilisé par PHP](https://www.php.net/manual/fr/datetime.format.php).
|
||||||
|
|
||||||
|
Si aucun format n'est indiqué, le défaut sera `d/m/Y à H:i`. (en français)
|
||||||
|
|
||||||
|
Exemples :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign this_year=$now|date:'Y'}}
|
||||||
|
{{$date|date:'d/m/Y'}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## strftime
|
||||||
|
|
||||||
|
Formatte une date selon un format spécifié en premier paramètre.
|
||||||
|
|
||||||
|
Le format à utiliser est identique [au format utilisé par la fonction strftime de PHP](https://www.php.net/strftime).
|
||||||
|
|
||||||
|
Un format doit obligatoirement être spécifié.
|
||||||
|
|
||||||
|
En passant un code de langue en second paramètre, cette langue sera utilisée. Sont supportés le français (`fr`) et l'anglais (`en`). Le défaut est le français si aucune valeur n'est passée en second paramètre .
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign this_year=$now|date:'%Y'}}
|
||||||
|
{{$date|date:'%d/%m/%Y'}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## relative_date
|
||||||
|
|
||||||
|
Renvoie une date relative à la date du jour : `aujourd'hui`, `hier`, `demain`, ou sinon `mardi 2 janvier` (si la date est de l'année en cours) ou `2 janvier 2021` (si la date est d'une autre année).
|
||||||
|
|
||||||
|
En spécifiant `true` en premier paramètre, l'heure sera ajoutée au format `14h34`.
|
||||||
|
|
||||||
|
## date_short
|
||||||
|
|
||||||
|
Formatte une date au format court : `d/m/Y`.
|
||||||
|
|
||||||
|
En spécifiant `true` en premier paramètre l'heure sera ajoutée : `à H\hi`.
|
||||||
|
|
||||||
|
## date_long
|
||||||
|
|
||||||
|
Formatte une date au format long : `lundi 2 janvier 2021`.
|
||||||
|
|
||||||
|
En spécifiant `true` en premier paramètre l'heure sera ajoutée : `à 20h42`.
|
||||||
|
|
||||||
|
## date_hour
|
||||||
|
|
||||||
|
Formatte une date en renvoyant l'heure uniquement : `20h00`.
|
||||||
|
|
||||||
|
En passant `true` en premier paramètre, les minutes seront omises si elles sont égales à zéro : `20h`.
|
||||||
|
|
||||||
|
## atom_date
|
||||||
|
|
||||||
|
Formatte une date au format ATOM : `Y-m-d\TH:i:sP`
|
||||||
|
|
||||||
|
## parse_date
|
||||||
|
|
||||||
|
Vérifie le format d'une chaîne de texte représentant la date et la transforme en chaîne de date standardisée au format `AAAA-MM-JJ`.
|
||||||
|
|
||||||
|
Les formats acceptés sont :
|
||||||
|
|
||||||
|
* `AAAA-MM-JJ`
|
||||||
|
* `JJ/MM/AAAA`
|
||||||
|
* `JJ/MM/AA`
|
||||||
|
|
||||||
|
## parse_datetime
|
||||||
|
|
||||||
|
Vérifie le format d'une chaîne de texte représentant la date et l'heure et la transforme en chaîne de date et heure standardisée au format `AAAA-MM-JJ HH:mm`.
|
||||||
|
|
||||||
|
Les formats acceptés sont :
|
||||||
|
|
||||||
|
* `AAAA-MM-JJ HH:mm:ss`
|
||||||
|
* `AAAA-MM-JJ HH:mm`
|
||||||
|
* `JJ/MM/AAAA HH:mm`
|
||||||
|
|
||||||
|
## parse_time
|
||||||
|
|
||||||
|
Vérifie le format d'une chaîne de texte représentant l'heure et la transforme en chaîne de date standardisée au format `HH:MM`.
|
||||||
|
|
||||||
|
Les formats acceptés sont :
|
||||||
|
|
||||||
|
* `HH:MM`
|
||||||
|
* `H:M`
|
||||||
|
* `H:MM`
|
||||||
|
* `HH:M`
|
||||||
|
|
||||||
|
Le séparateur peut être `:` ou `h`.
|
||||||
|
|
||||||
|
# Filtres de condition
|
||||||
|
|
||||||
|
Ces filtres sont à utiliser dans les conditions
|
||||||
|
|
||||||
|
## match
|
||||||
|
|
||||||
|
Renvoie `true` si le texte indiqué en premier paramètre est trouvé dans la variable.
|
||||||
|
|
||||||
|
Ce filtre est insensible à la casse.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{if $page.path|match:"/aide"}}Bienvenue dans l'aide !{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## regexp_match
|
||||||
|
|
||||||
|
Renvoie `true` si l'expression régulière indiquée en premier paramètre est trouvée dans la variable.
|
||||||
|
|
||||||
|
Exemple pour voir si le texte contient les mots "Bonjour" ou "Au revoir" (insensible à la casse) :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{if $texte|regexp_match:"/Bonjour|Au revoir/i"}}
|
||||||
|
Trouvé !
|
||||||
|
{{else}}
|
||||||
|
Rien trouvé :-(
|
||||||
|
{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Autres filtres
|
||||||
|
|
||||||
|
## math
|
||||||
|
|
||||||
|
Réalise un calcul mathématique. Cette fonction accepte :
|
||||||
|
|
||||||
|
* les nombres: `42`, `13,37`, `14.05`
|
||||||
|
* les signes : `+ - / *` pour additionner, diminuer, diviser ou multiplier
|
||||||
|
* les parenthèses : `( )`
|
||||||
|
* les fonctions : `round(0.5452, 2)` `ceil(29,09)` `floor(0.99)` mais aussi : min, max, cos, sin, tan, asin, acos, atan, sinh, cosh, tanh, exp, sqrt, abs, log, log10, et pi.
|
||||||
|
|
||||||
|
Le résultat est renvoyé sous la forme d'un entier, ou d'un nombre flottant dont les décimales sont séparées par un point.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{"1+1"|math}}
|
||||||
|
= 2
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est possible de donner d'autres arguments, de la même manière qu'avec `args` pour y inclure des données provenant de variables :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign age=42}}
|
||||||
|
{{"1+%d"|math:$age}}
|
||||||
|
= 43
|
||||||
|
{{:assign prix=39.99 tva=19.1}}
|
||||||
|
{{"round(%f*%f, 2)"|math:$prix:$tva}}
|
||||||
|
= 47.63
|
||||||
|
```
|
||||||
|
|
||||||
|
## or
|
||||||
|
|
||||||
|
Si la variable passée est évalue comme `false` (c'est à dire que sa valeur est un texte vide, ou un nombre qui vaut zéro, ou la valeur `false`), alors le premier paramètre sera utilisé.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign texte=""}}
|
||||||
|
{{$texte|or:"Le texte est vide"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est possible de chaîner les appels à `or` :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign texte1="" texte2="0"}}
|
||||||
|
{{$texte1|or:$texte2|or:"Aucun texte"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## size_in_bytes
|
||||||
|
|
||||||
|
Renvoie une taille en octets, Ko, Mo, ou Go à partir d'une taille en octets.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{100|size_in_bytes}} = 100 o
|
||||||
|
{{1500|size_in_bytes}} = 1,50 Ko
|
||||||
|
{{1048576|size_in_bytes}} = 1 Mo
|
||||||
|
```
|
||||||
|
|
||||||
|
## spell_out_number
|
||||||
|
|
||||||
|
Épelle un nombre en toutes lettres.
|
||||||
|
|
||||||
|
Le premier paramètre peut être utilisé pour spécifier le code de la langue à utiliser (par défaut c'est le français, donc le code `fr`).
|
||||||
|
|
||||||
|
```
|
||||||
|
{{42|spell_out_number}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Donnera :
|
||||||
|
|
||||||
|
```
|
||||||
|
quarante deux
|
||||||
|
```
|
||||||
|
|
||||||
|
## uuid
|
||||||
|
|
||||||
|
Renvoie un identifiant unique au format UUIDv4.
|
827
doc/admin/brindille_sections.md
Normal file
827
doc/admin/brindille_sections.md
Normal file
|
@ -0,0 +1,827 @@
|
||||||
|
Title: Référence des sections Brindille
|
||||||
|
|
||||||
|
{{{.nav
|
||||||
|
* [Modules](modules.html)
|
||||||
|
* [Documentation Brindille](brindille.html)
|
||||||
|
* [Fonctions](brindille_functions.html)
|
||||||
|
* **[Sections](brindille_sections.html)**
|
||||||
|
* [Filtres](brindille_modifiers.html)
|
||||||
|
}}}
|
||||||
|
|
||||||
|
<<toc aside level=2>>
|
||||||
|
|
||||||
|
# Sections généralistes
|
||||||
|
|
||||||
|
## foreach
|
||||||
|
|
||||||
|
Permet d'itérer sur un tableau par exemple. Ainsi chaque élément du tableau exécutera une fois le contenu de la section.
|
||||||
|
|
||||||
|
| Paramètre | Optionnel / obligatoire ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `from` | **obligatoire** | Variable sur laquelle effectuer l'itération |
|
||||||
|
| `key` | **optionnel** | Nom de la variable à utiliser pour la clé de l'élément |
|
||||||
|
| `item` | **optionnel** | Nom de la variable à utiliser pour la valeur de l'élément |
|
||||||
|
|
||||||
|
Considérons ce tableau :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="tableau" a="bleu" b="orange"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
On peut alors itérer pour récupérer les clés (`a` et `b` ainsi que les valeurs `bleu` et `orange`) :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#foreach from=$tableau key="key" item="value"}}
|
||||||
|
{{$key}} = {{$value}}
|
||||||
|
{{/foreach}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Cela affichera :
|
||||||
|
|
||||||
|
```
|
||||||
|
a = bleu
|
||||||
|
b = orange
|
||||||
|
```
|
||||||
|
|
||||||
|
Si on a un tableau à plusieurs niveaux, les éléments du tableau sont automatiquement transformés en variable :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="tableau.a" couleur="bleu"}}
|
||||||
|
{{:assign var="tableau.b" couleur="orange"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#foreach from=$variable}}
|
||||||
|
{{$couleur}}
|
||||||
|
{{/foreach}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Affichera :
|
||||||
|
|
||||||
|
```
|
||||||
|
bleu
|
||||||
|
orange
|
||||||
|
```
|
||||||
|
|
||||||
|
### Itérer sans tableau
|
||||||
|
|
||||||
|
Il est aussi possible de faire `X` itérations, arbitrairement, sans avoir de tableau en entrée, en utilisant le paramètre `count`.
|
||||||
|
|
||||||
|
C'est l'équivalent des boucles `for` dans les autres langages de programmation.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#foreach count=3 key="i"}}
|
||||||
|
- {{$i}}
|
||||||
|
{{/foreach}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Affichera :
|
||||||
|
|
||||||
|
```
|
||||||
|
- 0
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
```
|
||||||
|
|
||||||
|
## restrict
|
||||||
|
|
||||||
|
Permet de limiter (restreindre) une partie de la page aux membres qui sont connectés et/ou qui ont certains droits.
|
||||||
|
|
||||||
|
Deux paramètres optionnels peuvent être utilisés ensemble (il n'est pas possible d'utiliser seulement un des deux) :
|
||||||
|
|
||||||
|
| Paramètre | Optionnel / obligatoire ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `level` | *optionnel* | Niveau d'accès : `read`, `write`, `admin` |
|
||||||
|
| `section` | *optionnel* | Section où le niveau d'accès doit s'appliquer : `users`, `accounting`, `web`, `documents`, `config` |
|
||||||
|
| `block` | *optionnel* | Si ce paramètre est présent et vaut `true`, alors l'accès sera interdit si les conditions d'accès demandées ne sont pas remplies : une page d'erreur sera renvoyée. |
|
||||||
|
|
||||||
|
Exemple pour voir si un membre est connecté :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#restrict}}
|
||||||
|
Un membre est connecté, mais on ne sait pas avec quels droits.
|
||||||
|
{{else}}
|
||||||
|
Aucun membre n'est connecté.
|
||||||
|
{{/restrict}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Exemple pour voir si un membre qui peut administrer les membres est connecté :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#restrict section="users" level="admin"}}
|
||||||
|
Un membre est connecté, et il a le droit d'administrer les membres.
|
||||||
|
{{else}}
|
||||||
|
Aucun membre n'est connecté, ou un membre est connecté mais n'est pas administrateur des membres.
|
||||||
|
{{/restrict}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Pour bloquer l'accès aux membres non connectés, ou qui n'ont pas accès en écriture à la comptabilité.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#restrict block=true section="accounting" level="write"}}
|
||||||
|
{{/restrict}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Le mieux est de mettre ce code au début d'un squelette.
|
||||||
|
|
||||||
|
# Requêtes SQL
|
||||||
|
|
||||||
|
## select
|
||||||
|
|
||||||
|
Exécute une requête SQL `SELECT` et effectue une itération pour chaque résultat de la requête.
|
||||||
|
|
||||||
|
Pour une utilisation plus simplifiée des requêtes, voir aussi la section [sql](#sql).
|
||||||
|
|
||||||
|
Attention : la syntaxe de cette section est différente des autres sections Brindille. En effet après le début (`{{#select`) doit suivre la suite de la requête, et non pas les paramètres :
|
||||||
|
|
||||||
|
```
|
||||||
|
Liste des membres inscrits à la lettre d'informations :
|
||||||
|
{{#select nom, prenom FROM users WHERE lettre_infos = 1;}}
|
||||||
|
- {{prenom}} {{$nom}}<br />
|
||||||
|
{{else}}
|
||||||
|
Aucun membre n'est inscrit à la lettre d'information.
|
||||||
|
{{/select}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Des paramètres nommés de SQL peuvent être présentés après le point-virgule marquant la fin de la requête SQL :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign prenom="Karim"}}
|
||||||
|
{{#select * FROM users WHERE prenom = :prenom;
|
||||||
|
:prenom=$prenom}}
|
||||||
|
...
|
||||||
|
{{/select}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Notez les deux points avant le nom du paramètre. Ces paramètres sont protégés contre les injections SQL (généralement appelés paramètres nommés).
|
||||||
|
|
||||||
|
Pour intégrer des paramètres qui ne sont pas protégés (**attention !**), il faut utiliser le point d'exclamation :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="categories." value=1}}
|
||||||
|
{{:assign var="categories." value=2}}
|
||||||
|
{{#select * FROM users WHERE !categories;
|
||||||
|
!categories='id_category'|sql_where:'IN':$categories}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Cela créera la requête suivante : `SELECT * FROM users WHERE id_category IN (1, 2);`
|
||||||
|
|
||||||
|
Il est aussi possible d'intégrer directement des variables dans la requête, en utilisant la syntaxe `{$variable|filtre:argument1:argument2}`, comme une variable classique donc, mais au lieu d'utiliser des doubles accolades, on utilise ici des accolades simples. Ces variables seront automatiquement protégées contre les injections SQL.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign prenom="Camille"}}
|
||||||
|
{{#select * FROM users WHERE initiale_prenom = {$prenom|substr:0:1};}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Cependant, pour plus de lisibilité il est conseillé d'utiliser la syntaxe des paramètres nommés SQL (voir ci-dessus).
|
||||||
|
|
||||||
|
Il est aussi possible d'insérer directement du code SQL (attention aux problèmes de sécurité dans ce cas !), pour cela il faut rajouter un point d'exclamation après l'accolade ouvrante :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="prenoms." value="Karim"}}
|
||||||
|
{{:assign var="prenoms." value="Camille"}}
|
||||||
|
{{#select * FROM users WHERE {!"prenom"|sql_where:"IN":$prenoms};}}
|
||||||
|
...
|
||||||
|
{{/select}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est aussi possible d'utiliser les paramètres suivants :
|
||||||
|
|
||||||
|
| Paramètre | Fonction |
|
||||||
|
| :- | :- |
|
||||||
|
| `debug` | Si ce paramètre existe, la requête SQL exécutée sera affichée avant le début de la boucle. |
|
||||||
|
| `explain` | Si ce paramètre existe, l'explication de la requête SQL exécutée sera affichée avant le début de la boucle. |
|
||||||
|
| `assign` | Si renseigné, une variable de ce nom sera créée, et le contenu de la ligne y sera assigné. |
|
||||||
|
|
||||||
|
Exemple avec `debug` :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign prenom="Karim"}}
|
||||||
|
{{#select * FROM users WHERE prenom = :prenom; :prenom=$prenom debug=true}}
|
||||||
|
...
|
||||||
|
{{/select}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Affichera juste au dessus du résultat la requête exécutée :
|
||||||
|
|
||||||
|
```
|
||||||
|
SELECT * FROM users WHERE nom = 'Karim'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Paramètre assign
|
||||||
|
|
||||||
|
Exemple avec `assign` :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#select * FROM users WHERE prenom = 'Camille' LIMIT 1; assign="membre"}}{{/select}}
|
||||||
|
{{$membre.nom}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est possible d'utiliser un point final pour que toutes les lignes soient mises dans un tableau :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#select * FROM users WHERE prenom = 'Camille' LIMIT 10; assign="membres."}}{{/select}}
|
||||||
|
|
||||||
|
{{#foreach from=$membres}}
|
||||||
|
Nom : {{$nom}}<br />
|
||||||
|
Adresse : {{$adresse}}
|
||||||
|
{{/foreach}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## sql
|
||||||
|
|
||||||
|
|
||||||
|
Effectue une requête SQL de type `SELECT` dans la base de données, mais de manière simplifiée par rapport à `select`.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#sql select="*, julianday(date) AS day" tables="membres" where="id_categorie = :id_categorie" :id_categorie=$_GET.id_categorie order="numero DESC" begin=":page*100" limit=100 :page=$_GET.page}}
|
||||||
|
…
|
||||||
|
{{/sql}}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Paramètre | Optionnel / obligatoire ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `tables` | **obligatoire** | Liste des tables à utiliser dans la requête (séparées par des virgules). |
|
||||||
|
| `select` | *optionnel* | Liste des colonnes à sélectionner, si non spécifié, toutes les colonnes (`*`) seront sélectionnées |
|
||||||
|
|
||||||
|
### Sections qui héritent de `sql`
|
||||||
|
|
||||||
|
Certaines sections (voir plus bas) héritent de `sql` et rajoutent des fonctionnalités. Dans toutes ces sections, il est possible d'utiliser les paramètres facultatifs suivants :
|
||||||
|
|
||||||
|
| Paramètre | Fonction |
|
||||||
|
| :- | :- |
|
||||||
|
| `where` | Condition de sélection des résultats |
|
||||||
|
| `begin` | Début des résultats, si vide une valeur de `0` sera utilisée. |
|
||||||
|
| `limit` | Limitation des résultats. Si vide, une valeur de `10000` sera utilisée. |
|
||||||
|
| `group` | Contenu de la clause `GROUP BY` |
|
||||||
|
| `having` | Contenu de la clause `HAVING` |
|
||||||
|
| `order` | Ordre de tri des résultats. Si vide le tri sera fait par ordre d'ajout dans la base de données. |
|
||||||
|
| `assign` | Si renseigné, une variable de ce nom sera créée, et le contenu de la ligne du résultat y sera assigné. |
|
||||||
|
| `debug` | Si ce paramètre existe, la requête SQL exécutée sera affichée avant le début de la boucle. |
|
||||||
|
| `explain` | Si ce paramètre existe, l'explication de la requête SQL exécutée sera affichée avant le début de la boucle. |
|
||||||
|
| `count` | Booléen ou texte. Si ce paramètre est `TRUE`, le nombre de résultats sera retourné. Si une chaîne de texte est indiquée, elle sera utilisée dans la clause `COUNT(<texte>)`. |
|
||||||
|
|
||||||
|
Il est également possible de passer des arguments dans les paramètres à l'aides des arguments nommés qui commencent par deux points `:` :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#articles where="title = :montitre" :montitre="Actualité"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Exemples d'utilisation du paramètre `count` :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#articles count=true}}
|
||||||
|
Il y a {{$count}} articles.
|
||||||
|
{{/articles}}
|
||||||
|
|
||||||
|
{{#articles count=true assign="result"}}
|
||||||
|
{{/articles}}
|
||||||
|
Il y a {{$result.count}} articles.
|
||||||
|
|
||||||
|
{{#articles count="DISTINCT title"}}
|
||||||
|
Il y a {{$count}} articles avec un titre différent.
|
||||||
|
{{/articles}}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Membres
|
||||||
|
|
||||||
|
## users
|
||||||
|
|
||||||
|
Liste les membres.
|
||||||
|
|
||||||
|
Paramètres possibles :
|
||||||
|
|
||||||
|
| Paramètre | Optionnel / obligatoire ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `id` | optionnel | Identifiant unique du membre, ou tableau contenant une liste d'identifiants. |
|
||||||
|
| `search_name` | optionnel | Ne lister que les membres dont le nom correspond au texte passé en paramètre. |
|
||||||
|
| `id_parent` | optionnel | Ne lister que les membres rattachés à l'identifiant unique du membre responsable indiqué. |
|
||||||
|
|
||||||
|
Chaque itération renverra la fiche du membre, ainsi que ces variables :
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| :- | :- |
|
||||||
|
| `$id` | Identifiant unique du membre |
|
||||||
|
| `$_name` | Nom du membre, tel que défini dans la configuration |
|
||||||
|
| `$_login` | Identifiant de connexion du membre, tel que défini dans la configuration |
|
||||||
|
| `$_number` | Numéro du membre, tel que défini dans la configuration |
|
||||||
|
|
||||||
|
|
||||||
|
## subscriptions
|
||||||
|
|
||||||
|
Liste les inscriptions à une ou des activités.
|
||||||
|
|
||||||
|
Paramètres possibles :
|
||||||
|
|
||||||
|
| Paramètre | | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `user` | optionnel | Identifiant unique du membre |
|
||||||
|
| `active` | optionnel | Si `TRUE`, seules les inscriptions à jour sont listées |
|
||||||
|
| `id_service` | optionnel | Ne renvoie que les inscriptions à l'activité correspondant à cet ID. |
|
||||||
|
|
||||||
|
# Comptabilité
|
||||||
|
|
||||||
|
## accounts
|
||||||
|
|
||||||
|
Liste les comptes d'un plan comptable.
|
||||||
|
|
||||||
|
| Paramètre | Fonction |
|
||||||
|
| :- | :- |
|
||||||
|
| `codes` (optionel) | Ne renvoyer que les comptes ayant ces codes (séparer par des virgules). |
|
||||||
|
| `id` (optionel) | Ne renvoyer que le compte ayant cet ID. |
|
||||||
|
|
||||||
|
## balances
|
||||||
|
|
||||||
|
Renvoie la balance des comptes.
|
||||||
|
|
||||||
|
| Paramètre | Fonction |
|
||||||
|
| :- | :- |
|
||||||
|
| `codes` (optionel) | Ne renvoyer que les balances des comptes ayant ces codes (séparer par des virgules). |
|
||||||
|
| `year` (optionel) | Ne renvoyer que les balances des comptes utilisés sur l'année (indiquer ici un ID de year). |
|
||||||
|
|
||||||
|
## transactions
|
||||||
|
|
||||||
|
Renvoie des écritures.
|
||||||
|
|
||||||
|
| Paramètre | | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `id` | optionnel | Indiquer un ID d'écriture pour récupérer ses informations. |
|
||||||
|
| `user` | optionnel | Indiquer ici un ID utilisateur pour lister les écritures liées à un membre. |
|
||||||
|
|
||||||
|
## years
|
||||||
|
|
||||||
|
Liste les exercices comptables
|
||||||
|
|
||||||
|
| Paramètre | Fonction |
|
||||||
|
| :- | :- |
|
||||||
|
| `closed` (optionel) | Mettre `closed=true` pour ne lister que les exercices clôturés, ou `closed=false` pour ne lister que les exercices ouverts. |
|
||||||
|
|
||||||
|
# Pour le site web
|
||||||
|
|
||||||
|
## breadcrumbs
|
||||||
|
|
||||||
|
Permet de récupérer la liste des pages parentes d'une page afin de constituer un [fil d'ariane](https://fr.wikipedia.org/wiki/Fil_d'Ariane_(ergonomie)) permettant de remonter dans l'arborescence du site
|
||||||
|
|
||||||
|
Un seul paramètre est possible :
|
||||||
|
|
||||||
|
| Paramètre | Fonction |
|
||||||
|
| :- | :- |
|
||||||
|
| `uri` (obligatoire) | Adresse unique de la page parente |
|
||||||
|
| ou `id_page` (obligatoire) | Numéro unique (ID) de la page parente |
|
||||||
|
|
||||||
|
Chaque itération renverra trois variables :
|
||||||
|
|
||||||
|
| Variable | Contenu |
|
||||||
|
| :- | :- |
|
||||||
|
| `$id` | Numéro unique (ID) de la page ou catégorie |
|
||||||
|
| `$title` | Titre de la page ou catégorie |
|
||||||
|
| `$uri` | Nom unique de la page ou catégorie |
|
||||||
|
| `$url` | Adresse HTTP de la page ou catégorie |
|
||||||
|
|
||||||
|
### Exemple
|
||||||
|
|
||||||
|
```
|
||||||
|
<ul>
|
||||||
|
{{#breadcrumbs id_page=$page.id}}
|
||||||
|
<li>{{$title}}</li>
|
||||||
|
{{/breadcrumbs}}
|
||||||
|
</ul>
|
||||||
|
```
|
||||||
|
|
||||||
|
## pages, articles, categories <sup>(sql)</sup>
|
||||||
|
|
||||||
|
Note : ces sections héritent de `sql` (voir plus haut).
|
||||||
|
|
||||||
|
* `pages` renvoie une liste de pages, qu'elles soient des articles ou des catégories
|
||||||
|
* `categories` ne renvoie que des catégories
|
||||||
|
* `articles` ne renvoie que des articles
|
||||||
|
|
||||||
|
À part cela ces trois types de section se comportent de manière identique.
|
||||||
|
|
||||||
|
| Paramètre | Fonction |
|
||||||
|
| :- | :- |
|
||||||
|
| `search` | Renseigner ce paramètre avec un terme à rechercher dans le texte ou le titre. Dans ce cas par défaut le tri des résultats se fait sur la pertinence, sauf si le paramètre `order` est spécifié. |
|
||||||
|
| `future` | Renseigner ce paramètre à `false` pour que les articles dont la date est dans le futur n'apparaissent pas, `true` pour ne renvoyer QUE les articles dans le futur, et `null` (ou ne pas utiliser ce paramètre) pour que tous les articles, passés et futur, apparaissent. |
|
||||||
|
| `uri` | Adresse unique de la page/catégorie à retourner. |
|
||||||
|
| `id_parent` | Numéro unique (ID) de la catégorie parente. Utiliser `null` pour n'afficher que les articles ou catégories de la racine du site. |
|
||||||
|
| `parent` | Adresse unique (URI) de la catégorie parente. Exemple pour renvoyer la liste des articles de la sous-catégorie "Événements" de la catégorie "Notre atelier" : `evenements`. Utiliser `null` pour n'afficher que les articles ou catégories de la racine du site. Ajouter un point d'exclamation au début de la valeur pour inverser la condition. |
|
||||||
|
|
||||||
|
Par exemple lister 5 articles de la catégorie "Actualité", qui ne sont pas dans le futur, triés du plus récent au plus ancien :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#articles future=false parent="actualite" order="published DESC" limit=5}}
|
||||||
|
<h3>{{$title}}</h3>
|
||||||
|
{{/articles}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Chaque élément de ces boucles contiendra les variables suivantes :
|
||||||
|
|
||||||
|
| Nom de la variable | Description | Exemple |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `id` | Numéro unique de la page (ID) | `1312` |
|
||||||
|
| `id_parent` | Numéro unique de la catégorie parente (ID) | `42` |
|
||||||
|
| `type` | Type de page : `1` = catégorie, `2` = article | `2` |
|
||||||
|
| `uri` | Adresse unique de la page | `bourse-aux-velos` |
|
||||||
|
| `url` | Adresse HTTP de la page | `https://site.association.tld/bourse-aux-velos` |
|
||||||
|
| `path` | Chemin complet de la page | `actualite/atelier/bourse-aux-velos` |
|
||||||
|
| `parent` | Chemin de la catégorie parente | `actualite/atelier`|
|
||||||
|
| `title` | Titre de la page | `Bourse aux vélos` |
|
||||||
|
| `content` | Contenu brut de la page | `# Titre …` |
|
||||||
|
| `html` | Rendu HTML du contenu de la page | `<div class="web-content"><h1>Titre</h1>…</div>` |
|
||||||
|
| `has_attachments` | `true` si la page a des fichiers joints, `false` sinon | `true` |
|
||||||
|
| `published` | Date de publication | `2023-01-01 01:01:01` |
|
||||||
|
| `modified` | Date de modification | `2023-01-01 01:01:01` |
|
||||||
|
|
||||||
|
Si une recherche a été effectuée, deux autres variables sont fournies :
|
||||||
|
|
||||||
|
| Nom de la variable | Description | Exemple |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `snippet` | Extrait du contenu contenant le texte recherché (entouré de balises `<mark>`) | `L’ONU appelle la France à s’attaquer aux « profonds problèmes » de <mark>racisme</mark> au sein des forces de…` |
|
||||||
|
| `url_highlight` | Adresse de la page, où le texte recherché sera mis en évidence | `https://.../onu-racisme#:~:text=racisme%20au%20sein` |
|
||||||
|
|
||||||
|
|
||||||
|
## attachments, documents, images <sup>(sql)</sup>
|
||||||
|
|
||||||
|
Note : ces sections héritent de `sql` (voir plus haut).
|
||||||
|
|
||||||
|
* `attachments` renvoie une liste de fichiers joints à une page du site web
|
||||||
|
* `documents` renvoie une liste de fichiers joints qui ne sont pas des images
|
||||||
|
* `images` renvoie une liste de fichiers joints qui sont des images
|
||||||
|
|
||||||
|
À part cela ces trois types de section se comportent de manière identique.
|
||||||
|
|
||||||
|
Note : seul les fichiers de la section site web sont accessibles, les fichiers de membres, de comptabilité, etc. ne sont pas disponibles.
|
||||||
|
|
||||||
|
| Paramètre | Optionnel / obligatoire ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `parent` | **obligatoire** si `id_parent` n'est pas renseigné | Nom unique (URI) de l'article ou catégorie parente dont ont veut lister les fichiers |
|
||||||
|
| `id_parent` | **obligatoire** si `parent` n'est pas renseigné | Numéro unique (ID) de l'article ou catégorie parente dont ont veut lister les fichiers |
|
||||||
|
| `except_in_text` | *optionnel* | passer `true` à ce paramètre , et seuls les fichiers qui ne sont pas liés dans le texte de la page seront renvoyés |
|
||||||
|
|
||||||
|
# Sections relatives aux modules
|
||||||
|
|
||||||
|
## form
|
||||||
|
|
||||||
|
Permet de gérer la soumission d'un formulaire (`<form method="post"…>` en HTML).
|
||||||
|
|
||||||
|
Si l'élément dont le nom spécifié dans le paramètre `on` a été envoyé en `POST`, alors le code à l'intérieur de la section est exécuté.
|
||||||
|
|
||||||
|
Toute erreur à l'intérieur de la section arrêtera son exécution, et le message sera ajouté aux erreurs du formulaire.
|
||||||
|
|
||||||
|
Une vérification de sécurité [anti-CSRF](https://fr.wikipedia.org/wiki/Cross-site_request_forgery) est également appliquée. Si cette vérification échoue, le message d'erreur "Merci de bien vouloir renvoyer le formulaire." sera renvoyé. Pour que cela marche il faut que le formulaire dispose d'un bouton de type "submit", généré à l'aide de la fonction `button`. Exemple : `{{:button type="submit" name="save" label="Enregistrer"}}`.
|
||||||
|
|
||||||
|
En cas d'erreurs, le reste du contenu de la section ne sera pas exécuté. Les messages d'erreurs seront placés dans un tableau dans la variable `$form_errors`.
|
||||||
|
|
||||||
|
Il est aussi possible de les afficher simplement avec la fonction `{{:form_errors}}`. Cela revient à faire une boucle sur la variable `$form_errors`.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#form on="save"}}
|
||||||
|
{{if $_POST.titre|trim === ''}}
|
||||||
|
{{:error message="Le titre est vide."}}
|
||||||
|
{{/if}}
|
||||||
|
{{* La ligne suivante ne sera pas exécutée si le titre est vide. *}}
|
||||||
|
{{:save title=$_POST.titre|trim}}
|
||||||
|
{{else}}
|
||||||
|
{{:form_errors}}
|
||||||
|
{{/form}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est possible d'utiliser `{{:form_errors}}` en dehors du bloc `{{else}}` :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#form on="save"}}
|
||||||
|
…
|
||||||
|
{{/form}}
|
||||||
|
…
|
||||||
|
{{:form_errors}}
|
||||||
|
```
|
||||||
|
|
||||||
|
<!--
|
||||||
|
NOTE (bohwaz, 24/05/2023) : l'utilisation des règles de validation de Laravel me semble donner du code peu lisible, ce n'est donc pas documenté/complètement implémenté pour le moment.
|
||||||
|
|
||||||
|
Si l'élément dont le nom spécifié dans le paramètre `on` a été envoyé en `POST`, alors le formulaire est vérifié selon les autres paramètres. Une vérification de sécurité anti-CSRF est également appliquée. Si cette vérification échoue, le message d'erreur "Merci de bien vouloir renvoyer le formulaire." sera renvoyé.
|
||||||
|
|
||||||
|
Chaque paramètre supplémentaire indique un champ du formulaire qui doit être récupéré et validé. Le nom du paramètre doit correspondre au nom du champ dans le formulaire. La valeur du paramètre doit contenir une liste de règles de validations, séparées par des virgules `,`. Chaque règle peut prendre des paramètres, après deux points `:`.
|
||||||
|
|
||||||
|
Exemple pour un champ de formulaire nommé `titre` dont on veut qu'il soit présent et fasse entre 5 et 100 caractères : `titre="required,min:5,max:100"`
|
||||||
|
|
||||||
|
Si le titre fait moins de 5 caractères, le message d'erreur suivant sera renvoyé : `Le champ "titre" fait moins de 5 caractères.`
|
||||||
|
|
||||||
|
On peut spécifier une règle spéciale nommée `label` pour changer le nom du champ : `titre="required,min:5,max:100,label:Titre du texte"`. Cela modifiera le message d'erreur : `Le champ "Titre du texte" fait moins de 5 caractères.`
|
||||||
|
|
||||||
|
Chacun de ces paramètres sera disponible à l'intérieur de la section sous la forme d'une variable :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#form titre="required,min:5"}}
|
||||||
|
{{:save title=$titre}}
|
||||||
|
{{/form}}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Toute erreur dans le corps de la section `{{#form}}…{{/form}}` fera arrêter l'exécution, et le message d'erreur sera ajouté à la liste des erreurs du formulaire :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#form on="save"}}
|
||||||
|
{{if !$_POST.titre|trim}}
|
||||||
|
{{:error message="Pas de titre !"}}
|
||||||
|
{{/if}}
|
||||||
|
{{* La ligne suivante ne sera pas exécutée si le titre est vide. *}}
|
||||||
|
{{:save title=$_POST.titre}}
|
||||||
|
{{/form}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Transformation des variables
|
||||||
|
|
||||||
|
Certaines règles de validation ont un effet de transformation sur les variables présentes dans le corps de la section :
|
||||||
|
|
||||||
|
* `string` s'assure que la variable est une chaîne de texte
|
||||||
|
* `int` transforme la variable en nombre entier
|
||||||
|
* `float` transforme la variable en nombre flottant
|
||||||
|
* `bool` transforme la variable en booléen
|
||||||
|
* `date` ou `date_format` transforment la variable en date
|
||||||
|
|
||||||
|
### Exemple
|
||||||
|
|
||||||
|
Considérons ce formulaire par exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
<form method="post" action="">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Enregistrer un paiement</legend>
|
||||||
|
<dl>
|
||||||
|
{{:input type="text" required=true name="titre" label="Titre"}}
|
||||||
|
{{:input type="money" required=true name="montant" label="Montant"}}
|
||||||
|
</dl>
|
||||||
|
<p class="submit">
|
||||||
|
{{:button type="submit" label="Enregistrer" name="save"}}
|
||||||
|
</p>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
```
|
||||||
|
|
||||||
|
On pourrait l'enregistrer comme ceci :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{if $_POST.save}}
|
||||||
|
{{if $_POST.titre|trim === ''}}
|
||||||
|
{{:assign error="Le titre est vide"}}
|
||||||
|
{{elseif $_POST.montant|trim === '' || $_POST.montant|money_int < 0}}
|
||||||
|
{{:assign error="Le montant est vide ou négatif"}}
|
||||||
|
{{else}}
|
||||||
|
{{:save title=$_POST.titre|trim amount=$_POST.montant|money_int}}
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{if $error}}
|
||||||
|
<p class="error block">{{$error}}</p>
|
||||||
|
{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Mais alors dans ce cas il faut multiplier les conditions pour les champs.
|
||||||
|
|
||||||
|
La section `{{#form …}}` permet de simplifier ces tests, et s'assurer qu'aucune attaque CSRF n'a lieu :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#form on="save"
|
||||||
|
titre="required,string,min:1,label:Titre"
|
||||||
|
montant="required,money,min:0,label:Montant du paiement"
|
||||||
|
}}
|
||||||
|
{{:save title=$titre amount=$montant}}
|
||||||
|
{{else}}
|
||||||
|
{{:form_errors}}
|
||||||
|
{{/form}}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Règles de validation
|
||||||
|
|
||||||
|
| Nom de la règle | Description | Paramètres |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `required` | ...
|
||||||
|
-->
|
||||||
|
|
||||||
|
## load <sup>(sql)</sup>
|
||||||
|
|
||||||
|
Note : cette section hérite de `sql` (voir plus haut). De ce fait, le nombre de résultats est limité à 10000 par défaut, si le paramètre `limit` n'est pas renseigné.
|
||||||
|
|
||||||
|
Charge un ou des documents pour le module courant.
|
||||||
|
|
||||||
|
| Paramètre | Optionnel / obligatoire ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `module` | optionnel | Nom unique du module lié (par exemple : `recu_don`). Si non spécifié, alors le nom du module courant sera utilisé. |
|
||||||
|
| `key` | optionnel | Clé unique du document |
|
||||||
|
| `id` | optionnel | Numéro unique du document |
|
||||||
|
| `each` | optionnel | Traiter une clé du document comme un tableau |
|
||||||
|
|
||||||
|
Il est possible d'utiliser d'autres paramètres : `{{#load cle="valeur"}}`. Cela va comparer `"valeur"` avec la valeur de la clé `cle` dans le document JSON. C'est l'équivalent d'écrire `where="json_extract(document, '$.cle') = 'valeur'"`.
|
||||||
|
|
||||||
|
Pour des conditions plus complexes qu'une simple égalité, il est possible d'utiliser la syntaxe courte `$$…` dans le paramètre `where`. Ainsi `where="$$.nom LIKE 'Bourse%'` est l'équivalent de `where="json_extract(document, '$.nom') LIKE 'Bourse%'"`.
|
||||||
|
|
||||||
|
Voir [la documentation de SQLite pour plus de détails sur la syntaxe de json_extract](https://www.sqlite.org/json1.html#jex).
|
||||||
|
|
||||||
|
Note : un index SQL dynamique est créé pour chaque requête utilisant une clause `json_extract`.
|
||||||
|
|
||||||
|
Chaque itération renverra ces deux variables :
|
||||||
|
|
||||||
|
| Variable | Valeur |
|
||||||
|
| :- | :- |
|
||||||
|
| `$key` | Clé unique du document |
|
||||||
|
| `$id` | Numéro unique du document |
|
||||||
|
|
||||||
|
Ainsi que chaque élément du document JSON lui-même.
|
||||||
|
|
||||||
|
### Exemples
|
||||||
|
|
||||||
|
Afficher le nom du document dont la clé est `facture_43` :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#load key="facture_43"}}
|
||||||
|
{{$nom}}
|
||||||
|
{{/load}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Afficher la liste des devis du module `invoice` depuis un autre module par exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#load module="invoice" type="quote"}}
|
||||||
|
<h1>Titre du devis : {{$subject}}</h1>
|
||||||
|
<h2>Montant : {{$total}}</h2>
|
||||||
|
{{/load}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Utilisation du paramètre `each`
|
||||||
|
|
||||||
|
Le paramètre `each` est utile pour faire une boucle sur un tableau contenu dans le document. Ce paramètre doit contenir un chemin JSON valide. Par exemple `membres[1].noms` pour boucler sur le tableau `noms`, du premier élément du tableau `membres`. Voir la documentation [de la fonction json_each de SQLite pour plus de détails](https://www.sqlite.org/json1.html#jeach).
|
||||||
|
|
||||||
|
Pour chaque itération de la section, la variable `{{$value}}` contiendra l'élément recherché dans le critère `each`.
|
||||||
|
|
||||||
|
Par exemple nous pouvons avoir un élément `membres` dans notre document JSON qui contient un tableau de noms de membres :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign var="membres." value="Greta Thunberg}}
|
||||||
|
{{:assign var="membres." value="Valérie Masson-Delmotte"}}
|
||||||
|
{{:save membres=$membres}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Nous pouvons utiliser `each` pour faire une liste :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#load each="membres"}}
|
||||||
|
- {{$value}}
|
||||||
|
{{/load}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Ou pour récupérer les documents qui correspondent à un critère :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#load each="membres" where="value = 'Greta Thunberg'"}}
|
||||||
|
Le document n°{{$id}} est celui qui parle de Greta.
|
||||||
|
{{/load}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## list
|
||||||
|
|
||||||
|
Attention : cette section n'hérite **PAS de `sql`**.
|
||||||
|
|
||||||
|
Un peu comme `{{#load}}` cette section charge les documents d'un module, mais au sein d'une liste (tableau HTML).
|
||||||
|
|
||||||
|
Cette liste gère automatiquement l'ordre selon les préférences des utilisateurs, ainsi que la pagination.
|
||||||
|
|
||||||
|
Cette section est très puissante et permet de générer des listes simplement, une fois qu'on a saisi la logique de son fonctionnement.
|
||||||
|
|
||||||
|
| Paramètre | Optionnel / obligatoire ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `schema` | **requis** si `select` n'est pas fourni | Chemin vers un fichier de schéma JSON qui représenterait le document |
|
||||||
|
| `select` | **requis** si `schema` n'est pas fourni | Liste des colonnes à sélectionner, sous la forme `$$.colonne AS "Colonne"`, chaque colonne étant séparée par un point-virgule. |
|
||||||
|
| `module` | *optionnel* | Nom unique du module lié (par exemple : `recu_don`). Si non spécifié, alors le nom du module courant sera utilisé. |
|
||||||
|
| `columns` | *optionnel* | Permet de n'afficher que certaines colonnes du schéma. Indiquer ici le nom des colonnes, séparées par des virgules. |
|
||||||
|
| `order` | *optionnel* | Colonne utilisée par défaut pour le tri (si l'utilisateur n'a pas choisi le tri sur une autre colonne). Si `select` est utilisé, il faut alors indiquer ici le numéro de la colonne, et non pas son nom. |
|
||||||
|
| `desc` | *optionnel* | Si ce paramètre est à `true`, l'ordre de tri sera inversé. |
|
||||||
|
| `max` | *optionnel* | Nombre d'éléments à afficher dans la liste, sur chaque page. |
|
||||||
|
| `where` | *optionnel* | Condition `WHERE` de la requête SQL. |
|
||||||
|
| `debug` | *optionnel* | Si ce paramètre existe, la requête SQL exécutée sera affichée avant le début de la boucle. |
|
||||||
|
| `explain` | *optionnel* | Si ce paramètre existe, l'explication de la requête SQL exécutée sera affichée avant le début de la boucle. |
|
||||||
|
| `disable_user_ordering` | *optionnel* | Booléen. Si ce paramètre est `true`, il ne sera pas possible à l'utilisateur d'ordonner les colonnes. |
|
||||||
|
|
||||||
|
Pour déterminer quelles colonnes afficher dans le tableau, il faut utiliser soit le paramètre `schema` pour indiquer un fichier de schéma JSON qui sera utilisé pour donner le libellé des colonnes (via la `description` indiquée dans le schéma), soit le paramètre `select`, où il faut alors indiquer le nom et le libellé des colonnes sous la forme `$$.colonne1 AS "Libellé"; $$.colonne2 AS "Libellé 2"`.
|
||||||
|
|
||||||
|
Comme pour `load`, il est possible d'utiliser des paramètres supplémentaires : `cle="valeur"`. Cela va comparer `"valeur"` avec la valeur de la clé `cle` dans le document JSON. C'est l'équivalent d'écrire `where="json_extract(document, '$.cle') = 'valeur'"`.
|
||||||
|
|
||||||
|
Pour des conditions plus complexes qu'une simple égalité, il est possible d'utiliser la syntaxe courte `$$…` dans le paramètre `where`. Ainsi `where="$$.nom LIKE 'Bourse%'` est l'équivalent de `where="json_extract(document, '$.nom') LIKE 'Bourse%'"`.
|
||||||
|
|
||||||
|
Voir [la documentation de SQLite pour plus de détails sur la syntaxe de json_extract](https://www.sqlite.org/json1.html#jex).
|
||||||
|
|
||||||
|
Note : un index SQL dynamique est créé pour chaque requête utilisant une clause `json_extract`.
|
||||||
|
|
||||||
|
Chaque itération renverra toujours ces deux variables :
|
||||||
|
|
||||||
|
| Variable | Valeur |
|
||||||
|
| :- | :- |
|
||||||
|
| `$key` | Clé unique du document |
|
||||||
|
| `$id` | Numéro unique du document |
|
||||||
|
|
||||||
|
Ainsi que chaque élément du document JSON lui-même.
|
||||||
|
|
||||||
|
La section ouvre un tableau HTML et le ferme automatiquement, donc le contenu de la section **doit** être une ligne de tableau HTML (`<tr>`).
|
||||||
|
|
||||||
|
Dans chaque ligne du tableau il faut respecter l'ordre des colonnes indiqué dans `columns` ou `select`. Une dernière colonne est réservée aux boutons d'action : `<td class="actions">...</td>`.
|
||||||
|
|
||||||
|
**Attention :** une seule liste peut être utilisée dans une même page. Avoir plusieurs listes provoquera des problèmes au niveau du tri des colonnes.
|
||||||
|
|
||||||
|
### Exemples
|
||||||
|
|
||||||
|
Lister le nom, la date et le montant des reçus fiscaux, à partir du schéma JSON suivant :
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"date": {
|
||||||
|
"description": "Date d'émission",
|
||||||
|
"type": "string",
|
||||||
|
"format": "date"
|
||||||
|
},
|
||||||
|
"adresse": {
|
||||||
|
"description": "Adresse du bénéficiaire",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"nom": {
|
||||||
|
"description": "Nom du bénéficiaire",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"montant": {
|
||||||
|
"description": "Montant",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Le code de la section sera alors comme suivant :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#list schema="./recu.schema.json" columns="nom, date, montant"}}
|
||||||
|
<tr>
|
||||||
|
<th>{{$nom}}</th>
|
||||||
|
<td>{{$date|date_short}}</td>
|
||||||
|
<td>{{$montant|raw|money_currency}}</td>
|
||||||
|
<td class="actions">
|
||||||
|
{{:linkbutton shape="eye" label="Ouvrir" href="./voir.html?id=%d"|args:$id target="_dialog"}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{else}}
|
||||||
|
<p class="alert block">Aucun reçu n'a été trouvé.</p>
|
||||||
|
{{/list}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Si le paramètre `columns` avait été omis, la colonne `adresse` aurait également été incluse.
|
||||||
|
|
||||||
|
Il est à noter que si l'utilisation directe du schéma est bien pratique, cela ne permet pas de récupérer des informations plus complexes dans la structure JSON, par exemple une sous-clé ou l'application d'une fonction SQL. Dans ce cas il faut obligatoirement utiliser `select`. Par exemple ici on veut pouvoir afficher l'année, et trier sur l'année par défaut :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#list select="$$.nom AS 'Nom du donateur' ; strftime('%Y', $$.date) AS 'Année'" order=2}}
|
||||||
|
<tr>
|
||||||
|
<th>{{$nom}}</th>
|
||||||
|
<td>{{$col2}}</td>
|
||||||
|
<td class="actions">
|
||||||
|
{{:linkbutton shape="eye" label="Ouvrir" href="./voir.html?id=%d"|args:$id target="_dialog"}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{else}}
|
||||||
|
<p class="alert block">Aucun reçu n'a été trouvé.</p>
|
||||||
|
{{/list}}
|
||||||
|
```
|
||||||
|
|
||||||
|
On peut utiliser le nom des clés du document JSON, mais sinon pour faire référence à la valeur d'une colonne spécifique dans la boucle, il faut utiliser son numéro d'ordre (qui commence à `1`, pas zéro). Ici on veut afficher l'année, donc la seconde colonne, donc `$col1`.
|
||||||
|
|
||||||
|
Noter aussi l'utilisation du numéro de la colonne de l'année (`2`) pour le paramètre `order`, qui avec `select` doit indiquer le numéro de la colonne à utiliser pour l'ordre.
|
||||||
|
|
||||||
|
<!--
|
||||||
|
TODO:
|
||||||
|
## files
|
||||||
|
|
||||||
|
Liste les fichiers du module courant, éventuellement limité à un sous-répertoire designé.
|
||||||
|
|
||||||
|
| Paramètre | Optionnel / obligatoire ? | Fonction |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `path` | optionnel | Désigne le sous-répertoire éventuel pour limiter la liste. |
|
||||||
|
| `recursive` | optionnel | Booléen. Indique si on veut aussi lister les fichiers dans les sous-répertoires. Défaut : `false`. |
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
<table>
|
||||||
|
{{#files path="facture43" recursive=false}}
|
||||||
|
<tr>
|
||||||
|
<td>{{if $is_dir}}Répertoire{{else}}{{$mime}}{{/if}}</td>
|
||||||
|
<td>{{$name}}</td>
|
||||||
|
<td>{{$size|size_in_bytes}}</td>
|
||||||
|
</tr>
|
||||||
|
{{/files}}
|
||||||
|
</table>
|
||||||
|
```
|
||||||
|
-->
|
44
doc/admin/keyboard.md
Normal file
44
doc/admin/keyboard.md
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
Title: Raccourcis claviers dans l'édition de texte — Paheko
|
||||||
|
|
||||||
|
{{{.nav
|
||||||
|
* **[Raccourcis claviers](keyboard.html)**
|
||||||
|
* [Syntaxe MarkDown complète](markdown.html)
|
||||||
|
* [Référence rapide MarkDown](markdown_quickref.html)
|
||||||
|
}}}
|
||||||
|
|
||||||
|
# Raccourcis clavier
|
||||||
|
|
||||||
|
Depuis l'édition du texte :
|
||||||
|
|
||||||
|
| Raccourci | Action |
|
||||||
|
| :- | :- |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>G</kbd> | Mettre en gras |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>I</kbd> | Mettre en italique |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>T</kbd> | Mettre en titre |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>L</kbd> | Transformer en lien |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>I</kbd> | Insérer une image |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>F</kbd> | Insérer un fichier |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>P</kbd> | Prévisualiser |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>S</kbd> | Enregistrer |
|
||||||
|
| <kbd>F11</kbd> | Activer ou désactiver l'édition plein écran |
|
||||||
|
| <kbd>F1</kbd> | Afficher l'aide |
|
||||||
|
| <kbd>Echap</kbd> | Prévisualiser (rappuyer pour revenir à l'édition) |
|
||||||
|
|
||||||
|
|
||||||
|
Depuis la prévisualisation :
|
||||||
|
|
||||||
|
| Raccourci | Action |
|
||||||
|
| :- | :- |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>P</kbd> | Retour à l'édition |
|
||||||
|
|
||||||
|
Depuis l'aide ou l'insertion de fichier :
|
||||||
|
|
||||||
|
| Raccourci | Action |
|
||||||
|
| :- | :- |
|
||||||
|
| <kbd>Echap</kbd> | Fermer et revenir à l'édition |
|
||||||
|
|
||||||
|
# Ajouter un fichier ou une image
|
||||||
|
|
||||||
|
Il est aussi possible de faire glisser et déposer une image ou un fichier sur le champ d'édition du texte pour l'envoyer et l'insérer.
|
||||||
|
|
||||||
|
De même, il est aussi possible d'utiliser le copier/coller dans le texte pour insérer un fichier ou une image.
|
709
doc/admin/markdown.md
Normal file
709
doc/admin/markdown.md
Normal file
|
@ -0,0 +1,709 @@
|
||||||
|
Title: Référence complète MarkDown — Paheko
|
||||||
|
|
||||||
|
{{{.nav
|
||||||
|
* [Raccourcis claviers](keyboard.html)
|
||||||
|
* **[Syntaxe MarkDown complète](markdown.html)**
|
||||||
|
* [Référence rapide MarkDown](markdown_quickref.html)
|
||||||
|
}}}
|
||||||
|
|
||||||
|
<<toc aside>>
|
||||||
|
|
||||||
|
# Syntaxe MarkDown
|
||||||
|
|
||||||
|
Paheko permet d'utiliser la syntaxe [MarkDown](https://fr.wikipedia.org/wiki/Markdown) dans les pages du site web.
|
||||||
|
|
||||||
|
Cette syntaxe est la plus répandue dans les outils d'édition de texte, si vous ne la connaissez pas encore, voici les règles qu'on peut utiliser pour formatter du texte avec MarkDown dans la plupart des outils (dont Paheko), ainsi que [les règles spécifiques supportées par Paheko](#extensions).
|
||||||
|
|
||||||
|
## Styles de texte
|
||||||
|
|
||||||
|
### Italique
|
||||||
|
|
||||||
|
Pour mettre un texte en italique il faut l'entourer de tirets bas ou d'astérisques :
|
||||||
|
|
||||||
|
```
|
||||||
|
Ce texte est en *italique, dingue !*
|
||||||
|
```
|
||||||
|
|
||||||
|
Donnera :
|
||||||
|
|
||||||
|
> Ce texte est en *italique, dingue !*
|
||||||
|
|
||||||
|
### Gras
|
||||||
|
|
||||||
|
Pour le gras, procéder de la même manière, mais avec deux tirets bas ou deux astérisques :
|
||||||
|
|
||||||
|
```
|
||||||
|
Ce texte est **très gras**.
|
||||||
|
```
|
||||||
|
|
||||||
|
> Ce texte est **très gras**.
|
||||||
|
|
||||||
|
### Gras et italique
|
||||||
|
|
||||||
|
Pour combiner, utiliser trois tirets ou trois astérisques :
|
||||||
|
|
||||||
|
```
|
||||||
|
Ce texte est ***gras et italique***.
|
||||||
|
```
|
||||||
|
|
||||||
|
> Ce texte est ***gras et italique***.
|
||||||
|
|
||||||
|
### Barré
|
||||||
|
|
||||||
|
Utiliser un symbole tilde pour barrer un texte :
|
||||||
|
|
||||||
|
```
|
||||||
|
Texte ~~complètement barré~~.
|
||||||
|
```
|
||||||
|
|
||||||
|
> Texte ~~complètement barré~~.
|
||||||
|
|
||||||
|
### Surligné
|
||||||
|
|
||||||
|
Il est possible de marquer une phrase ou un mot comme surligné en l'entourant de deux signes égal :
|
||||||
|
|
||||||
|
```
|
||||||
|
Ce texte est ==surligné==.
|
||||||
|
```
|
||||||
|
|
||||||
|
> Ce texte est ==surligné==.
|
||||||
|
|
||||||
|
|
||||||
|
### Code
|
||||||
|
|
||||||
|
Il est possible d'indiquer du code dans une ligne de texte avec un caractère *backtick* (accent grave en français, obtenu avec les touches [Alt Gr + 7](https://superuser.com/questions/254076/how-do-i-type-the-tick-and-backtick-characters-on-windows)) :
|
||||||
|
|
||||||
|
```
|
||||||
|
Le code `<html>` c'est rigolo !
|
||||||
|
```
|
||||||
|
|
||||||
|
> Le code `<html>` c'est rigolo !
|
||||||
|
|
||||||
|
### Avertissement sur les styles de texte
|
||||||
|
|
||||||
|
Un style de texte ne s'applique que dans un même paragraphe, il n'est pas possible d'appliquer un style sur plusieurs paragraphes :
|
||||||
|
|
||||||
|
Dans l'exemple suivant, les astérisques ne seront pas remplacées par du gras, elles resteront telles quelles :
|
||||||
|
|
||||||
|
```
|
||||||
|
Ce texte n'est pas très **gras.
|
||||||
|
|
||||||
|
Et celui-ci encore moins**.
|
||||||
|
```
|
||||||
|
|
||||||
|
> Ce texte n'est pas très **gras.
|
||||||
|
>
|
||||||
|
> Et celui-ci encore moins**.
|
||||||
|
|
||||||
|
## Liens
|
||||||
|
|
||||||
|
Créez un lien en mettant le texte désiré entre crochets et le lien associé entre parenthèses :
|
||||||
|
|
||||||
|
```
|
||||||
|
Je connais un super gestionnaire [d'association](https://paheko.cloud/) !
|
||||||
|
```
|
||||||
|
|
||||||
|
Donne :
|
||||||
|
|
||||||
|
> Je connais un super gestionnaire [d'association](https://paheko.cloud/) !
|
||||||
|
|
||||||
|
Il est possible de faire un lien vers une autre page du site web en utilisant son adresse unique :
|
||||||
|
|
||||||
|
```
|
||||||
|
N'oubliez pas de [vous inscrire à notre atelier](atelier-soudure).
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est aussi possible de simplement inclure une adresse URL et elle sera automatiquement transformée en lien :
|
||||||
|
|
||||||
|
```
|
||||||
|
https://paheko.cloud/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Blocs
|
||||||
|
|
||||||
|
### Paragraphes et retours à la ligne
|
||||||
|
|
||||||
|
Une ligne vide indique un changement de paragraphe :
|
||||||
|
|
||||||
|
```
|
||||||
|
Ceci est un paragraphe.
|
||||||
|
|
||||||
|
Ceci est est un autre.
|
||||||
|
```
|
||||||
|
|
||||||
|
Un retour à la ligne simple est traité comme tel :
|
||||||
|
|
||||||
|
```
|
||||||
|
Ceci est un
|
||||||
|
paragraphe.
|
||||||
|
```
|
||||||
|
|
||||||
|
> Ceci est un
|
||||||
|
> paragraphe.
|
||||||
|
|
||||||
|
### Titres et sous-titres
|
||||||
|
|
||||||
|
Pour faire un titre, vous devez mettre un ou plusieurs caractères *hash* (`#`) au début de la ligne.
|
||||||
|
|
||||||
|
Un titre avec un seul caractère est un titre principal (niveau 1), avec deux caractères c'est un sous-titre (niveau 2), etc. jusqu'au niveau 6.
|
||||||
|
|
||||||
|
```
|
||||||
|
# Titre principal (niveau 1)
|
||||||
|
## Sous-titre (niveau 2)
|
||||||
|
### Sous-sous-titre (niveau 3)
|
||||||
|
#### Niveau 4
|
||||||
|
##### Niveau 5
|
||||||
|
###### Dernier niveau de sous-titre (6)
|
||||||
|
```
|
||||||
|
|
||||||
|
Donnera :
|
||||||
|
|
||||||
|
> # Titre principal (niveau 1) {.no_toc}
|
||||||
|
> ## Sous-titre (niveau 2) {.no_toc}
|
||||||
|
> ### Sous-sous-titre (niveau 3) {.no_toc}
|
||||||
|
> #### Niveau 4 {.no_toc}
|
||||||
|
> ##### Niveau 5 {.no_toc}
|
||||||
|
> ###### Dernier niveau de sous-titre (6) {.no_toc}
|
||||||
|
|
||||||
|
|
||||||
|
### Listes
|
||||||
|
|
||||||
|
Vous pouvez créer des listes avec les caractères astérisque (`*`) et tiret `-` en début de ligne pour des listes non ordonnées :
|
||||||
|
|
||||||
|
```
|
||||||
|
* une élément
|
||||||
|
* un autre
|
||||||
|
- un sous élément
|
||||||
|
- un autre sous élément
|
||||||
|
* un dernier élément
|
||||||
|
```
|
||||||
|
|
||||||
|
> * une élément
|
||||||
|
> * un autre
|
||||||
|
> - un sous élément
|
||||||
|
> - un autre sous élément
|
||||||
|
> * un dernier élément
|
||||||
|
|
||||||
|
Ou avec des nombres pour des listes ordonnées :
|
||||||
|
|
||||||
|
```
|
||||||
|
1. élément un
|
||||||
|
2. élément deux
|
||||||
|
```
|
||||||
|
|
||||||
|
> 1. élément un
|
||||||
|
> 2. élément deux
|
||||||
|
|
||||||
|
L'ordre des nombres n'est pas important, seul le premier nombre est utilisé pour déterminer à quel numéro commencer la liste.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
3. A
|
||||||
|
5. B
|
||||||
|
4. C
|
||||||
|
```
|
||||||
|
|
||||||
|
> 3. A
|
||||||
|
> 5. B
|
||||||
|
> 4. C
|
||||||
|
|
||||||
|
Il est ainsi possible d'utiliser uniquement le même numéro pour ne pas avoir à numéroter sa liste :
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Un
|
||||||
|
1. Deux
|
||||||
|
```
|
||||||
|
|
||||||
|
> 1. Un
|
||||||
|
> 1. Deux
|
||||||
|
|
||||||
|
### Citations
|
||||||
|
|
||||||
|
Les citations se font en ajoutant le signe *supérieur à* (`>`) au début de la ligne :
|
||||||
|
|
||||||
|
```
|
||||||
|
> Programming is not a science. Programming is a craft.
|
||||||
|
```
|
||||||
|
|
||||||
|
> Programming is not a science. Programming is a craft.
|
||||||
|
|
||||||
|
### Code
|
||||||
|
|
||||||
|
Créez un bloc de code en indentant chaque ligne avec quatre espaces, ou en mettant trois accents graves ``` ` ``` (*backtick*, obtenu avec [Alt Gr + 7](https://superuser.com/questions/254076/how-do-i-type-the-tick-and-backtick-characters-on-windows)) sur la ligne au dessus et en dessous de votre code:
|
||||||
|
|
||||||
|
```
|
||||||
|
<html>...</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
Résultat :
|
||||||
|
|
||||||
|
```
|
||||||
|
<html>...</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tableaux
|
||||||
|
|
||||||
|
Pour créer un tableau vous devez séparer les colonnes avec des barres verticales (`|`, obtenu avec les touches [AltGr + 6](https://fr.wikipedia.org/wiki/Barre_verticale#Saisie)).
|
||||||
|
|
||||||
|
La première ligne contient les noms des colonnes, la seconde ligne contient la ligne de séparation (chaque cellule doit contenir un ou plusieurs tirets), et les lignes suivantes représentent le contenu du tableau.
|
||||||
|
|
||||||
|
```
|
||||||
|
| Colonne 1 | Colonne 2 |
|
||||||
|
| - | - | - |
|
||||||
|
| AB | CD |
|
||||||
|
```
|
||||||
|
|
||||||
|
| Colonne 1 | Colonne 2 |
|
||||||
|
| - | - |
|
||||||
|
| AB | CD |
|
||||||
|
|
||||||
|
Par défaut les colonnes sont centrées. On peut aussi aligner le texte à gauche ou à droite en mettant deux points après le ou les tirets de la ligne suivant l'entête :
|
||||||
|
|
||||||
|
```
|
||||||
|
| Aligné à gauche | Centré | Aligné à droite |
|
||||||
|
| :--------------- |:---------------:| :--------------:|
|
||||||
|
| Aligné à gauche | ce texte | Aligné à droite |
|
||||||
|
| Aligné à gauche | est | Aligné à droite |
|
||||||
|
| Aligné à gauche | centré | Aligné à droite |
|
||||||
|
```
|
||||||
|
|
||||||
|
| Aligné à gauche | Centré | Aligné à droite |
|
||||||
|
| :--------------- |:---------------:| :--------------:|
|
||||||
|
| Aligné à gauche | ce texte | Aligné à droite |
|
||||||
|
| Aligné à gauche | est | Aligné à droite |
|
||||||
|
| Aligné à gauche | centré | Aligné à droite |
|
||||||
|
|
||||||
|
### Ligne de séparation
|
||||||
|
|
||||||
|
Il suffit de mettre au moins 3 tirets à la suite sur une ligne séparée pour ajouter une ligne de séparation :
|
||||||
|
|
||||||
|
```
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
Résultat :
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Commentaires
|
||||||
|
|
||||||
|
Pour ajouter un commentaire qui ne sera pas affiché dans le texte, utiliser la syntaxe suivante :
|
||||||
|
|
||||||
|
```
|
||||||
|
<!-- Ceci est un commentaire -->
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes de bas de page
|
||||||
|
|
||||||
|
Pour créer une note de base de page, il faut mettre entre crochets un signe circonflexe (obtenu en appuyant sur la touche circonflexe, puis sur espace) suivi du numéro ou du nom de la note. Enfin, à la fin du texte il faudra répéter les crochets, le signe circonflexe, suivi de deux points et de la définition.
|
||||||
|
|
||||||
|
```
|
||||||
|
Texte très intéressant[^1]. Approuvé par 100% des utilisateurs[^Source].
|
||||||
|
|
||||||
|
[^1]: Ceci est une note de bas de page
|
||||||
|
[^Source]: Enquête Paheko sur la base de 1 personne interrogée.
|
||||||
|
```
|
||||||
|
|
||||||
|
Donnera ceci :
|
||||||
|
|
||||||
|
> Texte très intéressant[^1]. Approuvé par 100% des utilisateurs[^Source].
|
||||||
|
>
|
||||||
|
> [^1]: Ceci est une note de bas de page
|
||||||
|
> [^Source]: Enquête Paheko sur la base de 1 personne interrogée.
|
||||||
|
|
||||||
|
|
||||||
|
## Insertion de vidéos depuis un service de vidéo
|
||||||
|
|
||||||
|
Certains services vidéo comme les instances Peertube permettent l'intégration des vidéos.
|
||||||
|
|
||||||
|
Pour cela il faut recopier le code d'intégration donné par le service vidéo. Voici un exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
<iframe title="ENQUÊTE : Brûler la Forêt pour Sauver le Climat ? | EP 3 - Le bois énergie" width="560" height="315" src="https://peertube.stream/videos/embed/12c52265-e3b3-4bad-93f3-f2c1df5bbe4f" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups"></iframe>
|
||||||
|
```
|
||||||
|
|
||||||
|
Résultat :
|
||||||
|
|
||||||
|
<iframe title="ENQUÊTE : Brûler la Forêt pour Sauver le Climat ? | EP 3 - Le bois énergie" width="560" height="315" src="https://peertube.stream/videos/embed/12c52265-e3b3-4bad-93f3-f2c1df5bbe4f" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups"></iframe>
|
||||||
|
|
||||||
|
## Identifiant et classe CSS sur les titres
|
||||||
|
|
||||||
|
Il est possible de spécifier l'ID et la classe CSS d'un titre en les rajoutant à la fin du titre, entre accolades, comme ceci :
|
||||||
|
|
||||||
|
```
|
||||||
|
## Titre de niveau 2 {#titre2} {.text-center}
|
||||||
|
```
|
||||||
|
|
||||||
|
Le code HTML résultant sera comme ceci :
|
||||||
|
|
||||||
|
```
|
||||||
|
<h2 id="titre2" class="text-center">Titre de niveau 2</h2>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Classes CSS
|
||||||
|
|
||||||
|
Il est possible de donner une classe CSS parente à un ensemble d'éléments en les mettant au centre d'un bloc définissant cette classe :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{{.custom-quote .custom-block
|
||||||
|
|
||||||
|
Paragraphe
|
||||||
|
|
||||||
|
> Citation
|
||||||
|
}}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Créera le code HTML suivant :
|
||||||
|
|
||||||
|
```
|
||||||
|
<div class="custom-quote custom-block">
|
||||||
|
|
||||||
|
<p>Paragraphe</p>
|
||||||
|
|
||||||
|
<blockquote><p>Citation</p></blockquote>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tags HTML
|
||||||
|
|
||||||
|
Certains tags HTML sont autorisés :
|
||||||
|
|
||||||
|
| Tag | Utilisation | Exemple |
|
||||||
|
| :- | :- | :- |
|
||||||
|
| `<kbd>` | Touches de clavier | <kbd>Ctrl</kbd> + <kbd>B</kbd> |
|
||||||
|
| `<samp>` | Exemple de programme en console | <samp>bohwaz@platypus ~ % sudo apt install paheko</samp> |
|
||||||
|
| `<var>` | Variable dans un programme informatique | <var>ab</var> + <var>cd</var> = 42 |
|
||||||
|
| `<del>` | Texte supprimé | Texte <del>supprimé</del> |
|
||||||
|
| `<ins>` | Texte ajouté | Texte <ins>ajouté</ins> |
|
||||||
|
| `<sup>` | Texte en exposant | Texte<sup>exposant</sup> |
|
||||||
|
| `<sub>` | Texte en indice | Texte<sub>indice</sub> |
|
||||||
|
| `<mark>` | Texte surligné | Texte <mark>surligné</mark> |
|
||||||
|
| `<audio>` | Insérer un lecteur audio dans la page | `<audio src="mon_fichier.mp3">` |
|
||||||
|
| `<video>` | Insérer une vidéo dans la page | `<video src="mon_fichier.webm">` |
|
||||||
|
|
||||||
|
Mais leurs possibilités sont limitées, notamment sur les attributs autorisés.
|
||||||
|
|
||||||
|
# Extensions
|
||||||
|
|
||||||
|
Paheko propose des extensions au langage MarkDown, qui n'existent pas dans les autres logiciels utilisant aussi MarkDown.
|
||||||
|
|
||||||
|
Toutes ces extensions se présentent sous la forme d'un code situé entre deux signes **inférieur à** (`<<`) et deux signes **supérieur à** (`>>`), à ne pas confondre avec les guillements français (`«` et `»`).
|
||||||
|
|
||||||
|
## Images jointes
|
||||||
|
|
||||||
|
Il est possible d'intégrer une image jointe à la page web en plaçant le code suivant sur une ligne (sans autre texte) :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<image|Nom_fichier.jpg|Alignement|Légende>>
|
||||||
|
```
|
||||||
|
|
||||||
|
* `Nom_fichier.jpg` : remplacer par le nom du fichier de l'image (parmi les images jointes à la page)
|
||||||
|
* `Alignement` : remplacer par l'alignement :
|
||||||
|
* `gauche` ou `left` : l'image sera placée à gauche en petit (200 pixels), le texte remplira l'espace laissé sur la droite de l'image ;
|
||||||
|
* `droite` ou `right` : l'image sera placée à droite en petit, le texte remplira l'espace laissé sur la gauche de l'image ;
|
||||||
|
* `centre` ou `center` : l'image sera placée au centre en taille moyenne (500 pixels), le texte sera placé au dessus et en dessous.
|
||||||
|
* Légende : indiquer ici une courte description de l'image.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<image|mon_image.png|center|Ceci est une belle image>>
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est aussi possible d'utiliser la syntaxe avec des paramètres nommés :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<image file="Nom_fichier.jpg" align="center" caption="Légende">>
|
||||||
|
```
|
||||||
|
|
||||||
|
Les images qui ne sont pas mentionnées dans le texte seront affichées après le texte sous forme de galerie.
|
||||||
|
|
||||||
|
## Galerie d'images
|
||||||
|
|
||||||
|
Il est possible d'afficher une galerie d'images (sous forme d'images miniatures) avec la balise `<<gallery` qui contient la liste des images à mettre dans la galerie :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<gallery
|
||||||
|
Nom_fichier.jpg
|
||||||
|
Nom_fichier_2.jpg
|
||||||
|
>>
|
||||||
|
```
|
||||||
|
|
||||||
|
Si aucun nom de fichier n'est indiqué, alors toutes les images jointes à la page seront affichées :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<gallery>>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Diaporama d'images
|
||||||
|
|
||||||
|
On peut également afficher cette galerie sous forme de diaporama. Dans ce cas une seule image est affichée, et on peut passer de l'une à l'autre.
|
||||||
|
|
||||||
|
La syntaxe est la même, mais on ajoute le mot `slideshow` après le mot `gallery` :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<gallery slideshow
|
||||||
|
Nom_fichier.jpg
|
||||||
|
Nom_fichier_2.jpg
|
||||||
|
>>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fichiers joints
|
||||||
|
|
||||||
|
Pour créer un bouton permettant de voir ou télécharger un fichier joint à la page web, il suffit d'utiliser la syntaxe suivante :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<file|Nom_fichier.ext|Libellé>>
|
||||||
|
```
|
||||||
|
|
||||||
|
* `Nom_fichier.ext` : remplacer par le nom du fichier (parmi les fichiers joints à la page)
|
||||||
|
* `Libellé` : indique le libellé du qui sera affiché sur le bouton, si aucun libellé n'est indiqué alors c'est le nom du fichier qui sera affiché
|
||||||
|
|
||||||
|
## Vidéos
|
||||||
|
|
||||||
|
Pour inclure un lecteur vidéo dans la page web à partir d'un fichier vidéo joint à la page, il faut utiliser le code suivant :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<video|Nom_du_fichier.ext>>
|
||||||
|
```
|
||||||
|
|
||||||
|
On peut aussi spécifier d'autres paramètres :
|
||||||
|
|
||||||
|
* `file` : nom du fichier vidéo
|
||||||
|
* `poster` : nom de fichier d'une image utilisée pour remplacer la vidéo avant qu'elle ne soit lue
|
||||||
|
* `subtitles` : nom d'un fichier de sous-titres au format VTT ou SRT
|
||||||
|
* `width` : largeur de la vidéo (en pixels)
|
||||||
|
* `height` : hauteur de la vidéo (en pixels)
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<video file="Ma_video.webm" poster="Ma_video_poster.jpg" width="640" height="360" subtitles="Ma_video_sous_titres.vtt">>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sommaire / table des matières automatique
|
||||||
|
|
||||||
|
Il est possible de placer le code `<<toc>>` pour générer un sommaire automatiquement à partir des titres et sous-titres :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<toc>>
|
||||||
|
```
|
||||||
|
|
||||||
|
Affichera un sommaire comme celui-ci :
|
||||||
|
|
||||||
|
<<toc>>
|
||||||
|
|
||||||
|
Il est possible de limiter les niveaux en utilisant le paramètre `level` comme ceci :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<toc level=1>>
|
||||||
|
```
|
||||||
|
|
||||||
|
N'affichera que les titres de niveau 1 (précédés d'un seul signe hash `#`), comme ceci :
|
||||||
|
|
||||||
|
<<toc level=1>>
|
||||||
|
|
||||||
|
Enfin il est possible de placer la table des matières sur le côté du texte, en utilisant le paramètre `aside` :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<toc level=1 aside>>
|
||||||
|
```
|
||||||
|
|
||||||
|
Note : en plus de la syntaxe `<<toc>>`, Paheko supporte aussi les syntaxes suivantes par compatibilité avec [les autres moteurs de rendu MarkDown](https://alexharv074.github.io/2018/08/28/auto-generating-markdown-tables-of-contents.html) : `{:toc}` `[[_TOC_]]` `[toc]`.
|
||||||
|
|
||||||
|
### Exclure un sous-titre du sommaire
|
||||||
|
|
||||||
|
Il est aussi possible d'indiquer qu'un titre ne doit pas être inclus dans le sommaire en utilisant la classe `no_toc` comme ceci :
|
||||||
|
|
||||||
|
```
|
||||||
|
## Sous-titre non-inclus {.no_toc}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Grilles et colonnes
|
||||||
|
|
||||||
|
Pour une mise en page plus avancée, il est possible d'utiliser les *grilles*, adaptation des [grids en CSS](https://developer.mozilla.org/fr/docs/Web/CSS/CSS_Grid_Layout). Il faut utiliser la syntaxe `<<grid>>...Contenu...<</grid>>`.
|
||||||
|
|
||||||
|
Attention, les blocs `<<grid>>` et `<</grid>>` doivent obligatoirement être placés sur des lignes qui ne contiennent rien d'autre.
|
||||||
|
|
||||||
|
**Note :** sur petit écran (mobile ou tablette) les grilles et colonnes sont désactivées, tout sera affiché dans une seule colonne, comme si les grilles n'étaient pas utilisées.
|
||||||
|
|
||||||
|
Pour spécifier le nombre de colonnes on peut utiliser un raccourci qui *mime* les colonnes, comme ceci :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<grid !!>>
|
||||||
|
```
|
||||||
|
|
||||||
|
Ce code indique qu'on veut créer une grille de 2 colonnes de largeur identique.
|
||||||
|
|
||||||
|
Dans les raccourcis, le point d'exclamation `!` indique une colonne simple, et le hash `#` indique une colonne qui prend le reste de la place selon le nombre de colonnes total.
|
||||||
|
|
||||||
|
D'autres exemples de raccourcis :
|
||||||
|
|
||||||
|
* `!!` : deux colonnes de largeur égale
|
||||||
|
* `!!!` : trois colonnes de largeur égale
|
||||||
|
* `!##` : deux colonnes, la première occupant un tiers de la largeur, la seconde occupant les deux tiers
|
||||||
|
* `!##!` : 4 colonnes, la première occupant un quart de la largeur, la seconde occupant la moitié, la dernière occupant le quart
|
||||||
|
|
||||||
|
Alternativement, pour plus de contrôle, ce bloc accepte les paramètres suivants :
|
||||||
|
|
||||||
|
* `short` : notation courte décrite ci-dessus
|
||||||
|
* `gap` : espacement entre les blocs de la grille
|
||||||
|
* `template` : description CSS complète de la grille (propriété [`grid-template`](https://developer.mozilla.org/fr/docs/Web/CSS/grid-template))
|
||||||
|
|
||||||
|
Après ce premier bloc `<<grid>>` qui définit la forme de la grille, on peut entrer le contenu de la première colonne.
|
||||||
|
|
||||||
|
Pour créer la seconde colonne il faut simplement placer un nouveau bloc `<<grid>>` vide (aucun paramètre) sur une ligne.
|
||||||
|
|
||||||
|
Enfin on termine en fermant la grille avec un block `<</grid>>`. Voici un exemple complet :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<grid !!!>>
|
||||||
|
Col. 1
|
||||||
|
<<grid>>
|
||||||
|
Col. 2
|
||||||
|
<<grid>>
|
||||||
|
Col. 3
|
||||||
|
<</grid>>
|
||||||
|
```
|
||||||
|
|
||||||
|
<<grid short="!!!" debug>>
|
||||||
|
Col. 1
|
||||||
|
<<grid>>
|
||||||
|
Col. 2
|
||||||
|
<<grid>>
|
||||||
|
Col. 3
|
||||||
|
<</grid>>
|
||||||
|
|
||||||
|
Exemple avec 3 colonnes, dont 2 petites et une large :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<grid !##!>>
|
||||||
|
Col. 1
|
||||||
|
<<grid>>
|
||||||
|
Colonne 2 large
|
||||||
|
<<grid>>
|
||||||
|
Col. 3
|
||||||
|
<</grid>>
|
||||||
|
```
|
||||||
|
|
||||||
|
<<grid short="!##!" debug>>
|
||||||
|
Col. 1
|
||||||
|
<<grid>>
|
||||||
|
Colonne 2 large
|
||||||
|
<<grid>>
|
||||||
|
Col. 3
|
||||||
|
<</grid>>
|
||||||
|
|
||||||
|
Il est possible de créer plus de blocs qu'il n'y a de colonnes, cela créera une nouvelle ligne avec le même motif :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<grid !!>>
|
||||||
|
L1 C1
|
||||||
|
<<grid>>
|
||||||
|
L1 C2
|
||||||
|
<<grid>>
|
||||||
|
L2 C1
|
||||||
|
<<grid>>
|
||||||
|
L2 C2
|
||||||
|
<</grid>>
|
||||||
|
```
|
||||||
|
|
||||||
|
<<grid short="!!" debug>>
|
||||||
|
L1 C1
|
||||||
|
<<grid>>
|
||||||
|
L1 C2
|
||||||
|
<<grid>>
|
||||||
|
L2 C1
|
||||||
|
<<grid>>
|
||||||
|
L2 C2
|
||||||
|
<</grid>>
|
||||||
|
|
||||||
|
Enfin, il est possible d'utiliser la notation CSS [`grid-row`](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row) et [`grid-column`](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column) pour chaque bloc, permettant de déplacer les blocs, ou de faire en sorte qu'un bloc s'étende sur plusieurs colonnes ou plusieurs lignes. Pour cela il faut utiliser le paramètre `row` ou `column` qui précède le bloc :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<grid short="#!!" column="span 2">>
|
||||||
|
A
|
||||||
|
<<grid row="span 2">>
|
||||||
|
B
|
||||||
|
<<grid>>
|
||||||
|
C
|
||||||
|
<<grid>>
|
||||||
|
D
|
||||||
|
<</grid>>
|
||||||
|
```
|
||||||
|
|
||||||
|
<<grid short="#!!" debug column="span 2">>
|
||||||
|
A
|
||||||
|
<<grid row="span 2">>
|
||||||
|
B
|
||||||
|
<<grid>>
|
||||||
|
C
|
||||||
|
<<grid>>
|
||||||
|
D
|
||||||
|
<</grid>>
|
||||||
|
|
||||||
|
Noter que dans ce cas on doit utiliser la notation `short="…"` pour pouvoir utiliser les autres paramètres.
|
||||||
|
|
||||||
|
Enfin, il est possible d'aligner un bloc verticalement par rapport aux autres en utilisant le paramètre `align` (équivalent de la propriété CSS [`align-self`](https://developer.mozilla.org/en-US/docs/Web/CSS/align-self)).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Alignement du texte
|
||||||
|
|
||||||
|
Il suffit de placer sur une ligne seule le code `<<center>>` pour centrer du texte :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<center>>
|
||||||
|
Texte centré
|
||||||
|
<</center>>
|
||||||
|
```
|
||||||
|
|
||||||
|
On peut procéder de même avec `<<left>>` et `<<right>>` pour aligner à gauche ou à droite.
|
||||||
|
|
||||||
|
## Couleurs
|
||||||
|
|
||||||
|
Comme sur les [Skyblogs](https://decoblog.skyrock.com/), il est possible de mettre en couleur le texte et le fond, et même de créer des dégradés !
|
||||||
|
|
||||||
|
Utiliser la syntaxe `<<color COULEUR>>...texte...<</color>>` pour changer la couleur du texte, ou `<<bgcolor COULEUR>>...texte...<</bgcolor>>` pour la couleur du fond.
|
||||||
|
|
||||||
|
Il est possible d'indiquer plusieurs couleurs, séparées par des espaces, pour créer des dégradés.
|
||||||
|
|
||||||
|
```
|
||||||
|
<<color red>>Rouge !<</color>>
|
||||||
|
<<bgcolor yellow>>Fond jaune pétant !<</bgcolor>>
|
||||||
|
<<color cyan green salmon>>Dégradé de texte !<</color>>
|
||||||
|
<<bgcolor chocolate khaki orange>>Dégradé du fond<</bgcolor>>
|
||||||
|
|
||||||
|
<<bgcolor darkolivegreen darkseagreen >>
|
||||||
|
<<color darkred>>
|
||||||
|
|
||||||
|
## Il est aussi possible de faire des blocs colorés
|
||||||
|
|
||||||
|
Avec des paragraphes
|
||||||
|
|
||||||
|
> Et citations
|
||||||
|
|
||||||
|
<</color>>
|
||||||
|
<</bgcolor>>
|
||||||
|
```
|
||||||
|
|
||||||
|
> <<color red>>Rouge !<</color>>
|
||||||
|
> <<bgcolor yellow>>Fond jaune pétant !<</bgcolor>>
|
||||||
|
> <<color cyan green salmon>>Dégradé de texte !<</color>>
|
||||||
|
> <<bgcolor chocolate khaki orange>>Dégradé du fond<</bgcolor>>
|
||||||
|
>
|
||||||
|
> <<bgcolor greenyellow indianred>>
|
||||||
|
> <<color darkred darkgreen>>
|
||||||
|
> ## Il est aussi possible de faire des blocs colorés {.no_toc}
|
||||||
|
>
|
||||||
|
> Avec des paragraphes
|
||||||
|
>
|
||||||
|
> > Et citations
|
||||||
|
>
|
||||||
|
> <</color>>
|
||||||
|
> <</bgcolor>>
|
||||||
|
|
||||||
|
Il est possible d'utiliser les couleurs avec [leur nom](https://developer.mozilla.org/en-US/docs/Web/CSS/named-color) ou leur code hexadécimal (exemple : `#ff0000` pour rouge).
|
||||||
|
|
||||||
|
**Attention : cette fonctionnalité est rigolote mais doit être utilisé avec parcimonie, en effet cela risque de rendre le texte illisible, notamment pour les personnes daltoniennes.**
|
55
doc/admin/markdown_quickref.md
Normal file
55
doc/admin/markdown_quickref.md
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
Title: Référence rapide MarkDown — Paheko
|
||||||
|
|
||||||
|
{{{.nav
|
||||||
|
* [Raccourcis claviers](keyboard.html)
|
||||||
|
* [Syntaxe MarkDown complète](markdown.html)
|
||||||
|
* **[Référence rapide MarkDown](markdown_quickref.html)**
|
||||||
|
}}}
|
||||||
|
|
||||||
|
# Référence rapide MarkDown
|
||||||
|
|
||||||
|
|Nom | Syntaxe | Rendu | Notes |
|
||||||
|
| :- | :- | :- | :- |
|
||||||
|
| Italique | `*italique*` | *italique* | |
|
||||||
|
| Gras | `**gras**` | **gras** | |
|
||||||
|
| Gras et italique | `***gras et italique***` | ***gras et italique*** | |
|
||||||
|
| Barré | `~~barré~~` | ~~barré~~ | [^P] |
|
||||||
|
| Surligné | `==surligné==` | ==surligné== | [^P] |
|
||||||
|
| Lien | `[Libellé du lien](adresse)` | [Libellé du lien](https://paheko.cloud/) | |
|
||||||
|
| Titre niveau 1 | `# Titre 1` | <h1>Titre 1</h1> | |
|
||||||
|
| Titre niveau 2 | `## Titre 2` | <h2>Titre 2</h2> | |
|
||||||
|
| Titre niveau 3 | `### Titre 3` | <h3>Titre 3</h3> | |
|
||||||
|
| Titre niveau 4 | `#### Titre 4` | <h4>Titre 4</h4> | |
|
||||||
|
| Titre niveau 5 | `##### Titre 5` | <h5>Titre 5</h5> | |
|
||||||
|
| Titre niveau 6 | `###### Titre 6` | <h6>Titre 6</h6> | |
|
||||||
|
| Liste | <pre><code>\* Liste 1<br>\* Liste 2</code></pre> | <ul><li>Liste 1</li><li>Liste 2</li></ul> | |
|
||||||
|
| Liste imbriquée | <pre><code>\* Liste 1<br> \* Sous-liste 1</code></pre> | <ul><li>Liste 1<ul><li>Sous-liste 1</li></ul></li></ul> | |
|
||||||
|
| Liste numérotée | <pre><code>1. Liste 1<br>2. Liste 2</code></pre> | <ol><li>Liste 1</li><li>Liste 2</li></ol> | |
|
||||||
|
| Code dans du texte | Voir ce <code>\`code\`</code> | Voir ce `code` | |
|
||||||
|
| Bloc de code | <pre><code>\```<br>Bloc de code<br>\```</code></pre> | <pre><code>Bloc de code</code></pre> | |
|
||||||
|
| Citation | <pre><code>> Citation<br>> Citation</code></pre> | <blockquote>Citation<br>Citation</blockquote> | |
|
||||||
|
| Tableau | <pre><code>\| Colonne 1 \| Colonne 2 \|<br>\| - \| - \|<br>\| A \| B \|</code></pre> | <table><thead><tr><th>Colonne 1</th><th>Colonne 2</th></tr></thead><tbody><tr><td>A</td><td>B</td></tr></tbody></table> | |
|
||||||
|
| Ligne horizontale | `----` | <hr /> | |
|
||||||
|
| Référence à une note de bas de page | `[^1]` | [^1] | [^P] |
|
||||||
|
| Définition d'une note de bas de page | <pre><code>\[^1]: Définition</code></pre> | [^1] | [^P] |
|
||||||
|
| Bloc avec classe CSS | <pre><code>{{{.boutons<br />* [Paheko](https://paheko.cloud/)<br />}}}</code></pre> | <div class="boutons"><ul><li><a href="https://paheko.cloud/">Paheko</a></li></ul></div> | [^P] |
|
||||||
|
| Sommaire / table des matières | `<<toc>>` | *(ne peut être montré sur cette page)* | [^P] |
|
||||||
|
| Image jointe | `<<image|nom_image.jpg|center|Légende>>` | *(ne peut être montré sur cette page)* | [^P] |
|
||||||
|
| Fichier joint | `<<file|nom_fichier.pdf|Libellé>>` | *(ne peut être montré sur cette page)* | [^P] |
|
||||||
|
| Grille à 2 colonnes | <pre><code>\<<grid !!>><br>Colonne 1<br><br>\<<grid>><br>Colonne 2<br><br>\<</grid>></code></pre> | *(ne peut être montré sur cette page)* | [^P] |
|
||||||
|
| Texte centré | `<<center>>Centre<</center>>` | <div style="text-align: center;">Centre</div> | [^P] |
|
||||||
|
| Texte aligné à droite | `<<right>>Droite<</right>>` | <div style="text-align: right;">Droite</div> | [^P] |
|
||||||
|
| Texte coloré | `<<color red>>Rouge<</color>>` | <<color red>>Rouge<</color>> | [^P] |
|
||||||
|
| Fond coloré | `<<bgcolor green>>Vert<</color>>` | <<bgcolor green>>Vert<</color>> | [^P] |
|
||||||
|
| Dégradé de texte | `<<color orange cyan>>Orange à cyan<</color>>` | <<color orange cyan>>Orange à cyan<</color>> | [^P] |
|
||||||
|
| Dégradé de fond | `<<bgcolor orange cyan>>Orange à cyan<</color>>` | <<bgcolor orange cyan>>Orange à cyan<</color>> | [^P] |
|
||||||
|
| Clavier | `<kbd>Ctrl</kbd> + <kbd>C</kbd>` | <kbd>Ctrl</kbd> + <kbd>C</kbd> | |
|
||||||
|
| Exemple console | `<samp>Exemple</samp>` | <samp>Exemple</samp> | |
|
||||||
|
| Variable maths | `<var>ab</var> + <var>cd</var> = 42` | <var>ab</var> + <var>cd</var> = 42 | |
|
||||||
|
| Texte supprimé | `<del>supprimé</del>` | <del>supprimé</del> | |
|
||||||
|
| Texte ajouté | `<ins>ajouté</ins>` | <ins>ajouté</ins> | |
|
||||||
|
| Exposant | `Texte<sup>exposant</sup>` | Texte<sup>exposant</sup> | |
|
||||||
|
| Indice | `Texte<sub>indice</sub>` | Texte<sub>indice</sub> | |
|
||||||
|
|
||||||
|
[^1]: Exemple de note de bas de page
|
||||||
|
[^P]: Indique une syntaxe qui ne fait pas partie du standard Markdown, mais est spécifique à Paheko.
|
338
doc/admin/modules.md
Normal file
338
doc/admin/modules.md
Normal file
|
@ -0,0 +1,338 @@
|
||||||
|
Title: Développer des modules pour Paheko
|
||||||
|
|
||||||
|
{{{.nav
|
||||||
|
* **[Modules](modules.html)**
|
||||||
|
* [Documentation Brindille](brindille.html)
|
||||||
|
* [Fonctions](brindille_functions.html)
|
||||||
|
* [Sections](brindille_sections.html)
|
||||||
|
* [Filtres](brindille_modifiers.html)
|
||||||
|
}}}
|
||||||
|
|
||||||
|
<<toc aside>>
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
Depuis la version 1.3, Paheko dispose d'extensions modifiables, nommées **Modules**.
|
||||||
|
|
||||||
|
Les modules permettent de créer et modifier des formulaires, des modèles de documents simples, à imprimer, mais aussi de créer des "mini-applications" directement dans l'administration de l'association, avec le minimum de code, sans avoir à apprendre à programmer PHP.
|
||||||
|
|
||||||
|
Les modules utilisent le langage [Brindille](brindille.html), aussi utilisé pour le site web (qui est lui-même un module). Avec Brindille on parle d'un **squelette** pour un fichier texte contenant du code Brindille.
|
||||||
|
|
||||||
|
Les modules ne permettent pas d'exécuter du code PHP, ni de modifier la base de données en dehors des données du module, contrairement aux [plugins](https://fossil.kd2.org/paheko/wiki?name=Documentation/Plugin&p). Grâce à Brindille, les administrateurs de l'association peuvent modifier ou créer de nouveaux modules sans risques pour le serveur, car le code Brindille ne permet pas d'exécuter de fonctions dangereuses. Les **plugins** eux sont écrits en PHP et ne peuvent pas être modifiés par une association. Du fait des risques de sécurité, seuls les plugins officiels sont proposés sur Paheko.cloud.
|
||||||
|
|
||||||
|
# Exemples
|
||||||
|
|
||||||
|
Paheko fournit quelques modules par défaut, qui peuvent être modifiés ou servir d'inspiration pour de nouveaux modules :
|
||||||
|
|
||||||
|
* Reçu de don simple
|
||||||
|
* Reçu de paiement simple
|
||||||
|
* Reçu fiscal
|
||||||
|
* Cartes de membres
|
||||||
|
* Heures d'ouverture
|
||||||
|
* Modèles d'écritures comptables
|
||||||
|
|
||||||
|
Ces exemples sont développés directement avec Brindille et peuvent être modifiés ou lus depuis le menu **Configuration**, onglet **Extensions**.
|
||||||
|
|
||||||
|
Un module fourni dans Paheko peut être modifié, et en cas de problème il peut être remis à son état d'origine.
|
||||||
|
|
||||||
|
D'autres exemples d'utilisation sont imaginables :
|
||||||
|
|
||||||
|
* Auto-remplissage de la déclaration de la liste des dirigeants à la préfecture
|
||||||
|
* Compte de résultat et bilan conforme au modèle du plan comptable
|
||||||
|
* Formulaires partagés entre la partie privée, et le site web (voir par exemple le module "heures d'ouverture")
|
||||||
|
* Gestion de matériel prêté par l'association
|
||||||
|
|
||||||
|
# Pré-requis
|
||||||
|
|
||||||
|
Une connaissance de la programmation informatique est souhaitable pour commencer à modifier ou créer des modules, mais cela n'est pas requis, il est possible d'apprendre progressivement.
|
||||||
|
|
||||||
|
# Résumé technique
|
||||||
|
|
||||||
|
* Utilisation de la syntaxe Brindille
|
||||||
|
* Les modules peuvent utiliser toutes les fonctions et boucles de Brindille
|
||||||
|
* Les modules peuvent stocker et récupérer des données dans la base SQLite dans une table clé-valeur spécifique à chaque module
|
||||||
|
* Les données du module sont stockées en JSON, on peut faire des requêtes complètes avec l'extension [JSON de SQLite](https://www.sqlite.org/json1.html)
|
||||||
|
* Les données peuvent être validées avant enregistrement en utilisant [JSON Schema](https://json-schema.org/understanding-json-schema/)
|
||||||
|
* Un module peut également accéder aux données des autres modules
|
||||||
|
* Un module peut aussi accéder à toutes les données de la base de données, sauf certaines données à risque (voir plus bas)
|
||||||
|
* Un module ne peut pas modifier les données de la base de données
|
||||||
|
* Paheko crée automatiquement des index sur les requêtes SQL des modules, permettant de rendre les requêtes rapides
|
||||||
|
|
||||||
|
# Structure des répertoires
|
||||||
|
|
||||||
|
Chaque module a un nom unique (composé uniquement de lettres minuscules, de tirets bas et de chiffres) et dispose d'un sous-répertoire dans le dossier `modules`. Ainsi le module `recu_don` serait dans le répertoire `modules/recu_don`.
|
||||||
|
|
||||||
|
Dans ce répertoire le module peut avoir autant de fichiers qu'il veut, mais certains fichiers ont une fonction spéciale :
|
||||||
|
|
||||||
|
* `module.ini` : contient les informations sur le module, voir ci-dessous pour les détails
|
||||||
|
* `config.html` : si ce squelette existe, un bouton "Configurer" apparaîtra dans la liste des modules (Configuration -> Modules) et affichera ce squelette dans un dialogue
|
||||||
|
* `icon.svg` : icône du module, qui sera utilisée sur la page d'accueil, si le bouton est activé, et dans la liste des modules. Attention l'élément racine du fichier doit porter l'id `img` pour que l'icône fonctionne (`<svg id="img"...>`), notamment pour que les couleurs du thème s'appliquent à l'icône.
|
||||||
|
* `README.md` : si ce fichier existe, son contenu sera affiché dans les détails du module
|
||||||
|
|
||||||
|
## Snippets
|
||||||
|
|
||||||
|
Les modules peuvent également avoir des `snippets`, ce sont des squelettes qui seront inclus à des endroits précis de l'interface, permettant de rajouter des fonctionnalités, ils sont situés dans le sous-répertoire `snippets` du module :
|
||||||
|
|
||||||
|
* `snippets/transaction_details.html` : sera inclus en dessous de la fiche d'une écriture comptable
|
||||||
|
* `snippets/transaction_new.html` : sera inclus au début du formulaire de saisie d'écriture
|
||||||
|
* `snippets/user_details.html` : sera inclus en dessous de la fiche d'un membre
|
||||||
|
* `snippets/my_details.html` : sera inclus en dessous de la page "Mes informations personnelles"
|
||||||
|
* `snippets/my_services.html` : sera inclus en dessous de la page "Mes inscriptions et cotisations"
|
||||||
|
* `snippets/home_button.html` : sera inclus dans la liste des boutons de la page d'accueil (ce fichier ne sera pas appelé si `home_button` est à `true` dans `module.ini`, il le remplace)
|
||||||
|
|
||||||
|
### Snippets MarkDown
|
||||||
|
|
||||||
|
Il est également possible, depuis Paheko 1.3.2, d'étendre les fonctionnalités Markdown du site web en créant un snippet dans le répertoire `snippets/markdown/`, par exemple `snippets/markdown/map.html`.
|
||||||
|
|
||||||
|
Le snippet sera appelé quand on utilise le tag du même nom dans le contenu du site web. Ici par exemple ça serait `<<map>>`.
|
||||||
|
|
||||||
|
Le nom du snippet doit commencer par une lettre minuscule et peut être suivi de lettres minuscules, de chiffres, ou de tirets bas. Exemples : `map2024` `map_openstreetmap`, etc.
|
||||||
|
|
||||||
|
Le snippet reçoit ces variables :
|
||||||
|
|
||||||
|
* `$params` : les paramètres du tag
|
||||||
|
* `$block` : booléen, `TRUE` si le tag est seul sur une ligne, ou `FALSE` s'il se situe à l'intérieur d'un texte
|
||||||
|
* `$content` : le contenu du bloc, si celui-ci est sur plusieurs lignes
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<map center="Auckland, New Zealand"
|
||||||
|
|
||||||
|
Ceci est la capitale de Nouvelle-Zélande !
|
||||||
|
>>
|
||||||
|
|
||||||
|
Voici un marqueur : <<map marker>>
|
||||||
|
```
|
||||||
|
|
||||||
|
Dans le premier appel, `map.html` recevra ces variables :
|
||||||
|
|
||||||
|
```
|
||||||
|
$params = ['center' => 'Auckland, New Zealand']
|
||||||
|
$content = "Ceci est la capitale de Nouvelle-Zélande !"
|
||||||
|
$block = TRUE
|
||||||
|
```
|
||||||
|
|
||||||
|
Dans le second appel, le snippet recevra celles-ci :
|
||||||
|
|
||||||
|
```
|
||||||
|
$params = [0 => 'marker']
|
||||||
|
$content = NULL
|
||||||
|
$block = FALSE
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fichier module.ini
|
||||||
|
|
||||||
|
Ce fichier décrit le module, au format INI (`clé=valeur`), en utilisant les clés suivantes :
|
||||||
|
|
||||||
|
* `name` (obligatoire) : nom du module
|
||||||
|
* `description` : courte description de la fonctionnalité apportée par le module
|
||||||
|
* `author` : nom de l'auteur
|
||||||
|
* `author_url` : adresse web HTTP menant au site de l'auteur
|
||||||
|
* `home_button` : indique si un bouton pour ce module doit être affiché sur la page d'accueil (`true` ou `false`)
|
||||||
|
* `menu` : indique si ce module doit être listé dans le menu de gauche (`true` ou `false`)
|
||||||
|
* `restrict_section` : indique la section auquel le membre doit avoir accès pour pouvoir voir le menu de ce module, parmi `web, documents, users, accounting, connect, config`
|
||||||
|
* `restrict_level` : indique le niveau d'accès que le membre doit avoir dans la section indiquée pour pouvoir voir le menu de ce module, parmi `read, write, admin`.
|
||||||
|
|
||||||
|
Attention : les directives `restrict_section` et `restrict_level` ne contrôlent *que* l'affichage du lien vers le module dans le menu et dans les boutons de la page d'accueil, mais pas l'accès aux pages du module.
|
||||||
|
|
||||||
|
# Variables spéciales
|
||||||
|
|
||||||
|
Toutes les pages d'un module disposent de la variable `$module` qui contient l'entité du module en cours :
|
||||||
|
|
||||||
|
* `$module.name` contient le nom unique (`recu_don` par exemple)
|
||||||
|
* `$module.label` le libellé du module
|
||||||
|
* `$module.description` la description
|
||||||
|
* `$module.config` la configuration du module
|
||||||
|
* `$module.url` l'adresse URL du module (`https://site-association.tld/m/recu_don/` par exemple)
|
||||||
|
|
||||||
|
# Stockage de données
|
||||||
|
|
||||||
|
Un module peut stocker des données de deux manières : dans sa configuration, ou dans son stockage de documents JSON.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
La première manière est de stocker des informations dans la configuration du module. Pour cela on utilise la fonction `save` et la clé `config` :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:save key="config" accounts_list="512A,512B" check_boxes=true}}
|
||||||
|
```
|
||||||
|
|
||||||
|
On pourra retrouver ces valeurs dans la variable `$module.config` :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{if $module.config.check_boxes}}
|
||||||
|
{{$module.config.accounts_list}}
|
||||||
|
{{/if}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Stockage de documents JSON
|
||||||
|
|
||||||
|
Chaque module peut stocker ses données dans une base de données clé-document qui stockera les données dans des documents au format JSON dans une table SQLite.
|
||||||
|
|
||||||
|
Grâce aux [fonctions JSON de SQLite](https://www.sqlite.org/json1.html) on pourra ensuite effectuer des recherches sur ces documents.
|
||||||
|
|
||||||
|
Pour enregistrer il suffit d'utiliser la fonction `save` :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:save key="facture001" type="facture" date="2022-01-01" label="Vente de petits pains au chocolat" total="42"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Si la clé indiquée (dans le paramètre `key`) n'existe pas, l'enregistrement sera créé, sinon il sera mis à jour avec les valeurs données.
|
||||||
|
|
||||||
|
### Validation
|
||||||
|
|
||||||
|
On peut utiliser un [schéma JSON](https://json-schema.org/understanding-json-schema/) pour valider que le document qu'on enregistre est valide :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:save validate_schema="./document.schema.json" type="facture" date="2022-01-01" label="Vente de petits pains au chocolat" total="42"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Le fichier `document.schema.json` devra être dans le même répertoire que le squelette et devra contenir un schéma valide. Voici un exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"date": {
|
||||||
|
"description": "Date d'émission",
|
||||||
|
"type": "string",
|
||||||
|
"format": "date"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"description": "Type de document",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["devis", "facture"]
|
||||||
|
},
|
||||||
|
"total": {
|
||||||
|
"description": "Montant total",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
"description": "Libellé",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"description": "Description",
|
||||||
|
"type": ["string", "null"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [ "type", "date", "total", "label"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Si le document fourni n'est pas conforme au schéma, il ne sera pas enregistré et une erreur sera affichée.
|
||||||
|
|
||||||
|
#### Propriété non requise
|
||||||
|
|
||||||
|
Si vous souhaitez utiliser dans votre document une propriété non requise, il ne faut pas la fournir en paramètre de la fonction `save`.
|
||||||
|
|
||||||
|
Si elle est fournie mais vide, il faut aussi autoriser le type `null` (en minuscules) au type de votre propriété.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
[...]
|
||||||
|
"description": {
|
||||||
|
"description": "Description",
|
||||||
|
"type": ["string", "null"]
|
||||||
|
}
|
||||||
|
[...]
|
||||||
|
|
||||||
|
### Stockage JSON dans SQLite (pour information)
|
||||||
|
|
||||||
|
Explication du fonctionnement technique derrière la fonction `save`.
|
||||||
|
|
||||||
|
En pratique chaque enregistrement sera placé dans une table SQL dont le nom commence par `module_data_`. Ici la table sera donc nommée `module_data_factures` si le nom unique du module est `factures`.
|
||||||
|
|
||||||
|
Le schéma de cette table est le suivant :
|
||||||
|
|
||||||
|
```
|
||||||
|
CREATE TABLE module_data_factures (
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
key TEXT NULL,
|
||||||
|
document TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX module_data_factures_key ON module_data_factures (key);
|
||||||
|
```
|
||||||
|
|
||||||
|
Comme on peut le voir, chaque ligne dans la table peut avoir une clé unique (`key`), et un ID ou juste un ID auto-incrémenté. La clé unique n'est pas obligatoire, mais peut être utile pour différencier certains documents.
|
||||||
|
|
||||||
|
Par exemple le code suivant :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:save key="facture_43" nom="Facture de courses"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Est l'équivalent de la requête SQL suivante :
|
||||||
|
|
||||||
|
```
|
||||||
|
INSERT OR REPLACE INTO module_data_factures (key, document) VALUES ('facture_43', '{"nom": "Facture de courses"}');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Récupération et liste de documents
|
||||||
|
|
||||||
|
Il sera ensuite possible d'utiliser la boucle `load` pour récupérer les données :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{#load id=42}}
|
||||||
|
Ce document est de type {{$type}} créé le {{$date}}.
|
||||||
|
<h2>{{$label}}</h2>
|
||||||
|
À payer : {{$total}} €
|
||||||
|
{{else}}
|
||||||
|
Le document numéro 42 n'a pas été trouvé.
|
||||||
|
{{/load}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Cette boucle `load` permet aussi de faire des recherches sur les valeurs du document :
|
||||||
|
|
||||||
|
```
|
||||||
|
<ul>
|
||||||
|
{{#load where="$$.type = 'facture'" order="date DESC"}}
|
||||||
|
<li>{{$label}} ({{$total}} €)</li>
|
||||||
|
{{/load}}
|
||||||
|
</ul>
|
||||||
|
```
|
||||||
|
|
||||||
|
La syntaxe `$$.type` indique d'aller extraire la clé `type` du document JSON.
|
||||||
|
|
||||||
|
C'est un raccourci pour la syntaxe SQLite `json_extract(document, '$.type')`.
|
||||||
|
|
||||||
|
# Export et import de modules
|
||||||
|
|
||||||
|
Il est possible d'exporter un module modifié. Cela créera un fichier ZIP contenant à la fois le code modifié et le code non modifié.
|
||||||
|
|
||||||
|
De la même manière il est possible d'importer un module à partir d'un fichier ZIP d'export. Si vous créez votre fichier ZIP manuellement, attention à respecter le fait que le code du module doit se situer dans le répertoire `modules/nom_du_module` du fichier ZIP. Tout fichier ou répertoire situé en dehors de cette arborescence provoquera une erreur et l'impossibilité d'importer le module.
|
||||||
|
|
||||||
|
# Restrictions
|
||||||
|
|
||||||
|
* Il n'est pas possible de télécharger ou envoyer des données depuis un autre serveur
|
||||||
|
* Il n'est pas possible d'écrire un fichier local
|
||||||
|
|
||||||
|
## Envoi d'e-mail
|
||||||
|
|
||||||
|
Voir [la documentation de la fonction `{{:mail}}`](brindille_functions.html#mail)
|
||||||
|
|
||||||
|
## Tables et colonnes de la base de données
|
||||||
|
|
||||||
|
Pour des raisons de sécurité, les modules ne peuvent pas accéder à toutes les données de la base de données.
|
||||||
|
|
||||||
|
Les colonnes suivantes de la table `users` (liste des membres) renverront toujours `NULL` :
|
||||||
|
|
||||||
|
* `password`
|
||||||
|
* `pgp_key`
|
||||||
|
* `otp_secret`
|
||||||
|
|
||||||
|
Tenter de lire les données des tables suivantes résultera également en une erreur :
|
||||||
|
|
||||||
|
* emails
|
||||||
|
* emails_queue
|
||||||
|
* compromised_passwords_cache
|
||||||
|
* compromised_passwords_cache_ranges
|
||||||
|
* api_credentials
|
||||||
|
* plugins_signals
|
||||||
|
* config
|
||||||
|
* users_sessions
|
||||||
|
* logs
|
160
doc/admin/skriv.md
Normal file
160
doc/admin/skriv.md
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
Title: Référence rapide SkrivML - Paheko
|
||||||
|
|
||||||
|
<<toc aside>>
|
||||||
|
|
||||||
|
# Syntaxe SkrivML
|
||||||
|
|
||||||
|
Paheko propose la syntaxe [SkrivML](https://fossil.kd2.org/paheko/doc/trunk/doc/skrivml.html) pour le formatage du texte des pages du site web.
|
||||||
|
|
||||||
|
## Styles de texte
|
||||||
|
|
||||||
|
| Style | Syntaxe |
|
||||||
|
| :- | :- |
|
||||||
|
| *Italique* | `Entourer le texte de ''deux apostrophes''` |
|
||||||
|
| **Gras** | `Entourer le texte de **deux astérisques**` |
|
||||||
|
| Texte <ins>Souligné</ins> | `Entourer le texte de deux __tirets bas__.` |
|
||||||
|
| ~~Barré~~ | `Deux --tirets hauts-- pour barrer.` |
|
||||||
|
| Texte <sup>Exposant</sup> | `XXI^^ème^^ siècle` |
|
||||||
|
| Texte <sub>Indice</sub> | `CO,,2,,` |
|
||||||
|
|
||||||
|
**Attention :** ces styles ne fonctionnent que si le code entoure des mots complets, ça ne fonctionne pas au milieu de mots.
|
||||||
|
|
||||||
|
```
|
||||||
|
Un **mot** en gras. Mais on ne peut pas cou**per** un mot avec du gras.
|
||||||
|
```
|
||||||
|
|
||||||
|
> Un **mot** en gras. Mais on ne peut pas cou\*\*per** un mot avec du gras.
|
||||||
|
|
||||||
|
## Titres
|
||||||
|
|
||||||
|
Doivent être précédé d'un ou plusieurs signe égal. Peuvent aussi être suivi du même nombre de signe égal.
|
||||||
|
|
||||||
|
```
|
||||||
|
= Titre niveau 1
|
||||||
|
== Titre niveau 2
|
||||||
|
=== Titre niveau 3 ===
|
||||||
|
==== Titre de niveau 4 ====
|
||||||
|
```
|
||||||
|
|
||||||
|
## Listes
|
||||||
|
|
||||||
|
Listes non ordonnées :
|
||||||
|
|
||||||
|
```
|
||||||
|
* Item 1
|
||||||
|
* Item 2
|
||||||
|
** Sous-item 2.1
|
||||||
|
** Sous-item 2.2
|
||||||
|
*** Sous-item 2.2.1
|
||||||
|
```
|
||||||
|
|
||||||
|
Listes ordonnées :
|
||||||
|
|
||||||
|
```
|
||||||
|
# Item 1
|
||||||
|
# Item 2
|
||||||
|
## Sub-item 2.1
|
||||||
|
## Sub-item 2.2
|
||||||
|
### Sub-item 2.2.1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Liens
|
||||||
|
|
||||||
|
Lien interne :
|
||||||
|
|
||||||
|
```
|
||||||
|
Voir [[cette page|adresse-unique-autre-page]].
|
||||||
|
```
|
||||||
|
|
||||||
|
Lien externe :
|
||||||
|
|
||||||
|
```
|
||||||
|
[[https://paheko.cloud/]]
|
||||||
|
```
|
||||||
|
## Tableaux
|
||||||
|
|
||||||
|
```
|
||||||
|
!! Colonne 1 !! Colonne 2
|
||||||
|
|| Cellule 1 || Cellule 2
|
||||||
|
|| Cellule 3 || Cellule 4
|
||||||
|
```
|
||||||
|
|
||||||
|
## Autres
|
||||||
|
|
||||||
|
Consulter la documentation complète de [SkrivML](https://fossil.kd2.org/garradin/doc/trunk/doc/skrivml.html).
|
||||||
|
|
||||||
|
# Extensions
|
||||||
|
|
||||||
|
Toutes les extensions se présentent sous la forme d'un code situé entre deux signes **inférieur à** (`<<`) et deux signes **supérieur à** (`>>`), à ne pas confondre avec les guillements français (`«` et `»`).
|
||||||
|
|
||||||
|
## Images jointes
|
||||||
|
|
||||||
|
Il est possible d'intégrer une image jointe à la page web en plaçant le code suivant sur une ligne (sans autre texte) :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<image|Nom_fichier.jpg|Alignement|Légende>>
|
||||||
|
```
|
||||||
|
|
||||||
|
* `Nom_fichier.jpg` : remplacer par le nom du fichier de l'image (parmi les images jointes à la page)
|
||||||
|
* `Alignement` : remplacer par l'alignement :
|
||||||
|
* `gauche` ou `left` : l'image sera placée à gauche en petit (200 pixels), le texte remplira l'espace laissé sur la droite de l'image ;
|
||||||
|
* `droite` ou `right` : l'image sera placée à droite en petit, le texte remplira l'espace laissé sur la gauche de l'image ;
|
||||||
|
* `centre` ou `center` : l'image sera placée au centre en taille moyenne (500 pixels), le texte sera placé au dessus et en dessous.
|
||||||
|
* Légende : indiquer ici une courte description de l'image.
|
||||||
|
|
||||||
|
Exemple :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<image|mon_image.png|center|Ceci est une belle image>>
|
||||||
|
```
|
||||||
|
|
||||||
|
Il est aussi possible d'utiliser la syntaxe avec des paramètres nommés :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<image file="Nom_fichier.jpg" align="center" caption="Légende">>
|
||||||
|
```
|
||||||
|
|
||||||
|
Les images qui ne sont pas mentionnées dans le texte seront affichées après le texte sous forme de galerie.
|
||||||
|
|
||||||
|
## Fichiers joints
|
||||||
|
|
||||||
|
Pour créer un bouton permettant de voir ou télécharger un fichier joint à la page web, il suffit d'utiliser la syntaxe suivante :
|
||||||
|
|
||||||
|
```
|
||||||
|
<<file|Nom_fichier.ext|Libellé>>
|
||||||
|
```
|
||||||
|
|
||||||
|
* `Nom_fichier.ext` : remplacer par le nom du fichier (parmi les fichiers joints à la page)
|
||||||
|
* `Libellé` : indique le libellé du qui sera affiché sur le bouton, si aucun libellé n'est indiqué alors c'est le nom du fichier qui sera affiché
|
||||||
|
|
||||||
|
|
||||||
|
# Raccourcis clavier
|
||||||
|
|
||||||
|
Depuis l'édition du texte :
|
||||||
|
|
||||||
|
| Raccourci | Action |
|
||||||
|
| :- | :- |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>G</kbd> | Mettre en gras |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>I</kbd> | Mettre en italique |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>T</kbd> | Mettre en titre |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>L</kbd> | Transformer en lien |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>I</kbd> | Insérer une image |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>F</kbd> | Insérer un fichier |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>P</kbd> | Prévisualiser |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>S</kbd> | Enregistrer |
|
||||||
|
| <kbd>F11</kbd> | Activer ou désactiver l'édition plein écran |
|
||||||
|
| <kbd>F1</kbd> | Afficher l'aide |
|
||||||
|
| <kbd>Echap</kbd> | Prévisualiser (rappuyer pour revenir à l'édition) |
|
||||||
|
|
||||||
|
|
||||||
|
Depuis la prévisualisation :
|
||||||
|
|
||||||
|
| Raccourci | Action |
|
||||||
|
| :- | :- |
|
||||||
|
| <kbd>Ctrl</kbd> + <kbd>P</kbd> | Retour à l'édition |
|
||||||
|
|
||||||
|
Depuis l'aide ou l'insertion de fichier :
|
||||||
|
|
||||||
|
| Raccourci | Action |
|
||||||
|
| :- | :- |
|
||||||
|
| <kbd>Echap</kbd> | Fermer et revenir à l'édition |
|
96
doc/admin/web.md
Normal file
96
doc/admin/web.md
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
Title: Squelettes du site web dans Paheko
|
||||||
|
|
||||||
|
{{{.nav
|
||||||
|
* [Documentation Brindille](brindille.html)
|
||||||
|
* [Fonctions](brindille_functions.html)
|
||||||
|
* [Sections](brindille_sections.html)
|
||||||
|
* [Filtres](brindille_modifiers.html)
|
||||||
|
}}}
|
||||||
|
|
||||||
|
# Les squelettes du site web
|
||||||
|
|
||||||
|
Les squelettes sont un ensemble de fichiers qui permettent de modéliser l'apparence du site web selon ses préférences et besoins.
|
||||||
|
|
||||||
|
La syntaxe utilisée dans les squelettes s'appelle **[Brindille](brindille.html)**. Voir la [documentation de Brindille](brindille.html) pour son fonctionnement.
|
||||||
|
|
||||||
|
# Exemples de sites réalisés avec Paheko
|
||||||
|
|
||||||
|
* [Faidherbe Alumni](https://www.alumni-faidherbe.fr/)
|
||||||
|
* [ASBM Mortagne](https://asbm-mortagne.fr/)
|
||||||
|
* [Vélocité 63](https://www.velocite63.fr/)
|
||||||
|
* [La rustine, Dijon](https://larustine.org/)
|
||||||
|
* [Tauto école](https://tauto-ecole.net/) [(les squelettes sont disponibles ici)](https://gitlab.com/noizette/squelettes-garradin-tauto-ecole/)
|
||||||
|
* [La boîte à vélos](https://boiteavelos.chenove.net/)
|
||||||
|
|
||||||
|
# Fonctionnement des squelettes
|
||||||
|
|
||||||
|
Par défaut sont fournis plusieurs squelettes qui permettent d'avoir un site web basique mais fonctionnel : page d'accueil, menu avec les catégories de premier niveau, et pour afficher les pages, les catégories, les fichiers joints et images. Il y a également un squelette `atom.xml` permettant aux visiteurs d'accéder aux dernières pages publiées.
|
||||||
|
|
||||||
|
Les squelettes peuvent être modifiés via l'onglet **Configuration** de la section **Site web** du menu principal.
|
||||||
|
|
||||||
|
Une fois un squelette modifié, il apparaît dans la liste comme étant modifié, sinon il apparaît comme *défaut*. Si vous avez commis une erreur, il est possible de restaurer le squelette d'origine.
|
||||||
|
|
||||||
|
## Adresses des pages du site
|
||||||
|
|
||||||
|
Les squelettes sont appelés en fonction des règles suivantes (dans l'ordre) :
|
||||||
|
|
||||||
|
| Squelette appelé | Cas où le squelette est appelé |
|
||||||
|
| :---- | :---- |
|
||||||
|
| `adresse` | Si l'adresse `adresse` est appelée, et qu'un squelette du même nom existe |
|
||||||
|
| `adresse/index.html` | Si l'adresse `adresse/` est appelée, et qu'un squelette `index.html` dans le répertoire du même nom existe |
|
||||||
|
| `category.html` | Toute autre adresse se terminant par un slash `/`, si une catégorie du même nom existe |
|
||||||
|
| `article.html` | Toute autre adresse, si une page du même nom existe |
|
||||||
|
| `404.html` | Si aucune règle précédente n'a fonctionné |
|
||||||
|
|
||||||
|
Ainsi l'adresse `https://monsite.paheko.cloud/Actualite/` appellera le squelette `category.html`, mais l'adresse `https://monsite.paheko.cloud/Actualite` (sans slash à la fin) appellera le squelette `article.html` si un article avec l'URI `Actualite` existe. Si un squelette `Actualite` (sans extension) existe, c'est lui qui sera appelé en priorité et ni `category.html` ni `article.html` ne seront appelés.
|
||||||
|
|
||||||
|
Autre exemple : `https://monsite.paheko.cloud/atom.xml` appellera le squelette `atom.xml` s'il existe.
|
||||||
|
|
||||||
|
Ceci vous permet de créer de nouvelles pages dynamiques sur le site, par exemple pour notre atelier vélo nous avons une page `https://larustine.org/velos` qui appelle le squelette `velos` (sans extension), qui va afficher la liste des vélos actuellement en stock dans notre hangar.
|
||||||
|
|
||||||
|
Le type de fichier étant déterminé selon l'extension (`.html, .css, etc.`) pour les fichiers traités par Brindille, un fichier sans extension sera considéré comme un fichier texte par le navigateur. Si on veut que le squelette `velos` (sans extension) s'affiche comme du HTML il faut forcer le type en mettant le code `{{:http type="text/html"}}` au début du squelette (première ligne).
|
||||||
|
|
||||||
|
## Fichier content.css
|
||||||
|
|
||||||
|
Ce fichier est particulier, car il définit le style du contenu des pages et des catégories.
|
||||||
|
|
||||||
|
Ainsi il est également utilisé quand vous éditez un contenu dans l'administration. Donc si vous souhaitez modifier le style d'un élément du texte, il vaux mieux modifier ce fichier, sinon le rendu sera différent entre l'administration et le site public.
|
||||||
|
|
||||||
|
# Cache
|
||||||
|
|
||||||
|
Depuis la version 1.3, Paheko dispose d'un cache statique du site web.
|
||||||
|
|
||||||
|
Cela veut dire que les pages du site web sont enregistrées sous la forme de fichiers HTML statiques, et le serveur web renvoie directement ce fichier sans faire appel à Paheko et son code PHP.
|
||||||
|
|
||||||
|
Les fichiers liés aux pages web sont également mis en cache de cette manière, en utilisant des liens symboliques.
|
||||||
|
|
||||||
|
Ce cache permet d'avoir un site web très rapide, même s'il reçoit des millions de visites.
|
||||||
|
|
||||||
|
## Désactiver le cache
|
||||||
|
|
||||||
|
Le seul inconvénient c'est qu'une page mise en cache étant statique, si vous utilisez du contenu dynamique (par exemple afficher un texte différent selon la langue du visiteur) dans le squelette Brindille, alors cela ne fonctionnera plus.
|
||||||
|
|
||||||
|
Dans ce cas-là, vous pouvez assigner la variable `nocache` dans le squelette pour désactiver le cache pour cette page :
|
||||||
|
|
||||||
|
```
|
||||||
|
{{:assign nocache=true}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Pour permettre des usages du type "affichage en temps presque réel des horaires d'ouverture", le cache d'une page HTML est effacé et remis à jour au bout d'une heure.
|
||||||
|
|
||||||
|
## Exceptions
|
||||||
|
|
||||||
|
Il est à noter que le cache n'est pas appelé dans les cas suivants :
|
||||||
|
|
||||||
|
* si la requête vers la page est d'un autre type que `GET` ou `HEAD`, ainsi par exemple l'envoi d'un formulaire (`POST`) ne sera jamais mis en cache ;
|
||||||
|
* si la requête vers la page contient des paramètres dans l'adresse (par exemple `velos.html?list=1` : cette page ne sera pas mise en cache) ;
|
||||||
|
* si le visiteur est connecté à l'administration de l'association. Ainsi si vous avez des parties du squelette qui varient en fonction de si la personne est connectée, le cache ne posera pas de problème.
|
||||||
|
|
||||||
|
Le cache est intégralement effacé à chaque modification du site web.
|
||||||
|
|
||||||
|
Le cache ne concerne que les pages et fichiers du site web public. Il ne concerne pas les modules, les extensions, ou l'administration.
|
||||||
|
|
||||||
|
Attention :
|
||||||
|
|
||||||
|
* avec un serveur sous Windows, le cache est désactivé car Windows ne sait pas gérer les liens symboliques ;
|
||||||
|
* seul Apache sait gérer le cache statique, le cache est désactivé avec les autres serveurs web (nginx, etc.).
|
BIN
doc/icon.png
Normal file
BIN
doc/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 522 B |
213
doc/index.md
Normal file
213
doc/index.md
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
# La gestion d'association libre et simple
|
||||||
|
|
||||||
|
<div id="prez">
|
||||||
|
<figure>
|
||||||
|
<img src="./selfhost2.png" alt="Illustration d'une personne aidant une autre à installer Paheko sur un ordinateur" />
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
### Paheko — la gestion d'association simple</h3>
|
||||||
|
|
||||||
|
**Paheko** <small>(anciennement appelé *Garradin*)</small> signifie *coopérer* en *Māori*. C'est un logiciel de gestion d'association, libre, simple et efficace, développé depuis 2012. Son but est de :
|
||||||
|
|
||||||
|
* **réduire le temps** passé sur les tâches administratives ;
|
||||||
|
* re-**donner de l'autonomie aux adhérent⋅e⋅s** dans la gestion de leurs données ;
|
||||||
|
* **simplifier la gestion administrative** de l'association, pour inciter à y participer ;
|
||||||
|
* **minimiser le nombre de logiciels à installer et maintenir** en intégrant les outils habituels.
|
||||||
|
|
||||||
|
Pour en savoir plus : [voir les principales fonctionnalités](#features).
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="warn">
|
||||||
|
<p><strong>Attention : ce site est dédié au logiciel libre Paheko.</strong><br />
|
||||||
|
Son installation, sur un serveur ou sur un ordinateur personnel, nécessite quelques compétences techniques.</p>
|
||||||
|
<p>Si votre association n'a pas ces compétences, nous recommandons l'utilisation de notre service d'hébergement :<br /><strong class="cloud"><a href="https://paheko.cloud/" target="_blank"><img src="./icon.png" alt="" /> Paheko.cloud</a></strong>
|
||||||
|
<small>(<strong>Essai gratuit</strong>, puis contribution à prix libre, à partir de 5 € par an)</small>
|
||||||
|
</div>
|
||||||
|
<nav id="gnav">
|
||||||
|
|
||||||
|
* [Guides d'installation](wiki:Installation)
|
||||||
|
* [Documentation](wiki:Documentation)
|
||||||
|
* [Entraide](wiki:Entraide)
|
||||||
|
* <a href="https://paheko.cloud/" target="_blank">Essayer gratuitement sur <b><img src="./icon.png" alt="" /> Paheko.cloud</b></a>
|
||||||
|
|
||||||
|
<ul id="news">
|
||||||
|
<li><a href="$ROOT/wiki/?name=Changelog">Nouveautés</a></li>
|
||||||
|
<li><a href="$ROOT/uvlist">Anciennes versions</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<p id="give"><a href="https://kd2.org/soutien.html" target="_blank">Soutenir Paheko en effectuant un don :-)</a></p>
|
||||||
|
|
||||||
|
<form method="GET" action="$ROOT/wiki" id="search_all" onsubmit="var t = this.querySelector('[type=radio]:checked'); this.querySelector('[name=s]').name=t.dataset.name; this.action=t.dataset.action; this.target=t.dataset.target;">
|
||||||
|
<fieldset class="searchForm searchFormWiki">
|
||||||
|
<legend>Rechercher</legend>
|
||||||
|
<input type="search" name="s" size="40" value="" />
|
||||||
|
<label><input type="radio" name="t" value="" data-name="s" data-action="/paheko/wiki" data-target="" checked="checked" /> Chercher dans la documentation technique</label>
|
||||||
|
<label><input type="radio" name="t" value="1" data-action="https://paheko.cloud/search" data-name="search" data-target="_blank" /> Chercher dans l'aide utilisateur</label>
|
||||||
|
<input type="submit" value="Rechercher" />
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function isNewerVersion (oldVer, newVer) {
|
||||||
|
const oldParts = oldVer.split('.')
|
||||||
|
const newParts = newVer.split('.')
|
||||||
|
for (var i = 0; i < newParts.length; i++) {
|
||||||
|
const a = ~~newParts[i] // parse int
|
||||||
|
const b = ~~oldParts[i] // parse int
|
||||||
|
if (a > b) return true
|
||||||
|
if (a < b) return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('/paheko/juvlist?'+(+(new Date))).then((r) => {
|
||||||
|
r.json().then((list) => {
|
||||||
|
let last = {};
|
||||||
|
let selected;
|
||||||
|
|
||||||
|
list.forEach((file) => {
|
||||||
|
var v = file.name.match(/^paheko-(\d+\.\d+\.\d+)\.(deb|exe|tar\.gz)$/);
|
||||||
|
|
||||||
|
if (!v || v[1].match(/-(alpha|rc|beta)/)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.type = v[2];
|
||||||
|
file.version = v[1];
|
||||||
|
file.human_size = (Math.round((file.size / 1024 / 1024) * 10) / 10 + ' Mo').replace(/\./, ',');
|
||||||
|
|
||||||
|
if (!last.hasOwnProperty(file.type) || isNewerVersion(last[file.type].version, file.version)) {
|
||||||
|
last[file.type] = file;
|
||||||
|
|
||||||
|
if (file.type == 'tar.gz') {
|
||||||
|
selected = file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let days = ((+new Date)/1000 - selected.mtime) / 3600 / 24;
|
||||||
|
|
||||||
|
if (days < 31) {
|
||||||
|
time = Math.ceil(days) + ' jours';
|
||||||
|
}
|
||||||
|
else if (days >= 31) {
|
||||||
|
time = Math.round(days / 30.5) + ' mois';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector('#news').innerHTML = `<li class="last"><strong>Dernière version : ${last['tar.gz'].version}</strong></li>
|
||||||
|
<li class="last"><em>il y a ${time}</em></li>` + document.querySelector('#news').innerHTML;
|
||||||
|
|
||||||
|
var links = `<div id="download">
|
||||||
|
<h2>Télécharger :</h2>
|
||||||
|
|
||||||
|
<nav>`;
|
||||||
|
|
||||||
|
if ('tar.gz' in last) {
|
||||||
|
links += `
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<h3><a href="$ROOT/uv/${last['tar.gz'].name}"><img src="data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB3aWR0aD0iMjQiCiAgaGVpZ2h0PSIyNCIKICB2aWV3Qm94PSIwIDAgMjQgMjQiCiAgZmlsbD0ibm9uZSIKICBzdHJva2U9ImN1cnJlbnRDb2xvciIKICBzdHJva2Utd2lkdGg9IjIiCiAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogIHN0cm9rZS1saW5lam9pbj0icm91bmQiCj4KICA8cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMjAiIGhlaWdodD0iOCIgcng9IjIiIHJ5PSIyIiAvPgogIDxyZWN0IHg9IjIiIHk9IjE0IiB3aWR0aD0iMjAiIGhlaWdodD0iOCIgcng9IjIiIHJ5PSIyIiAvPgogIDxsaW5lIHgxPSI2IiB5MT0iNiIgeDI9IjYuMDEiIHkyPSI2IiAvPgogIDxsaW5lIHgxPSI2IiB5MT0iMTgiIHgyPSI2LjAxIiB5Mj0iMTgiIC8+Cjwvc3ZnPgo=" alt="" /><span>Serveur</span></a></h3>
|
||||||
|
<p>pour auto-hébergement<br />
|
||||||
|
<em>(.tar.gz, ${last['tar.gz'].human_size})</em><br />
|
||||||
|
<small><a href="$ROOT/wiki/?name=Installation">Guides d'installation</a></small>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('deb' in last) {
|
||||||
|
links += `
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<h4><a href="$ROOT/uv/${last['deb'].name}"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGoAAAB8AgMAAAD8wM2CAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAAlwSFlzAAAF3gAABd4BiRluJgAAAAxQTFRFAAAAR3BMAAAAAAAAoOHXxQAAAAR0Uk5T/QBQozL7B+YAAAPySURBVEjHndc9aBxHFADgd7u64hTv4eYgxRVulijYpQURpDgIKVwILtbN7GAt9jquEl/gItUOl5gUhgjUbNKkMBhhkDE2rhOY2LhwYVvNgiEu0qhOwKiISSAzszPz3q7mhIlKfczuzJv3swds4d8Y3tEu/fNyb4FxCQBl2HJFkIRtpI0spGYIVkM2qS0JWV5bFLKiNnwhsZm1KmAja2nA5ta6AZMnmCXonWDJCdY5btxZ9D8tDtkpgD5fYKVUFzQKWqT+P9ARD5yh80UB1b/jkPHkh1346dTPwXXJ8gG8Wn6NF0hsuXMaXkXDsMVnYBifCxucgXMwxIsn9hz69z6G00F7LP+8MYXdoD355qvP2KNx0KTOaP4XqOAcz6XSZmnAbrrMT4/bt6Y8+WLbyrCSiH2it7IqMEFpzqtnTcsiaPNfGf9bZ3cSsN/fvinFa0zQxtm/3GPbE0wmas/VXnpqnxDIszslKyqO1YmWwWRtMzFlkbZNxEzGlSnRbtvGEbu0V5d20rZZx7eLqG2yh22mZdyFWPiNehNud5nf6BgPWmEddps2cinLfcl7k0DqN25YhiXpe5ozgS1Aus04y7GtzN1mnBVoM9ebnI2wVRWxrF/gbI7tL49tP3Amsb9P4IO6Pp3B+wNMgKSuCWscditMnGhuDuFtRufLzLzdWhbdZKThH5jma23S6TAyKIbmRNZEvzG/VkwkrOVLPTrrVkzkrY0/wvGl4n6e2myYMjLQlkxgrI0OBi0rvcnbeHR1z0vmdq3BrGzZwFkWj9gim9CwKDtPLI++a1vqrOg8JsbV2dFmnd8a66jNG8Z18/UmW+sOTOOqDaKdxrrbZB3E6411V6Q3VR73qSX7P0piA2pnISoGaF1qfwCs+LisTSNid1W1vOfuIVOdCu9BxHrouvublGyOObGhO0V8aE2oiOJDv9adIn5q7ZrOLX/x67rikwvGcujrHPFJuK4rfvWGse39Uh8jQlMVX101dst2B/fQW2aOf27syBbuqrdCveCisdQWT+KNv6nYZWJj33wu1BEgJvwMri2r8H2Zv4vaWBcNO4W1bWJ+o89syFNl37tKrl+cuQDtoOV2L8LZNWWf2qqzQSuc5Wg8bc4CJnb9M/1Z6LqjRjwKbxvKXPpdtd/RZJ+Z/3zQ+5z6dBSHYxA+v9T1X8dvzBcqLlfId7LEj2ihY30RS4R+YO8wapxaZmolL1sfoMY2zHXzfstS+0h9R9N+ecy469fX45KajkXuZ8CmQQ5v1bfNA6ltC2fHpn5ntob3cUTmynTNxqzOCdGYfw8PmWtpWzqPGjP1yS8u58WHm73WfN/3xfnQ7jv426l8h99V/wEOtd7r5KQmrQAAAABJRU5ErkJggg==" alt="" /><span>Linux</span></a></h4>
|
||||||
|
<p>hors-ligne, pour ordinateur<br />
|
||||||
|
<em>(.deb, ${last['deb'].human_size})</em><br />
|
||||||
|
<small><a href="$ROOT/wiki/?name=Fonctionnement+hors-ligne">Guide d'installation</a></small>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('exe' in last) {
|
||||||
|
links += `
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<h4><a href="$ROOT/uv/${last['exe'].name}"><img src="data:image/svg+xml;base64,PHN2ZyBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyNCAyNCIgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Im0yMiAyLTEwLjggMS42djhsMTAuOC0uMXptLTExLjggMTAuNS04LjItLjF2Ni44bDguMSAxLjF6bS04LjItNy43djYuOGg4LjF2LTcuOXptOS4xIDcuN3Y3LjlsMTAuOSAxLjZ2LTkuNHoiLz48L3N2Zz4=" alt="" /><span>Windows</span></a></h4>
|
||||||
|
<p>hors-ligne, pour ordinateur<br />
|
||||||
|
<em>(.exe, ${last['exe'].human_size})</em><br />
|
||||||
|
<small><a href="$ROOT/wiki/?name=Installation/Windows">Guide d'installation</a></small>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
links += `
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
document.querySelector('#news').insertAdjacentHTML('afterend', links);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<a name="features"></a>
|
||||||
|
|
||||||
|
## C'est quoi ?
|
||||||
|
|
||||||
|
* **100% libre :** placé sous la licence [AGPL v3](https://www.gnu.org/licenses/why-affero-gpl.fr.html).
|
||||||
|
* Gestion des **adhérent⋅e⋅s** : fiches de membre personnalisables, recherches personnalisées…
|
||||||
|
* Gestion des **cotisations** et **activités** : suivi des adhérent⋅e⋅s à jour, des paiements en attente, **rappels automatiques** de cotisation par e-mail, etc.
|
||||||
|
* Envoi de **newsletters** avec suivi des adresses e-mail invalides
|
||||||
|
* **Comptabilité** puissante (à double entrée), **simple à utiliser par les débutant⋅e⋅s** : recettes, dépenses, suivi des dettes et créances, bilan et compte de résultat annuel, **comptabilité analytique**, export PDF, **reçus fiscaux**, etc.
|
||||||
|
* Stockage et **partage** de **documents** : édition collaborative, synchronisation des fichiers sur un ordinateur, etc.
|
||||||
|
* Gestion du **site web** de l'association
|
||||||
|
* Comptabilisation du **temps bénévole** et sa **valorisation**
|
||||||
|
* Gestion de la **caisse informatisée** d'un atelier ou d'une boutique
|
||||||
|
* Réservation de **créneaux et d'événements**
|
||||||
|
* **Conforme au RGPD** : export des données de l'adhérent⋅e, désabonnement des e-mails, chiffrement des mots de passe…
|
||||||
|
|
||||||
|
**<a href="http://paheko.cloud/a-propos" target="_blank">Présentation des fonctionnalités sur le site Paheko</a>**
|
||||||
|
|
||||||
|
## Dans quels buts ?
|
||||||
|
|
||||||
|
Le but est de permettre :
|
||||||
|
|
||||||
|
* la gestion des __adhérent⋅e⋅s__ : ajout, modification, suppression, possibilité de choisir les informations présentes sur les fiches adhérent, envoi de mails collectifs aux adhérent⋅e⋅s
|
||||||
|
* la tenue de la __comptabilité__ : avoir une gestion comptable complète à même de satisfaire un expert-comptable tout en restant à la portée de celles et ceux qui ne savent pas ce qu'est la comptabilité à double entrée, permettre la production des rapports et bilans annuels et de suivre au jour le jour le budget de l'association
|
||||||
|
* la gestion des __cotisations__ et __activités__ : suivi des cotisations à jour, inscriptions et paiement des activités, rappels automatiques par e-mail, etc.
|
||||||
|
* le travail __collaboratif__ et __collectif__ : gestion fine des droits d'accès aux fonctions, échange de mails entre membres…
|
||||||
|
* la __simplification administrative__ : prise de notes en réunion, archivage et partage de fichiers (afin d'éliminer le besoin d'archiver les documents papier), etc.
|
||||||
|
* la publication d'un __site web__ pour l'association, simple mais suffisamment flexible pour pouvoir adapter le fonctionnement à la plupart des besoins
|
||||||
|
* l'__autonomisation des adhérents__ : possibilité de mettre à jour leurs informations par eux-même, ou de s'inscrire seul depuis un ordinateur ou un smartphone
|
||||||
|
* la possibilité d'adapter aux besoins spécifiques de chaque association via des [__extensions__](wiki:Extensions).
|
||||||
|
|
||||||
|
* Fonctionnalités qu'il reste à implémenter : voir [la feuille de route (roadmap)](wiki:Roadmap).
|
||||||
|
* Paheko ne convient pas ? [Voir la liste des alternatives, libres ou propriétaires](wiki:Alternatives)
|
||||||
|
|
||||||
|
## Un seul logiciel
|
||||||
|
|
||||||
|
Paheko réunit en un seul outil les besoins suivants :
|
||||||
|
|
||||||
|
* gestion des membres : remplace Ciel Associations, EBP, Assoconnect ou Galette ;
|
||||||
|
* comptabilité : remplace Assoconnect, Odoo, Dolibarr, Grisbi, GNUcash, Sage, etc. ;
|
||||||
|
* gestion et partage de fichiers, remplace NextCloud, Google Drive ou Dropbox ;
|
||||||
|
* site web : remplace WordPress, Drupal, etc. ;
|
||||||
|
* suivi du bénévolat : remplace Bénévalibre et les tableaux Excel.
|
||||||
|
|
||||||
|
## Documentation et entraide
|
||||||
|
|
||||||
|
* D'abord lire la [documentation](/wiki/?name=Documentation) et notamment la [foire aux questions](wiki:FAQ)
|
||||||
|
* Voir la page [Entraide](/wiki/?name=Entraide) pour accéder aux listes de discussion et au salon de discussion IRC
|
||||||
|
|
||||||
|
## Participer
|
||||||
|
|
||||||
|
Tout coup de main est le bienvenu, pas besoin d'avoir des connaissances techniques ! Nous avons un [guide de contribution](wiki:Contribuer) pour vous aider à voir comment vous pouvez participer à Paheko :)
|
||||||
|
|
||||||
|
### Développement
|
||||||
|
|
||||||
|
Paheko est un logiciel libre, développé en PHP, utilisant la base de données SQLite, et avec une interface utilisant HTML, CSS et un peu de Javascript.
|
||||||
|
|
||||||
|
Nous acceptons les contributions (plugins, patch, code, tickets, etc.) avec plaisir, consultez la [documentation développeur⋅euse](wiki:Documentation développeur) pour découvrir comment vous pouvez contribuer.
|
BIN
doc/selfhost2.png
Normal file
BIN
doc/selfhost2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
1430
doc/skrivml.html
Normal file
1430
doc/skrivml.html
Normal file
File diff suppressed because it is too large
Load diff
766
manifest
Normal file
766
manifest
Normal file
|
@ -0,0 +1,766 @@
|
||||||
|
-----BEGIN PGP SIGNED MESSAGE-----
|
||||||
|
Hash: SHA512
|
||||||
|
|
||||||
|
C Fix\squote\sin\slist
|
||||||
|
D 2024-01-06T13:45:04.578
|
||||||
|
F .editorconfig e6f131bd881371738fbc49cd771c470959e14df4b5baa398db781f21e2f98b34
|
||||||
|
F .fossil-settings/allow-symlinks 5a9cb4b1795fdc8982e907994a2e80eca49b6daf329c826d86903016391506ce
|
||||||
|
F .fossil-settings/ignore-glob 962019af50eb59ad515b3bdf7d4bc04b7a982a4b410d1d669a9561c095388772
|
||||||
|
F .fossil-settings/manifest 5a9cb4b1795fdc8982e907994a2e80eca49b6daf329c826d86903016391506ce
|
||||||
|
F .travis.yml 4da8c0eef1bdf524e1ad6cf8e7bfe3d4d26a680a
|
||||||
|
F COPYING 78e50e186b04c8fe1defaa098f1c192181b3d837
|
||||||
|
F README.md 827da5e24a451ad78aeff512e83128a3d23132cc34e00e2690bfa29668f08ebb
|
||||||
|
F SECURITY.md 58d2d41ec6509b4991e4ebcf46935ba1f33b568afc6e587df4a2d7ae703649f4
|
||||||
|
F archives/0.7.0_migration.sql acaa57e89553e8763fcbc2bcb50aa6a18b7327ad
|
||||||
|
F archives/0.7.2_migration.sql ba4b5fbcc7a56b971532d8fef20aba41e5c963ad
|
||||||
|
F archives/0.8.0_migration.sql b56b9689504b83b8ae279a5c5c42ce05e423d883
|
||||||
|
F archives/0.8.0_schema.sql 1c0ae41b79ce190843cc88a7d65f5bce65a0ca96
|
||||||
|
F archives/0.8.3_migration.sql 78f64dc82033abd49d4156b013c78828a795d326
|
||||||
|
F archives/0.8.3_schema.sql 80be656e5dde9e43cc7027d0ba6eb14b26ff3e7b
|
||||||
|
F archives/0.8.4_migration.sql 107bec2b2d0f7c958a87e71e3b2c9da3246b6762
|
||||||
|
F archives/0.9.0_migration.sql 90ab72f7f4dcb6d018df98790c3407e366881155
|
||||||
|
F archives/0.9.0_schema.sql 9f23495ff41c8810fee101826f74c80d44f7f56f
|
||||||
|
F archives/0.9.1_migration.sql 6227606b97cd3aa1296c0c2e7b884ae0b6aa2085
|
||||||
|
F archives/0.9.1_schema.sql efe750515a9909e2ee06db77bc97f005a2f8d923
|
||||||
|
F archives/0.9.5_schema.sql c8df01c2dd61ee0516f89fa2bfb78e5f208550e9
|
||||||
|
F archives/1.0.0_schema.sql 292ae067786851c89ca00bff59e08a12a43d40fd5f64ff85a313477e8007485f
|
||||||
|
F archives/plan_comptable.json c4962464667bb992c37d3b7363f80de0eeac9ad7
|
||||||
|
F build/debian/config.debian.php f3119a87085bb5fedbceca0c206442c3cfe49e14265125d48e5f2c5a23121d00
|
||||||
|
F build/debian/makedeb.sh dd8d4f904f9162b7ba0ef81bbc88514fb61803e2c8fb1c257c36a1f48528b2b6 x
|
||||||
|
F build/debian/manpage.txt 81ca70dd7d81d2e4578de5317057f03581326a7db15eca4a90d3d9885f5f3902
|
||||||
|
F build/debian/paheko a6de924cf5669b8d9c6db5277a6a74e26d5c9e76b388f338c8a11354fc4a4484 x
|
||||||
|
F build/debian/paheko.desktop f020895fffdbed4773f6cf9cfc99e6695ccf35084e80e8a2593167390e12d647
|
||||||
|
F build/debian/paheko.menu f93ffda8edce658a00928bb52e7757ca8ce3a17dc1e28944486b73d6fe4781d4
|
||||||
|
F build/debian/paheko.png e538df2fa2ebd8b873c77c8e71c1daad3cdc898901d8f06a14966eb655f3d5ab
|
||||||
|
F build/windows/Makefile 7b464ebe758771ad301e07cffcbd6dfe04c771a5562098c5bcaa3c5438b3442c
|
||||||
|
F build/windows/README.md 5c56cc2aa07f74d5b6f78899af2fd482b19d9f35803f1c9cdfc863a0868fbd8a
|
||||||
|
F build/windows/config.local.php f722b32a30b33980e301d264c3224b6fa4e5a4dbbe98cc5956fbee099b8584f9
|
||||||
|
F build/windows/launch.bat 4318d01c86cb116035345ea2bfefe584da2bc56520a4bb51e3a282377cce399d
|
||||||
|
F build/windows/paheko.ico 969b2f968c7bc5f8474f2fbdbadf515be1ed1798da2fd845faf6f42240f0fece
|
||||||
|
F build/windows/paheko.nsis 8f73d399b04c544b5d070fd821fdfbabbbafb861fae761826fba2d837b0e521c
|
||||||
|
F build/windows/php.ini 43ac89d6777fa71801cac6eb1d6515ce5f3bd460b022f328b75df0c27f2313be
|
||||||
|
F doc/admin/api.md 891b1aa042dd0c03ebdf4f9800de25bfd9d3f5c0565e1b084d3773c6eabb32e5
|
||||||
|
F doc/admin/brindille.md 8edc24b7ae8a3199365094300f7ba4f3fbc5575f8dcfc0872f9fafebee339470
|
||||||
|
F doc/admin/brindille_functions.md 227ccbad97ed1d0f0662624a8d57041bad12627c5746a5f5c8ede286e70558b2
|
||||||
|
F doc/admin/brindille_modifiers.md 5847dbdabd1a426f17a00c3a357c1ed4917e93dc7e61ec0d8e1ba3416329a3b1
|
||||||
|
F doc/admin/brindille_sections.md 6ef603f2600a7a22da271140537e226fe570bc6ea887539a86f82d309c5ccbd8
|
||||||
|
F doc/admin/keyboard.md e9a85dcaa57bac91a920bfb4cfb595c580f4059f46b4f56b03e662fb79eb8d33
|
||||||
|
F doc/admin/markdown.md 61cfd293d2831310e6a1ed051eff57db446a5658bb47edab1a18ebc4cd21f003
|
||||||
|
F doc/admin/markdown_quickref.md 6205777c597575cb8d3750325251ef59352ac4daa8489f8e75cf518a6eb3107d
|
||||||
|
F doc/admin/modules.md 8bbc7e0c4735fc0dd7b3c7a15e30d4dbf3484b0c64198f105a5d5dd24dc3d7d1
|
||||||
|
F doc/admin/skriv.md 840d985008180b189986c8006760b2945e5e55138429c44b0240bd86d5936a1f
|
||||||
|
F doc/admin/web.md 9859ee4f6c0b5eb464fe16a5b425473505fcacf015e5ac9c11caaf07bfe2d131
|
||||||
|
F doc/icon.png 13439ec7073ffb0bfdca7062ad90755961109b66ac9bf49179f6a2dd07f6a378
|
||||||
|
F doc/index.md 54ac4b8f732466b2a46be9d05738300665ef98d8d63a43c1e5055d207794cdd7
|
||||||
|
F doc/selfhost2.png 701da39174d67cc10da6b71fade8e1087d3c8b07e62e90b5b03ac7438031affd
|
||||||
|
F doc/skrivml.html b749ec40a9ef7f210f12108774b9e0f25c9a6c51fc3b1e6cc452b630a258aa41
|
||||||
|
F src/.htaccess.www 1fa848cf6a83049ffacd5db68281f6d2374a6a119ead4c6a3b7977c311e7ae68
|
||||||
|
F src/Makefile 2c0887f6862f285e1b11eaacb2bf984eeca725d02e97c0f937136122767fa559
|
||||||
|
F src/VERSION 586e3ccefcb1c33d7bbb9d9a5d045ac5237b4dde29cc64134e952cdf5206dbf3
|
||||||
|
F src/apache-htaccess.conf de974946e40c9da0a3ad98c7dee430c15297d344d499969ad0be272114db1c62
|
||||||
|
F src/apache-vhost.conf 04ec124c9b6632a8a638e78e63a5631b3638aa55cce07d18063ffd0d8970e5fe
|
||||||
|
F src/config.dist.php dd2986806a989758fd41c70f1c1bd9ff8ef4ce9af9d49f56f446536cc7b04ba9
|
||||||
|
F src/data/index.html abe89f9bfb756bbdfb2f535420e10bb5625eb4e2
|
||||||
|
F src/include/data/1.1.0_schema.sql ab4753bbe0e71c8e5910b94a4c73243191543e942a62304032a77f2060b130ab
|
||||||
|
F src/include/data/1.1.21_migration.sql 6a26982b556b4e91cab24c577b94b0d621cbcc6042aea0d1aa220bdb2126c7c0
|
||||||
|
F src/include/data/1.1.25_migration.sql 72b38ceb6c907083d59552efee8613a8bde94b87ada1503688c4f08c20f90ad2
|
||||||
|
F src/include/data/1.1.29_migration.sql 93d8b01db404c3a0adeaa01a26c5dac5cae0deefbbb102d14d727e7c8c204d95
|
||||||
|
F src/include/data/charts/be_pcmn_2019.csv 3f6549390acc521c8617b5f4cb67f5b33d528b75e281f739a4c76d9de6f9d26e
|
||||||
|
F src/include/data/charts/ch_asso.csv e384d6a13097e16163dcb6e0be0bcf445e11921df085ca978726b0d51ce93987
|
||||||
|
F src/include/data/charts/fr_cse_2015.csv 5386feeb8aac9533d0bd87781aab280db9738dcff79e27fac717d6b2a8a059d9
|
||||||
|
F src/include/data/charts/fr_pca_1999.csv cce600ccba024cfa5468101a08171d474a4cfdc7bbc1a3ea7b89bd4aebf27508
|
||||||
|
F src/include/data/charts/fr_pca_2018.csv b4e1b59a9637ca99f8700fb52f2ed8528b9ecbbe8097b43d3bce4ac38a94aea4
|
||||||
|
F src/include/data/charts/fr_pcc_2020.csv 2b88ba109a5724c43cb2e16260f791d6583e9848ef928983cc8977c80c94b0e8
|
||||||
|
F src/include/data/charts/fr_pcg_2014.csv a3ec7658abf73ff2704af6f51dfdc4e3e202c4df4e0e1360cce2e1aa55343aad
|
||||||
|
F src/include/data/charts/fr_pcs_2018.csv 301907d458e9351c416a793915bf1276ecd63b1dcd0db48fe8c6f937b4522292
|
||||||
|
F src/include/data/dictionary.fr d3245db784b299707cf47379ab48d82dd75439a3c5a77bfdf33f5c54408a3548
|
||||||
|
F src/include/data/schema.sql 57116110a23d96f4be9c8593b2e031930774e4234783612ba48ac1b4f3d17735 l
|
||||||
|
F src/include/data/users_fields_presets.ini c53432e075f004bbf156dd8d15194ade6af69cc4b7be8b7b1ed5ac8c82567b23
|
||||||
|
F src/include/init.php 764d5f963e25fd6febd55c3cc2195930dc33d2af4f1dc2921c5a7513e5a23773
|
||||||
|
F src/include/lib/Paheko/API.php 6f1b24a15426ba1479465312cc27c583ed653ee0f3d3a971c9450472c61b7173
|
||||||
|
F src/include/lib/Paheko/API_Credentials.php b8b75e5569b842f419eb1654163c4edf135a7e02e95b99b27c0d5a1874ec853e
|
||||||
|
F src/include/lib/Paheko/Accounting/Accounts.php f427cf5c529aec71faa83dd1809f7adb4b95414f2dcf636e448b3102c331d01b
|
||||||
|
F src/include/lib/Paheko/Accounting/AdvancedSearch.php 4dcebe68b436d34d394b4b69edd1ba5f878fd99f737862eac8e29f5a63323973
|
||||||
|
F src/include/lib/Paheko/Accounting/AssistedReconciliation.php c253756b1663c63a84a18c8efc6b23f05ed3e2bcf65751fee0de04064d34d1d6
|
||||||
|
F src/include/lib/Paheko/Accounting/Charts.php aa097f23d218a57e4652b6bdf9414035027ea51ef5c4cfaadd4eb6578d6f0538
|
||||||
|
F src/include/lib/Paheko/Accounting/Export.php 4f4ad7a47258d6e30b9be35d62b2d948af7484aafdf359532997f7c31b0f99c7
|
||||||
|
F src/include/lib/Paheko/Accounting/Graph.php 50db85fd4c4f4a4ac6e01d01af3f8cf7f368c73d1b3027ef32928527a6a2c1e6
|
||||||
|
F src/include/lib/Paheko/Accounting/Import.php 5dee4748b224b48309c3319bdf8f82bccd3f180dde92e71e138adfd9f96918b0
|
||||||
|
F src/include/lib/Paheko/Accounting/Projects.php f2c156faf2f4678103a432d468528b8c7d693de507de5148a2c18d7cc7c489f7
|
||||||
|
F src/include/lib/Paheko/Accounting/Reports.php e71e9321d9b54bf6eac5962ccd189c61bb3afb9827974d5e00f6d6a7d03b1a7d
|
||||||
|
F src/include/lib/Paheko/Accounting/Transactions.php bed5cfe0ccdf38f199b1f2ad18c29283412a4deb88ca5ea72aa3d970274f2e06
|
||||||
|
F src/include/lib/Paheko/Accounting/Years.php 6d8166387a20f437c5910dea43a5b4a903f4ef96ea2e574f3505fab7641da6f2
|
||||||
|
F src/include/lib/Paheko/AdvancedSearch.php 5a7f7c2a3842b676c2599db47b0a7ef81df957b1bc763d588adb66e09c2532ee
|
||||||
|
F src/include/lib/Paheko/Backup.php 8f8f3823f453908e3b5380f749294e58f65e8e18a9c60e48e944f7b6a053f435
|
||||||
|
F src/include/lib/Paheko/CSV.php 8482fbd483951db6b12f0ed14e70eb99adb93fd2e96bbd922d6742fa6186d14c
|
||||||
|
F src/include/lib/Paheko/CSV_Custom.php a30a154c6fca07d4217f123c3a9254d5e3d159975063306d6eedbb665ca9f7f7
|
||||||
|
F src/include/lib/Paheko/Config.php 38a8dfd9db963ef77cb4373975d2dea83b0a4df73558b9c5d58799a644d217d6
|
||||||
|
F src/include/lib/Paheko/DB.php 8ed15d427fb7b21be61c115c7d9c0bd5c4db644c75d34c1514292b65676be879
|
||||||
|
F src/include/lib/Paheko/DynamicList.php d40bde39fc4a1c30cdfa1c9ec7f5ad3e3fd91bea144298cd1a65017c18ba0341
|
||||||
|
F src/include/lib/Paheko/Email/Emails.php e36a3236d0c9bd47509658c1e112ed58bb708125722aaa14ca8f5a47224fefd1
|
||||||
|
F src/include/lib/Paheko/Email/Mailings.php 5286e9dc482beb953c237a6def36f3fbf5f026e09209c245771a732220b67fb2
|
||||||
|
F src/include/lib/Paheko/Email/Templates.php 27a909c9c9e9f261797769097f93b11fae7a1304d940b21e07a931b3f15b1d01
|
||||||
|
F src/include/lib/Paheko/Entities/API_Credentials.php af3482891c625853a9f38fe2a17f7deb9f6b51fc0eb2539c3c2f9391e04e8e68
|
||||||
|
F src/include/lib/Paheko/Entities/Accounting/Account.php a9dc45d2237aaa00c86e2fdb470f757e92cd24cd6d134fa50aa1b4b3edfa1988
|
||||||
|
F src/include/lib/Paheko/Entities/Accounting/Chart.php d7fb7ded59d304eb99d6b8fc4985bf73b6fd8f978e5a05963cb444ab7d2a7280
|
||||||
|
F src/include/lib/Paheko/Entities/Accounting/Line.php 473fcecdd3c22800106cfb733ea9105066ae0184b2e6ffa8587900c5cde77bfe
|
||||||
|
F src/include/lib/Paheko/Entities/Accounting/Project.php f221f56feec52d958a4df736b080dce528af7ac466ec799967365619b5fefed5
|
||||||
|
F src/include/lib/Paheko/Entities/Accounting/Transaction.php 877151f889d9aeb63a22953d31c42113f961c90b7445d7b1727ad575e081fd70
|
||||||
|
F src/include/lib/Paheko/Entities/Accounting/TransactionLinksTrait.php 9e8c62dbd3fb808b20412535d065279e57edeb0b3bca78f52747598a70f1a934
|
||||||
|
F src/include/lib/Paheko/Entities/Accounting/TransactionSubscriptionsTrait.php 6d7d38b625e1703c495fcf4bd3ec1c2cc273eb5942ce9b93a7d175bbfad5ab83
|
||||||
|
F src/include/lib/Paheko/Entities/Accounting/TransactionUsersTrait.php 5038ed021fba4e56bc8e6be768283f12f5e6881e6c97b8f37762e5d694a922ca
|
||||||
|
F src/include/lib/Paheko/Entities/Accounting/Year.php bd9796c31856f5ec40806784cead891c567683445f77c58496c2f286c403a3bb
|
||||||
|
F src/include/lib/Paheko/Entities/Email/Email.php e24405674c55b378a3fe4bea2ee57f1449049c74ec6352ce50a4a80649221fbd
|
||||||
|
F src/include/lib/Paheko/Entities/Email/Mailing.php e71284ec734199c060f27709e60227517a324e893ad7e7b7542f8143d8bf27fa
|
||||||
|
F src/include/lib/Paheko/Entities/Email/Message.php ba4dc91b79edc17533840b3af57f8e3b4cf1159f85722b5027cacd1915091339
|
||||||
|
F src/include/lib/Paheko/Entities/Files/File.php 2e4dbd2fd6b30a7704eaf85fb116b702553971112cb9a827f38bb0c2a3d9ed31
|
||||||
|
F src/include/lib/Paheko/Entities/Files/FilePermissionsTrait.php e5ac5707517af5932bcf286c1c95159f2d17d7529a9af842f8c860d76cd11c0d
|
||||||
|
F src/include/lib/Paheko/Entities/Files/FileThumbnailTrait.php 6608d4caab67ba703c467ee836f5346f91ea476276a330d6797db01e283acf81
|
||||||
|
F src/include/lib/Paheko/Entities/Files/FileVersionsTrait.php 6fc878b2fb66bb02ccfd4afa945756a9bdec0613d310d731d2b91b3e297a9a77
|
||||||
|
F src/include/lib/Paheko/Entities/Module.php 2bfdedeb7adee9579401ad5e3f78db292d43a135dc01b4a7c79a4798986735d9
|
||||||
|
F src/include/lib/Paheko/Entities/Plugin.php 5ba82415019306b83727f62460c57fc9f1475528cab3074fb13909e138f29d9c
|
||||||
|
F src/include/lib/Paheko/Entities/Search.php 9502b9219a5b40647651732fc2f56bfb0049c0f12bc3a025c7d710ab909394ef
|
||||||
|
F src/include/lib/Paheko/Entities/Services/Fee.php 3116155735de6a5f0e7649c40da9b789daa196d970e4523b091074e0d875d7b0
|
||||||
|
F src/include/lib/Paheko/Entities/Services/Reminder.php 51bb91ad7ac4d4804f887382c4c5a7ff58bab5eccfd5a44f06bb707fc505f613
|
||||||
|
F src/include/lib/Paheko/Entities/Services/ReminderMessage.php fbaef97c819df828721440d5fc47cabe2a1d23a26fb4dbbd2537516a4cba132b
|
||||||
|
F src/include/lib/Paheko/Entities/Services/Service.php 9de625b4c8ca882ebbb552552255d00ecf3315429a1bba631f2767aa94e096d7
|
||||||
|
F src/include/lib/Paheko/Entities/Services/Service_User.php 40f2eaf44b60d3ffb5cc8afe9902593dad11c1edc72a4e0a32a7430db2c6967b
|
||||||
|
F src/include/lib/Paheko/Entities/Signal.php a5e7ac2ccc7fbdcacdde3769249f0d267012785acf1362592939730c2c9c66be
|
||||||
|
F src/include/lib/Paheko/Entities/Users/Category.php 6413ce3b9175ed74a30c4cd685737b19e61ed959837dcd8e6b125d8dd3cec62b
|
||||||
|
F src/include/lib/Paheko/Entities/Users/DynamicField.php 082994b2d2c2314269321886289edbd7fbf6ac68f2f1fe2b2ccc727d5f7420c3
|
||||||
|
F src/include/lib/Paheko/Entities/Users/User.php e3c30ce20e15325c815586e66ae3385097309ea1a90faae1258ce7be963d9bd2
|
||||||
|
F src/include/lib/Paheko/Entities/Web/Page.php 42fca84ebfe3f747008cd68bb9ffcd29fa1a930982a36b5ede7cb7b5158679d7
|
||||||
|
F src/include/lib/Paheko/Entity.php b8ca90fb3a9034590c580cd897993bf04f51cff4dc84185bc7bc52f5382803d6
|
||||||
|
F src/include/lib/Paheko/Extensions.php 75ac18b3ca043cbf179aaadca4f2c8349da578b7f785036134487186726d27ac
|
||||||
|
F src/include/lib/Paheko/Files/Files.php 16545358437543c09c52d6380e015b4d6bf5bdf2887efa44a9ac09464d7ff4cb
|
||||||
|
F src/include/lib/Paheko/Files/Storage.php ba31577894ea74d9acad5fc73b5cb7f1038bf80469bb1a9f8fec0d9c86b56027
|
||||||
|
F src/include/lib/Paheko/Files/Storage/FileSystem.php 1e6d4c57f1d647287bc3f459cc3d47bbdcf00c49996bab6db50cb9824010d8d2
|
||||||
|
F src/include/lib/Paheko/Files/Storage/SQLite.php 8d794bb5a72c9f809ba9a9ed3407d1a035fea9fb747576fee4152b0a89deed97
|
||||||
|
F src/include/lib/Paheko/Files/Storage/StorageInterface.php 2921ea55a0f6e802950323abae575df6e6624e774ff9b1fe6edeeeaf791e3a4f
|
||||||
|
F src/include/lib/Paheko/Files/Transactions.php 1385346800e1a8d45d75a891657690b4d5fda06eb77c19b38861623b41afeede
|
||||||
|
F src/include/lib/Paheko/Files/Trash.php bbb480f47e0d87179824c1457dd252102852b83b15904d73336a8e9ae3abe11b
|
||||||
|
F src/include/lib/Paheko/Files/Users.php 03407caa6e0d61b3ef7b0fa896212611bd517cc9ae318883b836a03d03991d92
|
||||||
|
F src/include/lib/Paheko/Files/WebDAV/NextCloud.php 229f5fb71514108df6a23adaf454d8923ff239d0af27efa1d592bfbfd1e5d86a
|
||||||
|
F src/include/lib/Paheko/Files/WebDAV/Server.php 3f2d99c0c189211b6302057b791b583a4d404913aa891511294fc8100a8793b3
|
||||||
|
F src/include/lib/Paheko/Files/WebDAV/Session.php d427f05aa517fa12557c3470e828cfc48a7ff9ac4631d7a6b6c2087110498c58
|
||||||
|
F src/include/lib/Paheko/Files/WebDAV/Storage.php f55e8e076239e5fad6c0f3082dd102e6e0cb58caa4ef398d6d80e4033fb37220
|
||||||
|
F src/include/lib/Paheko/Files/WebDAV/WebDAV.php 73a217a837b2e90673dd35c8dffcc452cc0ec072e91c74abe98837afa36efed5
|
||||||
|
F src/include/lib/Paheko/Form.php 4d2c42aac6bc65fad279ae7b017b175faff35fb707c3ef62ba67314929c86d0b
|
||||||
|
F src/include/lib/Paheko/Install.php 38c05fd8307f6f4b2cc60bcf3aae64c5d52dbc68457407fa37fcd9c88439d937
|
||||||
|
F src/include/lib/Paheko/Log.php 17fdc8dca9b5fa3291bd61ebeb243dbdb32410b88f5e5805fd31d810f562759f
|
||||||
|
F src/include/lib/Paheko/Plugins.php 31c5631e873444fad42cde9e433c94288f437580f71fcb0e4ff63be03a987d31
|
||||||
|
F src/include/lib/Paheko/Search.php 6e24dc0bda30e39235cf505275f4e9d309f01437f3c5e3071283095cc712e49d
|
||||||
|
F src/include/lib/Paheko/Services/Fees.php a75ded20d288cbf6f086daf15cf36154780a05f2880de7e32b5eefde00059391
|
||||||
|
F src/include/lib/Paheko/Services/Reminders.php da771eb57ba22b54d8643ed5d76a50fce651e11f67fbe43b6313299a8da8c216
|
||||||
|
F src/include/lib/Paheko/Services/Services.php 6ec7982e4235f39763d401f84851933a429435cdc3a2da7ba823bba41ef42b88
|
||||||
|
F src/include/lib/Paheko/Services/Services_User.php 9e67c6257146aeba80f4a225ce463240e1de29c225a3c5eced10042a80469433
|
||||||
|
F src/include/lib/Paheko/Static_Cache.php edc4248208668422dc2d910933903bcb230d48c3612e42bd5417eddb1f5c6cb6
|
||||||
|
F src/include/lib/Paheko/Template.php 0b6840d1d669afd5815f9686eaca9d5995b050caa9ff76c69e849f304c5abc66
|
||||||
|
F src/include/lib/Paheko/Upgrade.php 1f6f24d62a884167c7a54a705c7924e15ef9f43ed0e5cbe2316b65411ba98042
|
||||||
|
F src/include/lib/Paheko/UserException.php 6f9f5ffa6da08080d84fc154f02ff20ad57d5f508da390fbf382534465a195ef
|
||||||
|
F src/include/lib/Paheko/UserTemplate/CommonFunctions.php b87628aa1010cbfb6ea8b6d2f746e82e0aa123c793f354ed89176d667eea31fe
|
||||||
|
F src/include/lib/Paheko/UserTemplate/CommonModifiers.php e21813cdbc0d6156d2b857bf85ae56acb2b2e28a34b12b3627a42ad5e0d7e0cc
|
||||||
|
F src/include/lib/Paheko/UserTemplate/Functions.php 440081c003aa222e4fbeded563f4971f5aac271e08d3b7cda1db7718098d0c4d
|
||||||
|
F src/include/lib/Paheko/UserTemplate/Modifiers.php 22201197247089daaa9bc4b61adf598cae3de084a04eb6d131558d192310c9f2
|
||||||
|
F src/include/lib/Paheko/UserTemplate/Modules.php c899e03ae03563b4bba626f31a9df8df806a74ca70f15e1a14610f6dab97ab3b
|
||||||
|
F src/include/lib/Paheko/UserTemplate/Sections.php cc144cf763041dbf5a148aa9e1d10638e65049d4f8fca6564d8188345890f6fc
|
||||||
|
F src/include/lib/Paheko/UserTemplate/UserTemplate.php 6b9729b0bebb6b53cb5f9fada8445985af0f593f1b5dc1366f577b3bfed9ff23
|
||||||
|
F src/include/lib/Paheko/Users/AdvancedSearch.php f508f34992cf1fa47e556f3b4185b52c66eeb78f874de858c408cc44f954f27d
|
||||||
|
F src/include/lib/Paheko/Users/Categories.php e3917ac1a89abef0ba1dd71793502d2d412e8ae278b4c2dbbc3f1bb423e4323a
|
||||||
|
F src/include/lib/Paheko/Users/DynamicFields.php bb7a043b7dfa12377b56f3131dd3daa773a429f25af4a8584bfed997f65ba569
|
||||||
|
F src/include/lib/Paheko/Users/Session.php 9e16088dbda0feef4e641faa83223e4eaec143f9bbf82d7a27701044a63567f8
|
||||||
|
F src/include/lib/Paheko/Users/Users.php 8b056aca383dc42802ec5ba7b8b96f9e5fdd7fdaa1162a5d1e1a1f7f2b72862d
|
||||||
|
F src/include/lib/Paheko/Utils.php 4381ec7b83632d5b56578772035bc0d95d2b1b37182a1376fdb1771392d4a637
|
||||||
|
F src/include/lib/Paheko/Web/Cache.php 541d11136dffacc1fed40f049cc260d7f3c2ef7ad318410bde9c80729499957f
|
||||||
|
F src/include/lib/Paheko/Web/Render/AbstractRender.php 576f498e9357474ec793aab4fbe460035c6c3fa3b9d55207f326588d8332552f
|
||||||
|
F src/include/lib/Paheko/Web/Render/Encrypted.php 055b068332ddf95ba0f29d43e715aa6f66227ee3c011df1369d135d0b1304142
|
||||||
|
F src/include/lib/Paheko/Web/Render/Extensions.php a42e230e2b6c7ae3dba5d3cbfd957bb95eb2105f8c79c38d20d93eb84c7d09c5
|
||||||
|
F src/include/lib/Paheko/Web/Render/Markdown.php d45beb860c8f99cd0f7b1e0f784b34d42e458afd67516807952e7260bafdff16
|
||||||
|
F src/include/lib/Paheko/Web/Render/Render.php bf9ea0b4507b7701c34778cc266be9e9529e6e4be150b4fa52e923a31f7c465a
|
||||||
|
F src/include/lib/Paheko/Web/Render/Skriv.php 472606401bd6631e54bcb7081a3b17f12790f9249a528aeba348b364126b0719
|
||||||
|
F src/include/lib/Paheko/Web/Router.php 562eda56629e12b5d0710703fc3f48071caa1df99127101f1cfdaea481c7c928
|
||||||
|
F src/include/lib/Paheko/Web/Sync.php 4745ad2187f7b0651b417d7b1c5b45a558eaf9f3aeb25e0252fd4233df27d51c
|
||||||
|
F src/include/lib/Paheko/Web/Web.php 853a03d12281d2cf2e976bc9f61439420e041af600c581b8025764d7016d39d5
|
||||||
|
F src/include/lib/dependencies.list a2ecd905ca0fc5fdc1cb35ab808f409ba96746c7b2fa891a83f6e8974ed1d875
|
||||||
|
F src/include/migrations/1.1/30.php c393e962ee1933a051ef041551b2ab1d27cb8f990eece5ccdcb0a2b78c5861a4
|
||||||
|
F src/include/migrations/1.1/31.sql 410442c903644007e377e60e0df7face87512613e91530c5f8b74c0f6036208b
|
||||||
|
F src/include/migrations/1.2/1.2.0.sql 0689e84c69dfabad05afd6f4638e3e30ceb02d3487c3be277457a2afd75b79cc
|
||||||
|
F src/include/migrations/1.2/1.2.1.sql b8ed39033fc2127eb9c8c3e5e9c950b02e7ca6a8ce35b0e051129cc06f7d2951
|
||||||
|
F src/include/migrations/1.2/1.2.2.php a4b2e1e6221dd431314fd872bd93e9d78357c97273060a5d934cbc98c45ed5f5
|
||||||
|
F src/include/migrations/1.2/schema.sql da30dfe665476016616504dd95adb74d712ea7dc8d9cafce0819052558b93104
|
||||||
|
F src/include/migrations/1.3/1.3.0-rc12.sql 11161ac317a08dda515f12560e778982950363cec241fa8a09bdb6988925ec49
|
||||||
|
F src/include/migrations/1.3/1.3.0-rc13.sql b6b78bf4c8116aa01c7fc55a571506d6627fb8f194ac5561824830083334c558
|
||||||
|
F src/include/migrations/1.3/1.3.0-rc14.php 93634bbe5dcc813eedfe3ccee41b65253b4211057faa7b799b28fd7007d0d96e
|
||||||
|
F src/include/migrations/1.3/1.3.0-rc14.sql cb37686db57f21310b326ef0bef7e0dc1b6785d15ad3b7bdfbf38b1aea80c06a
|
||||||
|
F src/include/migrations/1.3/1.3.0-rc15.sql fa08177ded47239bfd04ca852d9ed046eec0fecb491179ba25f0f54995890adb
|
||||||
|
F src/include/migrations/1.3/1.3.0-rc2.php 48d00a8704fec118b3378199cdd13b9800f1fcb160a5466e52ed6f5e9b110080
|
||||||
|
F src/include/migrations/1.3/1.3.0-rc5.php 04b6f67038ea82524e7f4d469eb79b253aab692b87c5012f01e1c01b289fbfea
|
||||||
|
F src/include/migrations/1.3/1.3.0-rc5.sql 870ceef216f7ae31189e389543aeaa4d990083ac8d382ff5d775b4b140395324
|
||||||
|
F src/include/migrations/1.3/1.3.0-rc7.php 49dfa481b37334158fc0df017a4749bae504900468301f866f2876e0be3fa02b
|
||||||
|
F src/include/migrations/1.3/1.3.0.php 37e1876293e26690ee923e04a4a466bda3bbe9a0a1d62266b833f14b42104169
|
||||||
|
F src/include/migrations/1.3/1.3.0.sql 02437ff2468951a43547a548965cbf37b8c5852fcc9ac31b05fdae40cf80ad9c
|
||||||
|
F src/include/migrations/1.3/1.3.0_bookings.sql 70038509b6da43357389713b1fffc47346ca6034efab63d0c6be9d9bd0b7bb93
|
||||||
|
F src/include/migrations/1.3/1.3.0_schema.sql cc2e6bf0f7ebbaa5ac1fe52f3c68bb993115fb14758379f9b05c64296458ad84
|
||||||
|
F src/include/migrations/1.3/1.3.2.sql 3a81504a4d49d8226aba81aadf40a0bc1955fcecd3ab5d009186080c70ce4318
|
||||||
|
F src/include/migrations/1.3/1.3.3.sql 765f1b91b165f2d806c00e2673491a76be9c78b37eaf82b2da06691443e403d6
|
||||||
|
F src/include/migrations/1.3/1.3.5.sql 0f6116f331fe383330e803d0261b16e0abf3123e088de8c9e427c85ba7899af6
|
||||||
|
F src/include/migrations/1.3/1.3.6.php 6641862274cd20981136cf9ccb8afa49f4193b357c62011e722e5118c5bb90f5
|
||||||
|
F src/include/migrations/1.3/1.3.6.sql d678a03fa53dfd80ac42479cd1e2deb4d39b07fd1fc3bb6d6f9adbd1d8a833f9
|
||||||
|
F src/include/migrations/1.3/schema.sql 789e6d39a66344c561a8f7538af4df9012dbab55f96887909525440473b48776
|
||||||
|
F src/include/test_required.php 22354c63e51c190b09cdebe4f67da51184e2d2d3f1ffe068dc016fd95fd83ac0
|
||||||
|
F src/index.php 3633bc39287a8bc3e4fc60b80287a12b61710f6e
|
||||||
|
F src/modules/README.txt dd5b3e533be29babbb6d1a3982deee2872519e9db63f4daf68bf765e781670cf
|
||||||
|
F src/pubkey.asc e8974cff9c91a4a2e6dc1749dfe79cc46ecd3750b57a829945aa748a932eb54a
|
||||||
|
F src/pubkey_old.asc 7eb815c6b8508e342c1383400c531c4774d75da553ec05687f7c3c495f6ed21a
|
||||||
|
F src/pubkey_signed.asc 2005d5e9303f9b455be7497161f03ddc835e25eaa1064b5144ba743cf44a3682
|
||||||
|
F src/scripts/cron.php b833b2c35fd1b1fcc053aa8ff775cb31cc5b7ec5ae962fd1fd3fabc5840c0b1f
|
||||||
|
F src/scripts/emails.php 8c7903525ba625f639e5006ced57e50b29c7c40048a44b4f097684049fea1062
|
||||||
|
F src/scripts/handle_bounce.php 8f113ead55cd356a42e223bd61216f26e758ec7bd5d524c69fe50434cf49f5c6
|
||||||
|
F src/scripts/storage.php 37792e3e82b0a0eec5f8651d91fdcfad74dadbaaa0e88ee212d22ea0e24a35a8
|
||||||
|
F src/scripts/upgrade.php c7191a17d2357dc940cf1c66e2084c1a255cccc8ae66b10a654d95bafe06df95
|
||||||
|
F src/sous-domaine.html 570b1ded6010aa8475f0fbd310916c2f171f02147824731a0f8fdb5c15b19492
|
||||||
|
F src/templates/_foot.tpl fd3f94279f98856e94e0bf7646da1d5a9a73d6c47f1f5a1718ec2bc9957db6f4
|
||||||
|
F src/templates/_head.tpl 285112325566e6290ab1f27820869bbfcc8f57f542ae482b38ac6e9e6b35ff7a
|
||||||
|
F src/templates/acc/_table_actions.tpl b564fc53bc4e9d88b2b9f73fe40fde55c69e1b7ddfb6719a97eaa140a835dedc
|
||||||
|
F src/templates/acc/_year_select.tpl 9d69235d945068789898d2dab051f4ad3aa4d241
|
||||||
|
F src/templates/acc/accounts/_nav.tpl 84ce1f0f134dd7c3bf3c417e6a49fe1455a6feb75e8ea44e98005fe83cb59952
|
||||||
|
F src/templates/acc/accounts/all.tpl 527b1a3cf17e6fab54b311b8b26cabb26168506e1359357768156149b745b58e
|
||||||
|
F src/templates/acc/accounts/deposit.tpl 5717951cb833afdf60d7cb0c596489290d350b9f7970c8de24a5d2d69569105b
|
||||||
|
F src/templates/acc/accounts/index.tpl 27ad87475ad3f6251445051c769eaf83c3d8308e746add8e5948d38267e3e6ef
|
||||||
|
F src/templates/acc/accounts/journal.tpl f1c1e22fe191f6a91e2657b9d6a57d7b4d1b181c2599f918412fee40b5b1bf70
|
||||||
|
F src/templates/acc/accounts/reconcile.tpl 763c8b6e15a7926b4794e3d7a718131a0088fc5cfa057690ede103c834dd2b2c
|
||||||
|
F src/templates/acc/accounts/reconcile_assist.tpl 5f4684d54a63e985bef8cb315bb031e0af610a9939bfd60c807f05f8f41cd1f3
|
||||||
|
F src/templates/acc/accounts/simple.tpl 492b45132e107abd27c3f6e5c83f0eca99b45707762924d38d62b3fe752ce236
|
||||||
|
F src/templates/acc/accounts/users.tpl d0ee19ce7a9dbf18ce4f494dddecd49671280d0f36ccedeb72b2945743a67c2b
|
||||||
|
F src/templates/acc/charts/_country_input.tpl 8970124fcce868eff491e4ea0bb41707fb1ddfb619d0f33c05c2284fc7f45b03
|
||||||
|
F src/templates/acc/charts/_nav.tpl 54421037ef8dd93411cdc8030b733bf3f9545961f0a9bde0881dd76ca5e6e4fc
|
||||||
|
F src/templates/acc/charts/accounts/_account_form.tpl 0f5791955c82409298a7a543a881f24d1279a68f808df870bf78b4b3affb1826
|
||||||
|
F src/templates/acc/charts/accounts/_nav.tpl 41dd69badc966c22e7b4b41835961a55d75fa543c29d5605912b710b5cc934aa
|
||||||
|
F src/templates/acc/charts/accounts/all.tpl 41a9827d7adbe228c72a49658782c6f124773753f8e3e86d2716413b2d4e2d07
|
||||||
|
F src/templates/acc/charts/accounts/delete.tpl a20a59f44d562f68568e8c617a83d690246b5df94fd98b0057cb3bd20958c090
|
||||||
|
F src/templates/acc/charts/accounts/edit.tpl f19aaf4a8f5c2a0588cc3c1f24f701dc3cf96718159b7f784ad4a94e267cd63a
|
||||||
|
F src/templates/acc/charts/accounts/index.tpl fae8c70754184c2a20a32c9be764bdac6530e6419344bd7fe8786d4567d2ce43
|
||||||
|
F src/templates/acc/charts/accounts/new.tpl 730cd32e4d87930127eea26f2ba2aaeaf18208a56ed4abebe5d98fea783ca3af
|
||||||
|
F src/templates/acc/charts/accounts/selector.tpl 0fe30f14a9c4d628e0746b7d783576457b3707599d5bdc7a0365e1b95331ef2e
|
||||||
|
F src/templates/acc/charts/delete.tpl 770eef87a72f0fd8f37ff638b21d743c5811e77af9569632275db9836bc45eac
|
||||||
|
F src/templates/acc/charts/edit.tpl b40615c384d6567a65dff280d4b72cb03f3f01321df43d332242833e5a16cdd2
|
||||||
|
F src/templates/acc/charts/index.tpl d93297a9f5d08d87df1fe621d0f4a5f1b477c3961397c70fe2b1c9b36f1148d4
|
||||||
|
F src/templates/acc/index.tpl 961141a8c7629606128ec79b936b30c607ec1d717336e5432df0203b05168b39
|
||||||
|
F src/templates/acc/projects/_list.tpl b400835f183326d1e20018b7905d0b594ef298abc776b6d76555e4515ca82ad5
|
||||||
|
F src/templates/acc/projects/_nav.tpl f31c70f86785821285a04a5ccf247d9b918861772a0479f17230df86b77f284f
|
||||||
|
F src/templates/acc/projects/config.tpl d654a3d8de49c284b90c32a91d18ea3e657b27471fec310667841de5a77b7e19
|
||||||
|
F src/templates/acc/projects/delete.tpl 50483883de6621504d4a3b6e2bdae3f54024e03ef3ae6db3b0636c4126ab6324
|
||||||
|
F src/templates/acc/projects/edit.tpl 866858263cf78aa66e7a0240dc8ed2f528972efa0dfd434ba51bd587f6e44cc3
|
||||||
|
F src/templates/acc/projects/index.tpl 1e74f6bf0469caed2a481a16166daf23fc4c311b80cb92b17d3fe4a567362abb
|
||||||
|
F src/templates/acc/reports/_header.tpl e478688d2dd27e8d909fa2bfe64d77bcbbbe154412efb2136378ed57adda4f46
|
||||||
|
F src/templates/acc/reports/_journal.tpl e70bc0c6869cb4f20309ac90bf5d124eec74c14ffdad6ec9b77738a137b7dab2
|
||||||
|
F src/templates/acc/reports/_journal_diff.tpl 97ed168abada0e4f4c52db6d12fffb2105cbd3d743e934b68783287521ea985a
|
||||||
|
F src/templates/acc/reports/_statement.tpl 8914b0b9aec0568d7736146e15eaf74474444670bc0b1865d3cac05deda573f5
|
||||||
|
F src/templates/acc/reports/_statement_table.tpl fd1b98776b4252de106b7265e977a9c3abb08e640060214e7ca62e479eefe38c
|
||||||
|
F src/templates/acc/reports/balance_sheet.tpl 78ec3533dd8fc56f2a1a3d73bdd1452003b5b8f806ebf182aea7adc0c7befc31
|
||||||
|
F src/templates/acc/reports/graphs.tpl ac8c23572f9bea47f62a6730647b8f6b34fdb435af90e8ae23630382de3e79f0
|
||||||
|
F src/templates/acc/reports/journal.tpl 2cdd15e90566050036fe662fcb86ece8380cfbbd899b1787575c16c11270dc56
|
||||||
|
F src/templates/acc/reports/ledger.tpl 3199442208fca1ecd7e9d3ad136f1392ea1448c6d93118583301b86e400cb0f3
|
||||||
|
F src/templates/acc/reports/statement.tpl b5b79a83845ad5533c02e578606e0a9c284c4571223228e88fbaf3435450303f
|
||||||
|
F src/templates/acc/reports/trial_balance.tpl f64c876e9d221355cddf5713a561b48e11a809e61c0383f6cf8961fa5cb1aedf
|
||||||
|
F src/templates/acc/search.tpl f6fc20649bada08a3765b4ac65337c251e1cf34a37335af6817eb32f8f7a06a5
|
||||||
|
F src/templates/acc/transactions/_form.tpl 2359d454365e2458f10fbe8037ca244469d1ce1c742961a01b140bacaa2a7240
|
||||||
|
F src/templates/acc/transactions/_lines_form.tpl bdefaea554333083b75c8a333e7ce9c05788ecc4678e08ebe049c280bfbe6274
|
||||||
|
F src/templates/acc/transactions/_pending_message.tpl 980bbc8a961d5ce2c23d70dfc99b8751401c233d6dc4245b95c9eab04e055bb8
|
||||||
|
F src/templates/acc/transactions/action_project.tpl c6e17886fe039f74a601aae8e59ac0b34de371f4343cb9165a78ef9138f3cc3b
|
||||||
|
F src/templates/acc/transactions/actions_delete.tpl e4e47c60f4889d5500f4c319c81c38b2903b8f5dc4e719eb6b8ea59dfb111f12
|
||||||
|
F src/templates/acc/transactions/creator.tpl 8d3d1b3556f579ef60d263840e701b875b1613b490bcbf14e1751c93a6b22b47
|
||||||
|
F src/templates/acc/transactions/delete.tpl a52ca8a4358c57f04f1d3651611ecd337cf3023385f8e3a2c0af18daa9615217
|
||||||
|
F src/templates/acc/transactions/details.tpl 9b35ee0ecc23e80996763f7edf843b8822921d8447e5b0e35bb16ffd0edc15a3
|
||||||
|
F src/templates/acc/transactions/edit.tpl f1b0629190fffbd6ec085f4d48562dd97530306ea1b66f400ec0d23009206f07
|
||||||
|
F src/templates/acc/transactions/lock.tpl a4d016d4407f984fcbba55b6e6b989bd04ea0792f0ec9e5a55cfec0932dabaa6
|
||||||
|
F src/templates/acc/transactions/new.tpl 5c27358fa01820f19734fcec1f8425a8a6520f37a452b3e4a417597a378e3ae9
|
||||||
|
F src/templates/acc/transactions/pending.tpl 0aeee62cf38e83b8c55811ad6f8446fde16724d58aff96119aee2fa22c3853d5
|
||||||
|
F src/templates/acc/transactions/selector.tpl 7b3ea49429b1700a2fee6b04f60a9c47257956034a8dc1b3cdf4ee8153dbb873
|
||||||
|
F src/templates/acc/transactions/service_user.tpl 6640beb19ffe0a684a4b71d14848898b1e095d6db6f212724e73c3fedb376b6f
|
||||||
|
F src/templates/acc/transactions/user.tpl 6a563c7bfe8d8af7b2c2bbb4db9f4fe7cb3253706ac2497312fd1cdaed9bcc41
|
||||||
|
F src/templates/acc/years/balance.tpl 1c03ed91c5e41188db976ca901ec570e380d53cffbf9a5fa5210222874d2668a
|
||||||
|
F src/templates/acc/years/close.tpl f4f366882050d2c62e1d0b6c0fbc7a6c41d6a8d1b55594fc4424f897d77c9b8f
|
||||||
|
F src/templates/acc/years/delete.tpl 5b6b3347d51916921e2fe93b90129297141c7dc8709651d7f8fc556629a94012
|
||||||
|
F src/templates/acc/years/edit.tpl 885bfd3bc578109d2153719ea6c5fd60c350576d15341779bdb3eac70167526c
|
||||||
|
F src/templates/acc/years/export.tpl 8758eb1e941fdd1338457c561808b722c3e20b9e63a8f1bd991c950bd088f465
|
||||||
|
F src/templates/acc/years/first_setup.tpl 9f5d11c30c99b0b9c56e665333dbf149d5737c5b0dc17b87b712e33e6345ac6e
|
||||||
|
F src/templates/acc/years/import.tpl e820cde50b74fa04a3887f9d2b179c707ecb9894effcbb290542392ae1e2573f
|
||||||
|
F src/templates/acc/years/index.tpl d3c41fa54dfcf9c1b00342cb4d6f929d9689a6977ba99f48cd3e53d091f3bda5
|
||||||
|
F src/templates/acc/years/new.tpl 6309d13cdc2cb38b5e2b8da1a565467b14588348d0c5504801fcf2032b703398
|
||||||
|
F src/templates/acc/years/select.tpl f5d95242b1dfc4e28da0a26e2572f11f0358bcc76a84e5a1b34bf115340d2d8e
|
||||||
|
F src/templates/ask_share_password.tpl 64a822abef8bffbd21d9d4d1ce5c05cc06d4fafeef01d068e0af6046f0343d02
|
||||||
|
F src/templates/common/_csv_help.tpl d2396fd24265c6d5ec0ad11db694bf685c73d00247d8d44034347f710a06adda
|
||||||
|
F src/templates/common/_csv_match_columns.tpl 3b26a258d5e2401494de4d1f52451cc49fad8fccca0484a26f183490773581f4
|
||||||
|
F src/templates/common/_sql_table.tpl c361e988d8163383ff52ba5b3e7bc735ad8187d7b8da1aa1796793faaa4f12ec
|
||||||
|
F src/templates/common/delete_form.tpl d0d845ada2b1b9c79c636160e5b7c0a08168a59fcad753f1c4dd7588eb1688d6
|
||||||
|
F src/templates/common/dynamic_list_head.tpl abde4332b8d2f310dc5d350877319f245416cc530f38045604b013fedcc6ee5d
|
||||||
|
F src/templates/common/files/_context_list.tpl 92d4b1a7cfda602aa3004a5f063dd1f84e8d47929ba31047630066ef074b0c7b
|
||||||
|
F src/templates/common/files/_file_render_encrypted.tpl 96a545c1d04ba674e9331aba1bf5dbb976d622c792f9dd3a882bb5d2e80815f6
|
||||||
|
F src/templates/common/files/_preview.tpl 2d5be4acf580f38311de0544a426bd467e62d61c6ef2a891948f84a09ee197d7
|
||||||
|
F src/templates/common/files/delete.tpl be0cff6dce2535e8e379daeaab56a68bed9bf673081364c68e2d07de2b093b47
|
||||||
|
F src/templates/common/files/edit_code.tpl fff859ec49c2d8929711ea37211cb3d96aee3b833f6e4110b81c65defc092678
|
||||||
|
F src/templates/common/files/edit_web.tpl 62e2d8808847a858da27a249dac0e4944c693089204889f3c699760c4686fb41
|
||||||
|
F src/templates/common/files/history.tpl 800cf176bc67e04a438429ed17c75608e1fdd899d35fdb76349db49def47da9c
|
||||||
|
F src/templates/common/files/history_rename.tpl cf3891da0eef64621152899dcb15059f3dcac2dbe081a3d3480325db61f6b749
|
||||||
|
F src/templates/common/files/rename.tpl 31f0f230d4d5c067ce3eefba7d13756574a8daa85df7b053f2e2da60f22a2501
|
||||||
|
F src/templates/common/files/share.tpl 8c51b4bce0edad18ff15289becd1f17a3a3b68edc36d62065f21603cbc1f9cee
|
||||||
|
F src/templates/common/files/upload.tpl f4e3d9978c99d9ae9c2f23a008cb1832d1ec55fc93464a94d76d2fa0b69d1826
|
||||||
|
F src/templates/common/search/advanced.tpl 399fb967f8c2b83af7fc60b3e023d909e05fe36417236ee1109641b1136b0953
|
||||||
|
F src/templates/common/search/saved_searches.tpl 25bd296f13c6056708c3e76bd800016bedbe9b37738dbd0a577abf91eb555271
|
||||||
|
F src/templates/config/_menu.tpl 8e80c00714d5a3550e2834a7938c5081febb0fcbe76ec99a2d99318d0e4059d6
|
||||||
|
F src/templates/config/advanced/api.tpl d8e3b6d3d4512c9ad82bf5f496fd8dd4d5a401a960ed1c52e24f7c6cdff74bfe
|
||||||
|
F src/templates/config/advanced/audit.tpl 5ecb9cb203ffe49626195e86c0101a2f8b4aa16f55b603139fb078de7e700ca6
|
||||||
|
F src/templates/config/advanced/errors.tpl 286b66c96854e23a163c99f1869c303fa31db7e0707c5cb921bc2ef57dee32e5
|
||||||
|
F src/templates/config/advanced/index.tpl b39fd9f3d537a19a15dad2ecc0c1732b2aa9110a283a0997bbb8063aa6a00384
|
||||||
|
F src/templates/config/advanced/reopen.tpl 4d422485411d63d9cfb15c13df9acbadda25d0cc008cce87b186cf0cf7bb456a
|
||||||
|
F src/templates/config/advanced/reset.tpl 0f77448e3ea524581acadf687f5fc3e8a7850f4e567654d3b5fa5a0477897a57
|
||||||
|
F src/templates/config/advanced/sql.tpl becbafaa6911ea6f65e9f23f43c1f334db754c8f76fec59b8ebfe4930b84bd36
|
||||||
|
F src/templates/config/advanced/sql_debug.tpl 6edc4e970bd5cd22454342053111494bd50875e07a96c17bce533ab9b4eb24ef
|
||||||
|
F src/templates/config/backup/_menu.tpl 697510b2be8f1c190a9841052aed7f31b19c43c1279d524f92e770319b8eff95
|
||||||
|
F src/templates/config/backup/auto.tpl e1cbf70807040a95b63928b1dd4abcb80425cd0b52d006729e9ec8b40f3cb350
|
||||||
|
F src/templates/config/backup/documents.tpl c9821014c8320c4cc2fcacba514484509d9c43207b7f41662217af6d2fc671d6
|
||||||
|
F src/templates/config/backup/index.tpl 1faf2939208049f19ee7e3f2ea5c728b97afc596384018021a98db5b78908853
|
||||||
|
F src/templates/config/backup/restore.tpl 98b0327c18d0b8ed21c88f9fc8f98b6365030dd222ce1bb8b0110bc81d751933
|
||||||
|
F src/templates/config/backup/versions.tpl 1c7d54cd7d0586aafc16d2d2c84c8eb6bca5f35b66d0c68baa4a0d924b3db3d6
|
||||||
|
F src/templates/config/backup/versions_delete.tpl b02242093c04d66b2e8bf37bc6737711ed8f3420dcbf7c4903cfd2b95bbc0038
|
||||||
|
F src/templates/config/categories/delete.tpl d68a5716bd966c99307ba350b5aed3c9128d3cbb1eefe73c444900b473565f86
|
||||||
|
F src/templates/config/categories/edit.tpl 69738b641dd4f432ea0c06a069dbf036b0f5b9723f8509ed8a287c63226cb46e
|
||||||
|
F src/templates/config/categories/index.tpl 2b49a28f7880c63971edf8c85570e9598b5e52e02f69170dc788b75caa83abd3
|
||||||
|
F src/templates/config/custom.tpl 852e5f8d66253c11551dfacf54bd663c1107e8d617b09d048d6b55037e3cf215
|
||||||
|
F src/templates/config/disk_usage.tpl 41fb60af426697cf57c69b121c6567399fe307e2cbab96176f92037fdc39a639
|
||||||
|
F src/templates/config/edit_image.tpl 249062b118e6a849827d2d853cedb5181b16326b95316890c78d63eef34a4a42
|
||||||
|
F src/templates/config/ext/_details.tpl c5a501557bb3e2e27666a489648c2b7fc4c732d7f81aac0ed0ac632636b6834a
|
||||||
|
F src/templates/config/ext/_nav.tpl fba85f993ea122b1255cfbb640d37f0d88f03a343c3eeec6041a803d76d86a97
|
||||||
|
F src/templates/config/ext/delete.tpl fc672871e7c2928fc62b0e3b932d4e3ebecc9a27290776fbd005991f3e615961
|
||||||
|
F src/templates/config/ext/details.tpl 8f8f84e658123b13eccfdde5d7541ccd0766ebcac0c0919a36eee42196fd8973
|
||||||
|
F src/templates/config/ext/diff.tpl c21a78df5af19cbb7f6f66f4ac6459d08aeb755a102db7176ca424ea6081aa1e
|
||||||
|
F src/templates/config/ext/edit.tpl d3e657b46b5283e46621e6bb17208b51316c5586581fffeffc81f0a79c261473
|
||||||
|
F src/templates/config/ext/import.tpl 6b4c385d0c81686fbad72f8ef274afc59add81e197b44127a9da87502b6ad7fa
|
||||||
|
F src/templates/config/ext/index.tpl 30d78b814eaec87660c6faad9e1b41eb84275876e5a0df360df6d15bfd02164e
|
||||||
|
F src/templates/config/ext/new.tpl 9a8b1a826f500dc0bfce7c25a8fc114dfdb33753ea606fa08355a9d9673c76cd
|
||||||
|
F src/templates/config/fields/delete.tpl 7f5227ca29989fc776e37745f875b1d50baa85f3a2846bdb3ec9a90dadd55aad
|
||||||
|
F src/templates/config/fields/edit.tpl 2651d7db047b2c64de95c65ea3a430f1ea8bf8f30dc3d87529674b3d91b600b2
|
||||||
|
F src/templates/config/fields/index.tpl efd6618c4663447375a623f0b6126e91d16ee5fe077958641c799d60f57b315e
|
||||||
|
F src/templates/config/fields/new.tpl 72353574ecf16f3e4771275f65a1e7ab7ccf872d8911a9e41f913278e7fe5738
|
||||||
|
F src/templates/config/index.tpl 95475a082ca670a84dc14063f2541d0f6469070883eaf5db1b04bff40899a5b7
|
||||||
|
F src/templates/config/server/index.tpl d91eb5a4e4abb2ac1351e6d3c6df3fcaea15eed2b087e912c9a43519cb49e734
|
||||||
|
F src/templates/config/upgrade.tpl cf8e3610f7d1402d20ecb4a5dbef7820237d84c84ed873f2e78ba45f7903785b
|
||||||
|
F src/templates/config/users/field_selector.tpl 4f5e4a822a803fa166638ac1489752d15cb1926dde15980db9d93cca7e442419
|
||||||
|
F src/templates/config/users/index.tpl 8b9b97d305ab0439f2cb6295955e7f1abe66b08627e9030f06a9e0f30518074e
|
||||||
|
F src/templates/docs/_nav.tpl 920527f86b1aefa5c699d82ab2ccddc5d98244969e06b3de69d771b7e3ed4698
|
||||||
|
F src/templates/docs/action_delete.tpl 85a65c16cbcfb058acf21dad9a0d0526eb4242d6aeadbf6f5f030221fb477fb9
|
||||||
|
F src/templates/docs/action_move.tpl cebb332df8dbcdc76a5deafb76f06acde18a3b7306f0544afd29e93682506600
|
||||||
|
F src/templates/docs/action_zip.tpl 114d5fbcba613fa60010bea0f5747072c8b7c1fb24aa19bd50851efa7857283c
|
||||||
|
F src/templates/docs/index.tpl 2fc0c3c4cec6fa948d4d28f79871cde72e76c0e427d6d7a3be5f2c1421db27a8
|
||||||
|
F src/templates/docs/new_dir.tpl efb439d26cd579114e13870c35c39e8a71abb66f1c60618b39465d4e7b3908cb
|
||||||
|
F src/templates/docs/new_doc.tpl 61bd4b47f99b57ebf71141fdc5360bcec4abb40ec811253cb04f8552448508d0
|
||||||
|
F src/templates/docs/new_file.tpl a6c698189b67b187207759403493cd92af38d46dbf004d0ebbde51ad59a28d1b
|
||||||
|
F src/templates/docs/search.tpl 56173f01c0aa5898bc01dd41016f93f87417737417d7b8f609d7e53b3db09300
|
||||||
|
F src/templates/docs/trash.tpl 239164286cd7954f48f5bee144628bc3f3df51f079dce5cc00797bf6e789fd16
|
||||||
|
F src/templates/docs/trash_delete.tpl 09f17d3438bc7406f8b7b8fbc32c5849a66c293b1d5ede463be41cccf413b777
|
||||||
|
F src/templates/emails/login_changed.tpl aaf10e05bad319868dacd8a9fbfa9a321e41adcb46d2d106eba45312db5e396b
|
||||||
|
F src/templates/emails/password_changed.tpl f2ac7406d790310e1854bc428cbc77f533ee662957b696b29c4d5b739d06766e
|
||||||
|
F src/templates/emails/password_recovery.tpl 6a0f64f4f79cfd6dfc667bc29b71784866f797c762166eb168a1f151f5a99403
|
||||||
|
F src/templates/emails/verify_email.tpl a4d3823daeb5ae9fed9bc85b6328235e9a22b8cc34239442a0fa85ad734406d8
|
||||||
|
F src/templates/error.tpl 50ad744aad666beafb6b0b43225732e1337e53698c01b20a045ed12e5704c406
|
||||||
|
F src/templates/index.html abe89f9bfb756bbdfb2f535420e10bb5625eb4e2
|
||||||
|
F src/templates/index.tpl 994ad84e962abdf7aab481571b788f933395a7d19d8f0d56b56447420420b656
|
||||||
|
F src/templates/install.tpl d95835b6de5de137de97570b723823c64efb15af8369cb8201d0e0123118275d
|
||||||
|
F src/templates/legal.tpl 10bbe6d7b52ada7763bac4016dbb8706d0e0b59cdb1db3de03fc7b5a47906b5e
|
||||||
|
F src/templates/login.tpl 8256c7641bd7315c96d7d2663379d07f4cde5f0d070c37c6c0874fcc8a191662
|
||||||
|
F src/templates/login_app.tpl aacba63dfc74e513295fae6ffe1b9a8f65ac8432c2856fccc531714de327bd67
|
||||||
|
F src/templates/login_otp.tpl ac9cba2f9f3656a31d14a951708740264b7da5834dfce3d59a91ea9d0a36e3ec
|
||||||
|
F src/templates/me/_nav.tpl 680aee52295b9a6a4dd4a564aff5f9ad0f302fe897995564156b8297b0ae65a6
|
||||||
|
F src/templates/me/edit.tpl 6962fa61d2acab7743ad26ab954f7647b8a8cce243cbfa791d27f7268c72bd0d
|
||||||
|
F src/templates/me/export.tpl bf02d04af7613f6e11e76d59b99c03b227facd7887e3657d315eb7cf1d04de8b
|
||||||
|
F src/templates/me/index.tpl 1e788bb34faa9ea957ea430fa611d871cda836931c5380f8b9f70ddb9c1bbcf4
|
||||||
|
F src/templates/me/preferences.tpl 18d75a6ee3998d7133090664098702da75e74bc76804f0874b8650de82101255
|
||||||
|
F src/templates/me/security.tpl 00429b96894ee5429e6d59bf0c040619986f5e66c0e76c488fbeeec6c7627a27
|
||||||
|
F src/templates/me/services.tpl 87e02c49816875997252d3c25499d83e79078c965f83127c84cf628c867f3383
|
||||||
|
F src/templates/optout.tpl 59ccf897026fae5afd48b0bcf9b4e34cba3c7397031fd559a9b33fe29fd46c38
|
||||||
|
F src/templates/password.tpl 31ba1206d06499ce283bea1fe3dd4725ae01995e6ec7fb7f5bd3442e95ac4302
|
||||||
|
F src/templates/password_change.tpl 6a5f87eb36c02174bc8dc45ba93c773856071c5e5ade90918b7a369223ce9dd8
|
||||||
|
F src/templates/services/_nav.tpl 5e52af7d0643eaeda6abc9ce7aff3418e6a255b1660cc2dfb797014c198bef5c
|
||||||
|
F src/templates/services/_service_form.tpl 7e9c55acbd09f74fe03f19ed55179a6c16d02461c986b609d0942a54aa924311
|
||||||
|
F src/templates/services/delete.tpl 347481046351c43cd14d97623e42b2a6e6d5f90c9351d095f80ed1faeadf7dcf
|
||||||
|
F src/templates/services/details.tpl 814e435b61db5974050841bb2392e5561fdac3b3eecac26ed3d4e4cb75331359
|
||||||
|
F src/templates/services/edit.tpl 12c859a833be1022ad33a9230f04e18e89715a2311820417ac428b15496db120
|
||||||
|
F src/templates/services/fees/_fee_form.tpl 5de507e3b93aba39dbc015200d08788ed3dbb52c18f808df2459da2ac0791493
|
||||||
|
F src/templates/services/fees/delete.tpl 820c8a6b776f55cbfe57aa9581c0e3ec2f8e005ef9e4ef5c2ff4ba3c868f8e74
|
||||||
|
F src/templates/services/fees/details.tpl 01c98ab39afc4587a7223f9a282b18a7752ad701bed14620f4d21ec11d0937b1
|
||||||
|
F src/templates/services/fees/edit.tpl df78282e9779644ac753be3e9e5de47433cd73dc92d6166a9ce395df6a2cda57
|
||||||
|
F src/templates/services/fees/index.tpl 46e7db2d1b3138dc855cb07c50927998a56d31eaf13f3cc578a95ba3fbf7a9ec
|
||||||
|
F src/templates/services/import.tpl 4484803cc7fdfa52391a265e506579ff0b6ee6a4665f52166dede5c374b81672
|
||||||
|
F src/templates/services/index.tpl 74054465a9f770b4d612764b5a11f224e4b985eb77d78a04313a01111422c7e6
|
||||||
|
F src/templates/services/reminders/_form.tpl 2645d5042ac9b9e0c3fb6410edecc7e84eb5bb17eca65a0ad5336586d9ad1547
|
||||||
|
F src/templates/services/reminders/delete.tpl 95bcd98fcf9bfd492c6dd55a80354f0d123b7916ea5cd68434df99c6ae2ae38e
|
||||||
|
F src/templates/services/reminders/details.tpl 827126e9349ec5307985c739e71ae016f0a48e583f22f25ac33693d923ad6ef8
|
||||||
|
F src/templates/services/reminders/edit.tpl bf5129f51cf1c454c1d9ca99ab0a5cf2baefc225c20fdcdbdeb1f97267a9a458
|
||||||
|
F src/templates/services/reminders/index.tpl d2a030a07f66fd34e275e0b8f5d967ed173ee08f5656326913f994b04918cd4d
|
||||||
|
F src/templates/services/reminders/new.tpl 8974fb9fde0b0d607997c6c56447bb30563fd1467800e5b1e4eead0c24e4b05d
|
||||||
|
F src/templates/services/reminders/preview.tpl 62b7b595c29f01ce071a04deed0d1a34d6f9b989e2fe214e62e98850bdc677ba
|
||||||
|
F src/templates/services/reminders/user.tpl 8f1d568b5d8b64ccdcc5d101df487b65b9c604c3be674c469b062a6ee7ff1b5c
|
||||||
|
F src/templates/services/user/_choice_form.tpl 2bdf0b250d0c1fac8159530837e674ea6047428a800042f9ba3ab4272ed9bea2
|
||||||
|
F src/templates/services/user/_service_user_form.tpl 2a5685417c79c0a723bfb8f340a7fef7f4c26d13a78fc5b5ae962e4911b4ac44
|
||||||
|
F src/templates/services/user/add.tpl a9b93751c54e6350de13fd94e4771105eb7d1a027433286db51337bb7a61bf62
|
||||||
|
F src/templates/services/user/delete.tpl 9a92a85389c44597036a2bdd27a6620e39470a5c1d642dbcdc56fd65be9759c9
|
||||||
|
F src/templates/services/user/edit.tpl 3f7ef103e93c9d98599979bab0bf619436c7badba2d05bf406b06ce5e36bbf39
|
||||||
|
F src/templates/services/user/index.tpl 3993d68104d477b5b3107602ce6d7dbd70b6081f478d34d598ff4f86e9a79dd7
|
||||||
|
F src/templates/services/user/link.tpl 6f582c8e1fb60863e0942c3bcc630fd062992943ba8a0fd138417664423ea4c6
|
||||||
|
F src/templates/services/user/payment.tpl d5e1991249dc65825bdc1513dc96a428ec23afd9bcbe726877346a20c4fbd2bb
|
||||||
|
F src/templates/services/user/subscribe.tpl 956f4af913ed7b1c7356653c774fe96edea481f020b98f86214a788aafd5c7f6
|
||||||
|
F src/templates/static/upgrade_post.html 189bab4a7794569385df112f9227bf928be00fb1071fa658d61a2b898b983fc6
|
||||||
|
F src/templates/users/_details.tpl b3fb59fa846c704a4212369327aa9a96aad20e3dd345b3fc66675a690f970374
|
||||||
|
F src/templates/users/_import_list.tpl c35d5796835eceb572e2a37741ce7ce1e4251114617a0879a06d96a749ed9eff
|
||||||
|
F src/templates/users/_list_actions.tpl 9e89b82f0aad2b5ac99d19cf35c5495c397bf3dd69ed8fe3f203afde57a8e0ef
|
||||||
|
F src/templates/users/_log_list.tpl 08b5d1bd093db3a61e1a8b0cc3a8ac56279612c1e88d9e4b6239525af0a168b8
|
||||||
|
F src/templates/users/_nav.tpl 4e65aedb035f076b1d53d4092ca19d69f854ccc3b090f7e9efd3938ae2093812
|
||||||
|
F src/templates/users/_nav_user.tpl 8a253455d6ae3d40ff81175d577eab1a2bd86df0de3dd0b7f31fb3cac628b885
|
||||||
|
F src/templates/users/_password_form.tpl fb3df829ba483036bc3e09ab6d87797a787552eff5f1bece6aa67caa59ddc48f
|
||||||
|
F src/templates/users/action.tpl 2f37b9ed9af60d94610f8cf5b309b90d9ad2b9b4024380de78b5defff423e735
|
||||||
|
F src/templates/users/delete.tpl 31f1744fa2732f3a91ea89fc9cec1d0b640ed4b48255651dfbd7338a80800e0e
|
||||||
|
F src/templates/users/details.tpl a4b7b4e4cb81fda977776195d423813dd0f21280412f769d89293430b608b5ed
|
||||||
|
F src/templates/users/edit.tpl b1a8abad3507fed835d89540cf38e46841208a0d4f245e8d5b414a8cf667c86d
|
||||||
|
F src/templates/users/edit_security.tpl 9f47b76628e1ffdf7862d1038d4a9afcc7e43f610bea22c472bb27b5b9b4d1eb
|
||||||
|
F src/templates/users/import.tpl c82adaa55c5e94a4462544e7922927a3c5fae87160c09b4594fdac3d87f4116b
|
||||||
|
F src/templates/users/index.tpl 98b52f2c45ffe371edb4ccc9d4f532c9be2c793cf2d0e4ea09c1c667ee9cf227
|
||||||
|
F src/templates/users/log.tpl 6a72a51d09deab43fe3caee7d9d333908c4973898afde9023810983fe3da8e94
|
||||||
|
F src/templates/users/mailing/_nav.tpl 63fc9f91241b6aa3ee139ea9a59b7a37787c505edf6b7c5daa02a6c1900c8e17
|
||||||
|
F src/templates/users/mailing/block.tpl d3cb8291678bac15d24b99ae07b01f9a95f8af7c83b19661103b7f9ff4d13ec4
|
||||||
|
F src/templates/users/mailing/delete.tpl 287d96382be6517ca133c8c8c97d747d57cd39eb2c276141b352d68f647b8fbd
|
||||||
|
F src/templates/users/mailing/details.tpl fa6f584102239e203474f16537e40c741454387e85c003963dd9b105af588b3c
|
||||||
|
F src/templates/users/mailing/index.tpl 7992bafc9ff2ef216d386139dc88b5d9ad869d56f2f72d6fb1b2d5969f7373f1
|
||||||
|
F src/templates/users/mailing/new.tpl 8dc2925045c064e48694d79e455048bbc6f7764aa7c3eb9df71c098c61514a8f
|
||||||
|
F src/templates/users/mailing/optout.tpl efbb38fa59ebae7425aea2ccb2b0413fbb1b52006cc00e8cea39f29037da0d4c
|
||||||
|
F src/templates/users/mailing/recipient_data.tpl d5ad4ec244404a0c1371d98a774094939fe7326cea8c4c655543b25fd2d43fa5
|
||||||
|
F src/templates/users/mailing/recipients.tpl 03df04746b6bdfe093e3ec8c89863356c21e2f1cb476c905fa2175a27b3319f0
|
||||||
|
F src/templates/users/mailing/rejected.tpl 11f5f93f7147be28a02075406f3526f9fe74252159e982daee5394aacdd94167
|
||||||
|
F src/templates/users/mailing/verify.tpl 3380d3fc0bc4b18c8158eb6c7ed41ad2d2e65dffa3b0ecd068f8e571a0cd09bf
|
||||||
|
F src/templates/users/mailing/write.tpl a5ee5946c0ad554aae8c68da54a26372b5f34f3b99c52f95fada058036f365b2
|
||||||
|
F src/templates/users/message.tpl 68d6edcd71bda70cb1025f88c83bed7def3b9afbb280274329075d7d6d3d4265
|
||||||
|
F src/templates/users/new.tpl dfa68c990d769719a079218337375b16d23809e3dd708fe4d6891c380ea7802f
|
||||||
|
F src/templates/users/search.tpl 865c43f3408d50382a733dc0189a1d5bbc7236519af66c8bf4a701c1b6ef85b0
|
||||||
|
F src/templates/users/selector.tpl bb00612e9169adc9e57d81e746ed0fd3accffc3c278f05fa3e80ba2fbc18f249
|
||||||
|
F src/templates/web/_attach.tpl 14872d8a8bd7a44a5b7975b53443a9fc34c8a4547cec4db75bd6309e8172218b
|
||||||
|
F src/templates/web/_history.tpl 8e1b0437e7f81bde064cd017c739b98a7ac9ad54964034b0c27dcf2f56f833d0
|
||||||
|
F src/templates/web/_list.tpl 471d580070e04c9c978441f7519706cc2548736e94fa7d0c916b560eb003f714
|
||||||
|
F src/templates/web/_page.tpl 4156c42d29bfd2a0242641cccab8998a1b6e58042e9019317c43866c107a2602
|
||||||
|
F src/templates/web/_selector.tpl 7ed2030acc7adb26b6b45c756f8eafa36db8cebcefbc6c963bd233ae423bb1e8
|
||||||
|
F src/templates/web/all.tpl aa5ef2cd454b8d636f9ee398511951efbe1c91a375bd1384df02cbb6b3abc48b
|
||||||
|
F src/templates/web/delete.tpl 7d5e7c30bf8b42d65bf566127b1fab38d0b4c664c48dd87693ea8e9d6c855f7d
|
||||||
|
F src/templates/web/edit.tpl c8ff1d7a39618f813852c3e162fbd68b92463d4a340abaa6079d10505bc1c4d2
|
||||||
|
F src/templates/web/index.tpl cda4822b30d24ea1af866c6381d2382d57227fce9a3efb1c55e8f9851d6aa997
|
||||||
|
F src/templates/web/new.tpl fecf4f84d90d66dfa82029a59dc0dfad2e461df3f212fe0d30974fa4466b2435
|
||||||
|
F src/templates/web/search.tpl 12d480905d1b460436854b7b3270bc57ecee5b9ba8ba2e3024432f804df0fd29
|
||||||
|
F src/www/_route.php fbc1235739cf597dd07e10b6f685df089de5a43eff5c0d82d96f441934ecc906
|
||||||
|
F src/www/admin/_inc.php ade6ec023564a91f2107826e7276a003d61e71fba7e154ad2d412dffe30a85e2
|
||||||
|
F src/www/admin/_serviceworker.js 94c15e9c0d42c4acfa82da0e784beefea888c992422855f76fad69fb6f7e56bc
|
||||||
|
F src/www/admin/acc/_inc.php cae640f5568028c3941a885ba88b9628b88dce1dd92ceb420b559de12c2213cc
|
||||||
|
F src/www/admin/acc/accounts/all.php 259df489f0ce8dc2d43535b29a3d41e56d13deff3daf53dda037cdcb23950ee6
|
||||||
|
F src/www/admin/acc/accounts/deposit.php 1551d00b01dccf41008bb41752dca083f13d572fc407596e378f2c5f295a5067
|
||||||
|
F src/www/admin/acc/accounts/index.php 8e62e8fe2f71623c366d26527a6933d03687b1bed2045d957fde57edf712e31c
|
||||||
|
F src/www/admin/acc/accounts/journal.php ec60c74084c422529d5af722160d65d5d1b48899272b6db8844cfcb314795e2e
|
||||||
|
F src/www/admin/acc/accounts/reconcile.php e40db86c79a2184ee63aabcc46429d74bba6f463f9093c550f9cabb0ea7c4f30
|
||||||
|
F src/www/admin/acc/accounts/reconcile_assist.php 479427fb8b43d89bbf55483037d87f8fdb522707e3e4c4258d985f2cb8634f68
|
||||||
|
F src/www/admin/acc/accounts/simple.php 5d4d5e06061543007033e29a3b9c339cb22438c6ab73560f63cadb841c449808
|
||||||
|
F src/www/admin/acc/accounts/users.php 40514630058b097e887dec8bb4896828cfdc913d9466f6d111cc71310863f7ef
|
||||||
|
F src/www/admin/acc/charts/accounts/_inc.php 7d4861d729a9ab7a646b81e48cacee16697b805a4a191f9ccf09ccffceb8d166
|
||||||
|
F src/www/admin/acc/charts/accounts/all.php 6cc19c0d16d21fbf77a0ab3498f1f19ebe26017b9a19017963115a2fe693b343
|
||||||
|
F src/www/admin/acc/charts/accounts/delete.php a15cf614a6b912fb31ad7ac69e89638111b0f77c79e9bbcf0bc67a05051bc90a
|
||||||
|
F src/www/admin/acc/charts/accounts/edit.php d996161f87fc99d8cc3ff9b89e6b816f72ac3d6a98b780422d4968cec4c8e8f2
|
||||||
|
F src/www/admin/acc/charts/accounts/index.php 8d5b8bdfd1583f01e6fafdafbf9845b64a8d338255cdea3a7d2330bd5f76b901
|
||||||
|
F src/www/admin/acc/charts/accounts/new.php 33f507b0f6d6453e5d7d774d06630a6598b3630293a9d2301f705f78d1b0fbd0
|
||||||
|
F src/www/admin/acc/charts/accounts/selector.php 1b98a5ac982e09aafc948ef0c56e63cc3a2c82f1c5986f089be304c79af692aa
|
||||||
|
F src/www/admin/acc/charts/delete.php 952a8b2bdcb95eaa49753cc04ae6e4bdf16fa86a34a59e4fd9f0b407504a4dde
|
||||||
|
F src/www/admin/acc/charts/edit.php cc4c1ce9c62425bc968b13eabe202d4ec6e13ebff47e8834e277f957598eaf2b
|
||||||
|
F src/www/admin/acc/charts/export.php ebcd95b86ed73f2d4000b7501c56b78ee461be9c7dac1cee651d5b739e77268c
|
||||||
|
F src/www/admin/acc/charts/index.php c7d0deab0d719c658831e3924203e730783a12cbfcf607aa3a017a64a4ab809d
|
||||||
|
F src/www/admin/acc/index.php 5cdc30cfce11aafc37e8f442e4e2e8ec0d1301712780037ef9f04191701f5c0f
|
||||||
|
F src/www/admin/acc/projects/config.php 4fe87b3d295c986b65a46664d0394fa234d89390109c9a7beecff3c515be1ba1
|
||||||
|
F src/www/admin/acc/projects/delete.php 7b5c59346a98c8c3d3f19d915e6d0921628b43c44d60e2a8971a8c4d101860a3
|
||||||
|
F src/www/admin/acc/projects/edit.php 6c31beb81d04cc73658103b84812cf1e07d8f3376cc50ea4c9a5f248277f5fa8
|
||||||
|
F src/www/admin/acc/projects/index.php 1273ca37f5f9a6c28131e0d9d9451d7ca83f3fe47d71c32921ca9805aaac1df1
|
||||||
|
F src/www/admin/acc/reports/_inc.php d0cf8a6629a3c1d2d92d5ad20366bed2190ff5f34ffd369dae62321c10cac578
|
||||||
|
F src/www/admin/acc/reports/balance_sheet.php 77da1df82dc55f4bdad7ec317fb34e077455473b4b1558c0c432d8f9b7424b2a
|
||||||
|
F src/www/admin/acc/reports/graph_pie.php 754cacd3890ee75e14c511bef556ad4e2903605c16d5e988416448da6fd0caa6
|
||||||
|
F src/www/admin/acc/reports/graph_plot.php fa120f9c68b525c42cdd5ffbe8af37b77f94b22e8f19a304eba20c156b8aefb8
|
||||||
|
F src/www/admin/acc/reports/graph_plot_all.php df40ccf7889494d01e2d5ed8a35bc1fac196f8a8176f9fdb17d76494ab86931f
|
||||||
|
F src/www/admin/acc/reports/graphs.php a0d771f15c29963fb4800625de9972da4767e520136295123d39aa5edd67f124
|
||||||
|
F src/www/admin/acc/reports/journal.php a71fc0c396b22a9dd154f342943e54590f07f492a1ea5b8520d025367b9adee9
|
||||||
|
F src/www/admin/acc/reports/ledger.php 110c942871607429aeebb96b06ff3578534718e1768536ff35ca4372d3426bb9
|
||||||
|
F src/www/admin/acc/reports/statement.php e8f2524f96a8d1496c07548e72c786d750e344cd85398a16332d4e3f9a0eb80c
|
||||||
|
F src/www/admin/acc/reports/trial_balance.php 21ba816df3c45af15a02e04e7c12e521e9ff92f819bf4e2f029c825b8b095813
|
||||||
|
F src/www/admin/acc/saved_searches.php 073ce71141c97ad3df1df0432bc9ce504913d2dad2d02f91595cf7c6a88f769d
|
||||||
|
F src/www/admin/acc/search.php 1536892f1316ed05faf741906e80852f921c5b94ea6839ec78d1ca2fe89b219a
|
||||||
|
F src/www/admin/acc/transactions/actions.php fc2048c55d23863161b2e718c9194ce7e37f1e424ee81d5aa69a346e68acfbbd
|
||||||
|
F src/www/admin/acc/transactions/creator.php e909867efed5e03a1372607c2d57d815c9ac461d3bb1aaf22526bdb6de496b6c
|
||||||
|
F src/www/admin/acc/transactions/delete.php 302c38dc9e46ea4c688605f8252e2bbbeb014d44450f1e07d5dcc174ed2a2efc
|
||||||
|
F src/www/admin/acc/transactions/details.php 1a82cb539aba1cefae849e91333f263f78b4f7ccb2bd4e1c9c313fe5467f6b17
|
||||||
|
F src/www/admin/acc/transactions/edit.php 8c9a45805a0afd6b975068f1dd1051c08827fef6cc9bd23bde8d56f78e8136bb
|
||||||
|
F src/www/admin/acc/transactions/lock.php 20bd2034e7d7f94f657853f4ebcb2352d9a96c38bdb7cf87c206c63a343f1e25
|
||||||
|
F src/www/admin/acc/transactions/new.php 66324e1269604038bfb8276006d83dfba168311dab4b5b939fa3a4749f2b3b4d
|
||||||
|
F src/www/admin/acc/transactions/pending.php 6f7db72b7ec7aad39dfbdea2e1417f56ed90598a9418da75d62ab0f0c7d8f8f3
|
||||||
|
F src/www/admin/acc/transactions/selector.php c32b47d2fdfde59e3f0dfe2f9d84ae35dc7c468bd87ce7c83a764638890dbc03
|
||||||
|
F src/www/admin/acc/transactions/service_user.php c55459a2ecc5768548a7baa68f44d2af137dc8243f8eac0bbacd0adb459c595f
|
||||||
|
F src/www/admin/acc/transactions/user.php b8ff73c47d6fdad975badc0585fd399fe1d628744c20b62a79e788aaff59c068
|
||||||
|
F src/www/admin/acc/years/balance.php e69827e7493236088c1a9f7bcdc8c2511fbff75e3f0cb48b62b9904d25a0a0fe
|
||||||
|
F src/www/admin/acc/years/close.php 19f4c7b62ec6bd98cba9ddd446ad5243572dc674c974da98ebfd2110c10c286c
|
||||||
|
F src/www/admin/acc/years/delete.php a0b5106cf351ba4917c8379830714254cc2bf37c1ead208b6495c6fab11b20fd
|
||||||
|
F src/www/admin/acc/years/edit.php 12a6439d201ac147eaa8fd39855d53a81300f18a7f73bff025489b7055205651
|
||||||
|
F src/www/admin/acc/years/export.php 188de31dff824e5682fdd3fc9e50f2ad28fa513224f185efa99896ffcda4945b
|
||||||
|
F src/www/admin/acc/years/first_setup.php 7a2a8e3723fb979b191f3d4750dda2cbd1267b566d14341bcb63dc0ef7d4c9c0
|
||||||
|
F src/www/admin/acc/years/import.php 5e69b590e1a6367821093cff4f247d11cc548af20adf9a66ef4040abd2392213
|
||||||
|
F src/www/admin/acc/years/index.php d91200350501d0b9c3f908e83b52bfc2460929027154a635abeeae74b31a7ce9
|
||||||
|
F src/www/admin/acc/years/new.php 2bce3c1c2bf136e22c790ce4261b511dbcb87ee25b96c7f7376cb6874de7bd37
|
||||||
|
F src/www/admin/acc/years/select.php 4ad57b28fed100d7d6fa0fbc975a70c86ad3b0050f68b07989d8c5ab99cecc32
|
||||||
|
F src/www/admin/common/files/_preview.php e1c2013500cd5e64b8879c7d74aa6560fedac0f78f76ad3693a85c5c52fe197d
|
||||||
|
F src/www/admin/common/files/delete.php f1535255a7103a67862ffb5d813a7c28329c33e10de95dd3ce47072346ce2732
|
||||||
|
F src/www/admin/common/files/edit.php 82ff52989824382fdeec8d2a760f59e7446d39254963075d743a3a2f76787227
|
||||||
|
F src/www/admin/common/files/history.php a3da49e4e2fc55073facaa02d282c7dedcc4fd7ea888fbcac5a7499339774443
|
||||||
|
F src/www/admin/common/files/preview.php 57467471f7339070f6cc4e593f882d385275160e55e6b2c51ee2461f5bcbeeff
|
||||||
|
F src/www/admin/common/files/rename.php 9a722ed83d3c52f3bc4d418ed7e36fe9cf3ec9cb23dec06fde950efc2d80733c
|
||||||
|
F src/www/admin/common/files/share.php cc2b2fe5cd433c909f1f62e1a9b77d9f8edbb861a244aa2a9d58ff47c9d30f54
|
||||||
|
F src/www/admin/common/files/upload.php 3ac3d647062bf54b277a5a6511116c933534eb197f84c0679fa246d0dc155061
|
||||||
|
F src/www/admin/common/saved_searches.php f6a7dfbe4fb521a0dbfcaec8f2c063656173c7ec44b0e8478eec8198d6f7801c
|
||||||
|
F src/www/admin/common/search.php 874b0d6ba447e2165521f3eeb66b65d5f9d08050e952a26d5c8f1344e90fb253
|
||||||
|
F src/www/admin/config/_inc.php 38dbaa8eceba69256ce410069345adbfb22d8fe7682f9df4decdacc6468f5186
|
||||||
|
F src/www/admin/config/advanced/api.php 0867da54514a62f8f2d20520cce6ad570fc0d1b8d493e4af61310c29fa8dc7cb
|
||||||
|
F src/www/admin/config/advanced/audit.php 03c22ee4a5984848ce4aec9056a0d2e69c4e869398622136556c0f5ecefaffc1
|
||||||
|
F src/www/admin/config/advanced/errors.php 11eac7346acc44f433896d8c298e4e4984513b3dd1d35a09868e98ad7361ffd7
|
||||||
|
F src/www/admin/config/advanced/index.php 62c60bb5dda9d2cafee5f506ed81fb6cf91ca9ab25f0b0e614034b59fd8f723f
|
||||||
|
F src/www/admin/config/advanced/reopen.php ee337b79851396fdae8ca2ffe341b26ff15e980daee08b2faba1459e9599ce24
|
||||||
|
F src/www/admin/config/advanced/reset.php 0393a990855aa3af0398e29c30872e6b19d7ff155c8e0267cd99fcea3b6ccafb
|
||||||
|
F src/www/admin/config/advanced/sql.php 39e06fc2830f26a8a9414885140d13b866df48b5803df9cd51b3fafb42e66dea
|
||||||
|
F src/www/admin/config/advanced/sql_debug.php 57db4c8a1e2372b8c2fc3b99fb9987f5fd1f4c9619bda792cb42422cc211fc17
|
||||||
|
F src/www/admin/config/backup/auto.php 41acbdd9ca793c1328e384adc431b2a6cd861230c79b667be3b3564b3f4eaafa
|
||||||
|
F src/www/admin/config/backup/documents.php e6be7da76e1f751c6ef46b47d5c9fc189e1079166838a76953498d8885b27e0f
|
||||||
|
F src/www/admin/config/backup/index.php 62bf45aec0e6e343b5200cb48c38f4961abe964558801d88e910d2296aac95d9
|
||||||
|
F src/www/admin/config/backup/restore.php 5b2b274e78a1a2c6292b8bd39dd28232a0e752bd4972b516afa7f8e3fa3cec37
|
||||||
|
F src/www/admin/config/backup/versions.php 5ff829ca122c68a95617e7e311370d419a36b491648a57502481fd3c5c19e2ac
|
||||||
|
F src/www/admin/config/categories/delete.php 916faad60b44a231ce8d030efbc7ef59c85a906bd527c06093ed11039f09d0a1
|
||||||
|
F src/www/admin/config/categories/edit.php ee348e18d4d44bec1c85015b2da557cf9136ea2d26a4b570a4173b64977af2f4
|
||||||
|
F src/www/admin/config/categories/index.php 448c26ecf521369c846c739883bf63f6fbbc693cd91853f257313ab2cce7cc08
|
||||||
|
F src/www/admin/config/custom.php 11ac0ff0852393501dcd33b6fb49c1538b0cc6f4b8b68ee31da2877d720da618
|
||||||
|
F src/www/admin/config/disk_usage.php a2b18d7edebe5fac6b733b629b2b1a3fac20b32351f1b40d3c4e1b37d7f0eb8d
|
||||||
|
F src/www/admin/config/donnees/import.php 63fd2e55bf602e3d5fe16d6e70777b313af7f87c465aafdfe2a435dbbc88d443
|
||||||
|
F src/www/admin/config/edit_file.php 692b6bbf107750afefe073622930a2e141d593554ea782a95561b172cc9fd025
|
||||||
|
F src/www/admin/config/ext/delete.php 2da7be8aa33eefbfe67d49e0b48b1364f8c69ac0a96fbb1dbe5ffbe1986af7cd
|
||||||
|
F src/www/admin/config/ext/details.php 566bc1c5fa2e61eda4fb87efcf1dfbd25290a6746f50302b856789c69496244a
|
||||||
|
F src/www/admin/config/ext/diff.php 234a1118d048e5c1f3f91917db8f462b2e4bb28548dc0641940fc66b4adabbd7
|
||||||
|
F src/www/admin/config/ext/edit.php b5243bc9140fe85b972b9d133b98563ade7dfea9f616321dcad6f186ab99848e
|
||||||
|
F src/www/admin/config/ext/import.php 964ad852bebff092c8692925ef1d53dadea1c709fe97668376dd370074795b14
|
||||||
|
F src/www/admin/config/ext/index.php bb4dbd0fa845c5e02d67679804aff26fccfbc5433837a852fb174f0446cc637c
|
||||||
|
F src/www/admin/config/ext/new.php 0961b290769a6173873ee4774a8d5c7d5ccf55dd280c11e117a4f4e6ad74b9fb
|
||||||
|
F src/www/admin/config/fields/delete.php 263592cb30b7504f7a0b427cee61bcf5081f29fd8a49fc06065a5d2012b94044
|
||||||
|
F src/www/admin/config/fields/edit.php f93c22353dde208d4d2847a7212ac019d1a0f79c6ab929f6aa77b902079b2d4b
|
||||||
|
F src/www/admin/config/fields/index.php 99f1f4d7bb810ab71630a63bd2fe256a23ca24e8d3805b3f0396e5af9957066a
|
||||||
|
F src/www/admin/config/fields/new.php bca14e9b81f76a107bde1b529133a5a73b81f3eaa5b6af877a2ac6258d7473c1
|
||||||
|
F src/www/admin/config/index.php 4db930d9b14080adfef2ce9e4ec8957a9440820dabe00c56a212180dd2ade8a8
|
||||||
|
F src/www/admin/config/server/index.php 7f7388c4fe053ba5d6df01b7f618d756174c80cd007ddc8364f3219f8bc7a66b
|
||||||
|
F src/www/admin/config/upgrade.php c5bb2b07cf8b4a1ec6ac86b863e69f887f5a1f39f1e16511fc960c6a60baf40a
|
||||||
|
F src/www/admin/config/users/field_selector.php f4671d4b51d890b704dcc3922fe0306068931d338a9938cc696bad1d358f0376
|
||||||
|
F src/www/admin/config/users/index.php 2f0fb565c5c00361c3764b238648f75292741a774f1727c747f50cc1e6c36358
|
||||||
|
F src/www/admin/docs/_inc.php ac1a2736b738ea049b291d091d4990de822a3dad9da8738c72ec37fc33721a9d
|
||||||
|
F src/www/admin/docs/action.php defab0b85f30183c24d18b0bf257f9265223ab0fef09de8dab16c26bb4a5307b
|
||||||
|
F src/www/admin/docs/index.php 4b81f3ee6581fe9c332372443e971e05541ce8575edd986b75131258079023c0
|
||||||
|
F src/www/admin/docs/new_dir.php d9a2d4e8ea9da76cde050fcdf7f753a897d5615684b8e5eb279acbacb794600c
|
||||||
|
F src/www/admin/docs/new_doc.php 82bd169bdaf9da94cd93835dbf22f242f4578ef360b2ad373920877760c82484
|
||||||
|
F src/www/admin/docs/new_file.php 46f2bffa0060f6adf4fea3c8234bd989749ed61c5c0189a10b8edb985930072c
|
||||||
|
F src/www/admin/docs/search.php 60c138d0ec74854f837509f53a7cf89051107b80005b4eb936a89c83dc5c7fb0
|
||||||
|
F src/www/admin/docs/trash.php d65494e835637c234604220b64b2dc42fceb2750d2cd9edfc4e993516719bb5c
|
||||||
|
F src/www/admin/handle_bounce.php ac546e03a21ec3687a12482fed3753a8e4632fab632297807c72afa9ef5394d6
|
||||||
|
F src/www/admin/index.php 6888125b475826e000e8c5a9dbe2e63c1a13bfc572c2bf3da862ac94ab00cd37
|
||||||
|
F src/www/admin/install.php ec203de9f710ce484103d5b623a0c1633c42cf296590049724d81064d9638444
|
||||||
|
F src/www/admin/legal.php 0a9422c75dcd77fa25491251bcd50133701cedea52b375ef4bb04dad99400a57
|
||||||
|
F src/www/admin/login.php 54c2d517c3c4593d25ce4d214bcfad2e30f642d7b83ed41659dbbd975041861c
|
||||||
|
F src/www/admin/login_app.php d686b28a90aed936f5cdcf7ff636b56a870c072cfa1b1b971bcf9dccc6411176
|
||||||
|
F src/www/admin/login_otp.php ac1615acf75604122a55095eaebd3fefa798258b3aa922ea05b462a112568f26
|
||||||
|
F src/www/admin/logout.php 5976597893d20d84a0b61f11aeb59ef4132db8a3ee4abf5ee02f67da2f95f1a9
|
||||||
|
F src/www/admin/manifest.php bfc8e82584902075944a114a09c28e22228633cab6d1d397cb9d527b7e6868a6
|
||||||
|
F src/www/admin/me/_inc.php 640b9e5ede51b34b04e9ae12dd8ce86a5880c0d419667613afbf9616eb29a66b
|
||||||
|
F src/www/admin/me/edit.php 3fea9f4c5895e7c9fc87821eeed975600f87dae95801c4c31523e4ae6cce5edc
|
||||||
|
F src/www/admin/me/export.php 64f543bd103a8fd984c6038d56e3f2df7f7f8a49a249551296f7dc91ef2d9da0
|
||||||
|
F src/www/admin/me/index.php 8a7bc848f78d5c99c98316d33cd3037d02aefb29a777df6164740d1eef48b952
|
||||||
|
F src/www/admin/me/preferences.php 8ae1dd650e1f59fb3b1ecfe633ee7152a47e220ad45019220cee58e7464dc074
|
||||||
|
F src/www/admin/me/security.php ed288514fbc34bddf0f0c519c296915d8f24a00d235734a603d72996588d9750
|
||||||
|
F src/www/admin/me/services.php 01519cc713f0657c8f261dbb184975de3ed48a57fce0ebfb3ec0f4b6ad06b7b7
|
||||||
|
F src/www/admin/optout.php a8e32e6d40ce7352c42607250ce195bdf0ecce812ff851df511efbd770839262
|
||||||
|
F src/www/admin/password.php ba2d7caf0bfa0c87955adc16d18f91d43f5582dccd5b6666e0ac8cdfdc0df695
|
||||||
|
F src/www/admin/services/_inc.php 2ee23bab80c9f3a0e11e0952eb9d4b7e08e6232ff3a8460f2b4f3e994a92a084
|
||||||
|
F src/www/admin/services/delete.php 9505dfb7053aa03d3a4c923f2d6aa08626a9b40bfda37669846f42a43217b9cc
|
||||||
|
F src/www/admin/services/details.php e1c3c955c42f1cd8541bba05ace6d18d2d06c982c336c134eddcb9c36161d150
|
||||||
|
F src/www/admin/services/edit.php 6480b8b88194204854bf074dbd00e90db82aab47a1dd19012cf567b06453ce42
|
||||||
|
F src/www/admin/services/fees/delete.php fb4d08069c863250ad7507a076f1c73ab8456fb42088d789cd45fd65e278c5c2
|
||||||
|
F src/www/admin/services/fees/details.php 1a695a0e563656c0aad0de57e4deaa9fed8c0ff78022cffcd85478eb944e756b
|
||||||
|
F src/www/admin/services/fees/edit.php 29f6e346ecd4120640f1bee44ed5e0bb6965cc0d328f5bf0c278fd4114228adf
|
||||||
|
F src/www/admin/services/fees/index.php 66ec678b3e5abe953b0a10b3a07a58579f254c295d96fb13be41b6392e1627f9
|
||||||
|
F src/www/admin/services/import.php 8b45124880cab3293a0358558e3fd69b337806d53616889a2a76629979591dc2
|
||||||
|
F src/www/admin/services/index.php 1c9db068ebf1bc219861aea1be9e6b3248bff9a3846ce885338af0fbd3d10757
|
||||||
|
F src/www/admin/services/reminders/delete.php 7fa839c1bc9119a3d1f76f536f2305bb2bae21ad7d76fe2a7c18b933d6be12ac
|
||||||
|
F src/www/admin/services/reminders/details.php 7fd507e005d1a5f1cfa790059ee5075c89af3e03ac4ea20828e4dd92493cc285
|
||||||
|
F src/www/admin/services/reminders/edit.php 1cec0cd9241342c30894289539220e73ace46cdd5e29f474449f52cae0fba338
|
||||||
|
F src/www/admin/services/reminders/index.php cc83df448673e653b80c81b56830848d9dba6dad747184b8a7ab078f4d46f92d
|
||||||
|
F src/www/admin/services/reminders/new.php 34e936f9f4e9f53cb9bf1aef8f418bf27804a926aff90a2375840a4ca116b94d
|
||||||
|
F src/www/admin/services/reminders/preview.php b614113fe991e2df7b24761e7f3cc91bad48bdf6133eabc4ccf954e57c0278dc
|
||||||
|
F src/www/admin/services/reminders/user.php 491234f0df7bf9ffebf8365fea031fa00750f6ce2c1935f2bc44d30783a8e224
|
||||||
|
F src/www/admin/services/user/_form.php 6c01868431afe4dd2cdcf392657ad64ae1790c80ceb3fbdba3a22f4e7cd5b848
|
||||||
|
F src/www/admin/services/user/add.php f211c6b3cd75cd0b82fb587937b7f1bbdbd98c057d38cd6e3c57e1b62fc1948f
|
||||||
|
F src/www/admin/services/user/delete.php 258ad809c74de1c88ef22ff8c673276f73ada517513967b6603fe9826fa88360
|
||||||
|
F src/www/admin/services/user/edit.php ac51e77e6c5f5bd531742d1b11caf3396270cfb4b65e7087195f5e17d5c43a8f
|
||||||
|
F src/www/admin/services/user/index.php f8e9112ec82b953c448f64f09ce2aa35a09d592cc10ff0e10d659e591a9003f9
|
||||||
|
F src/www/admin/services/user/link.php fadf825ef461c07fc967a4d93dcd95fbdfcdc28132a89cbe527debafd44b8831
|
||||||
|
F src/www/admin/services/user/payment.php ffae6c1087e650bad783d3500a117b8087eadce740b3bd86f193ed9d8e15a79b
|
||||||
|
F src/www/admin/services/user/subscribe.php f757166bd54bc23ad61f172357669333569fb6acee4f427700fbd8c3dc0b8428
|
||||||
|
F src/www/admin/static/admin.css 8d4155645ad7b6efdad7439b160751f3a52fbf2c992d7ae9d0c91b741104dafb
|
||||||
|
F src/www/admin/static/bg.png bb11a55a0d2630f7f225e01109c2fc8dddf1e9e6c989ef1d17d18852703f8438
|
||||||
|
F src/www/admin/static/bg_dev.png 890be2cba33ae3a2e874ceb33167005cab3474a1e61810baad37ad2b46920dd1
|
||||||
|
F src/www/admin/static/doc/api.html c49e5d658057d25634c7ecf725615b7670fa9882e108be1298177f354d5d1378
|
||||||
|
F src/www/admin/static/doc/brindille.html 175273e804f9e2505e0a78a4f3550c51d8442924c43ab39bee66c8c1330914db
|
||||||
|
F src/www/admin/static/doc/brindille_functions.html 0ab56fd11e704f4a023f5651defcd786f5d29bddfa50049e7c0a3d3fd398d2d2
|
||||||
|
F src/www/admin/static/doc/brindille_modifiers.html e69ee882906f75890cd1474892259f4e011b0b00356b9de2bda40350992b94ec
|
||||||
|
F src/www/admin/static/doc/brindille_sections.html 0d86861bfa5a41855a4620713effda34b830e86a85f1ae1bc4b22070885be07c
|
||||||
|
F src/www/admin/static/doc/keyboard.html 55dd27ea5d6efc22202a7ed7b72544c1ec8a4b3a36f4f684f6d096f53ef62821
|
||||||
|
F src/www/admin/static/doc/markdown.html dd127085d32ec6a1d20fdae1fa83c61ed7f38e02b331a6bb0850d3877bd63993
|
||||||
|
F src/www/admin/static/doc/markdown_quickref.html a03b76328e070ee482bdc0e512fbe13c40eeafcbfecd20b98b2f8bcd59121e56
|
||||||
|
F src/www/admin/static/doc/modules.html c143ed67d2bd4e5b741fdef76db80b9bf5af21d52d33e90487d3f0cca8ee0d45
|
||||||
|
F src/www/admin/static/doc/shapes.png cb46b164ccc62541b94dfa202494a947b7147f083701bfe244db5c3243178d9e
|
||||||
|
F src/www/admin/static/doc/skriv.html 1fdf3f7ccd0f1b3a2bf2eebed2c2d9f699b9d246bd320ccf1d56b2402e1273c4
|
||||||
|
F src/www/admin/static/doc/web.html fe4a7a605925630db3cb5be5b13278261a5807bd683d98943a6f9a24d3209513
|
||||||
|
F src/www/admin/static/favicon.png 18c14f40c3ed6d4d73ceb5319c55b05cff7b0677b52ad79ba28d69ef63036aee
|
||||||
|
F src/www/admin/static/font/config.json 5f5d1fe7aaec836ed53d819e312987df71d5ac596edae6662a4ed81b8c8ccd6c
|
||||||
|
F src/www/admin/static/font/paheko.css 73f799c34ebf03ef74668241b776c8f564409f0fc0b1f71147600dadcf00b0b5
|
||||||
|
F src/www/admin/static/font/paheko.eot 10c942b5f295de52b6f26dc4f595ab669c206af85083b447ac19cd20116d4050
|
||||||
|
F src/www/admin/static/font/paheko.svg aa7009cbc76c9ade6bb34f179e97004c542d121afdd3e8fb924a3cb7726b1a78
|
||||||
|
F src/www/admin/static/font/paheko.ttf 620692b9a4ec07f335a71aeded66b2c82ddfe5205c5087d0bb93d844df349ffc
|
||||||
|
F src/www/admin/static/font/paheko.woff 13bf306d815f923ee487f6db4af254b2589f9fcf0cd42f81f066600a69307f09
|
||||||
|
F src/www/admin/static/font/paheko.woff2 60c9a88a0493737e514eb824ac01c6f289adba789986cce918abac3a2694bf84
|
||||||
|
F src/www/admin/static/handheld.css 04e6d592984da5113d3cd6390d681c00dcdcde82aff859a7a89582b4fd2eb99c
|
||||||
|
F src/www/admin/static/icon.png 1387768a8bcff7465be6bb1b4afa8d6d9c22126655288c1edfbb614d86e575f5
|
||||||
|
F src/www/admin/static/pics/img_center.png c93c143b47b8d5a7e2caf3acce64251c4716b9a5
|
||||||
|
F src/www/admin/static/pics/img_flow.png d247e7abf93a2c37d2ba402be08ec432bb0d7bc1
|
||||||
|
F src/www/admin/static/pics/img_left.png e43aa44c9fe1b5508a2af6c1ec124654999b6c6b
|
||||||
|
F src/www/admin/static/pics/img_right.png e2021d96729d6f28fcc946b5ed6742f6732a967e
|
||||||
|
F src/www/admin/static/print.css 5b83453f12d3aea1f8d5f9106a85a9621bd2bf347003e21ba5269706e9476bbe
|
||||||
|
F src/www/admin/static/scripts/accounting.js 7062c9800f0535a3cebec4f44f778d512c4e1806d160e51c1ba3f087bb4318ca
|
||||||
|
F src/www/admin/static/scripts/accounting_setup.js 11af0b9e261c75dd30f0e17e532e3b3bf5a907873b09bd8fbbf7e6c8cea140a3
|
||||||
|
F src/www/admin/static/scripts/accounts_list.js c39abd92100678388e0bebb16a0a2c5b041c44e07aaa032bb3693c837184404d
|
||||||
|
F src/www/admin/static/scripts/advanced_search.js 38b7503d3ad679f89196e723516ba95d6c8ee67548ca56fe4408462afab89c10
|
||||||
|
F src/www/admin/static/scripts/auto_logout.js 9e0c4517de170d9d24c29eaf8f73b21a783fe77ecb2f769eae6edf7ad3c12aaa
|
||||||
|
F src/www/admin/static/scripts/code_editor.css f56ab02df74b8e494feccad9d611547dab875223272ccd4bb50ea1ab16557fe1
|
||||||
|
F src/www/admin/static/scripts/code_editor.js 7f7383a25f337f58bc75fffc25c6303ef9862089fe6fe29d36ed20c8a992aaa3
|
||||||
|
F src/www/admin/static/scripts/color_helper.js 5c89caa19b524d7f54eb9361968b043a641c2772c76e3472714f955ddc87373a
|
||||||
|
F src/www/admin/static/scripts/config_fields.js 4eb6a786648c1d35b9a9c61b2973fccf0fb79460cf8feaa9e91e3762ff0c57a1
|
||||||
|
F src/www/admin/static/scripts/dragdrop-table.js 9fa37ece4c56e3c3025a0cdc87993dba2beee4dedf12d853c85e899df9cf9d51
|
||||||
|
F src/www/admin/static/scripts/file_drag.js 4bb2ca2e887ba23d1ec02ef95d7dee7a8eaa50b2f71bfcdfb0f4e71d425a1a16
|
||||||
|
F src/www/admin/static/scripts/file_input.js 34388e3acf6a87b384f392c207509542cad1d8de641f9e636596ca001733efcc
|
||||||
|
F src/www/admin/static/scripts/global.js c5de6536d3cc1ba2e542ee15a6b36062d2a8d9da336c6c8c81be0dee35ee2ba2
|
||||||
|
F src/www/admin/static/scripts/homescreen.js 80dc4e87743bf7061484eb96cb9c546c27fe4b756935eca7851fd5aa53ab1e70
|
||||||
|
F src/www/admin/static/scripts/lib/code_editor.min.js b93b17e625c99e610d6fd3d8dd17d95421f6c6ff74211448a52c2feed464e21a
|
||||||
|
F src/www/admin/static/scripts/lib/datepicker2.min.js a4c81fc228bbb79c906350181d215a1ab36d44d97f632582b5314a0ba3529163
|
||||||
|
F src/www/admin/static/scripts/lib/gibberish-aes.min.js 8c82e940cf5cf6fb68433bdc6c3a62c71583a60d
|
||||||
|
F src/www/admin/static/scripts/lib/query_builder.js 2535abc10734bbdb7afeee16243047b67c067207f519821b6228fbbd66f9c057
|
||||||
|
F src/www/admin/static/scripts/lib/text_editor.min.js efdbdc1b49c459f111e32708e17aa201749308f683a661c75fe33c6eb9b17033
|
||||||
|
F src/www/admin/static/scripts/lib/unzipit.min.js 8729f4e48a77faee72b09d2503934f705fb5befab597262230c7c26836f52162
|
||||||
|
F src/www/admin/static/scripts/lib/webdav.css e95322578b2e34bde605ec29148d22faa17c7c01c2216f42f17298a1a77788d7
|
||||||
|
F src/www/admin/static/scripts/lib/webdav.fr.js 5101d45a9c20993e773d59bd185c3b93503fb4d2c4256f1f2c0bab6bc7bc9653
|
||||||
|
F src/www/admin/static/scripts/lib/webdav.js 986d04833f6c2fbefb127ca4d6ea663f6977c71233bb996b7445cf9f48236c14
|
||||||
|
F src/www/admin/static/scripts/password.js 6b890f3fa7aaef7c69b83a52cd6fc271984159983b52bc35bd0ead7dcad604e1
|
||||||
|
F src/www/admin/static/scripts/selector.js 62447412c8b62259e1b26e3555204373bc6d17de17a694f25333c13e56c69d0a
|
||||||
|
F src/www/admin/static/scripts/service_form.js 272a6811a71259018ee6713057e96dbcdd1cafb01d332950b8b4438ebb6b5a21
|
||||||
|
F src/www/admin/static/scripts/unzip_restore.js 67bdb4b62bc91deb97f2ec9334a9647908d5d7a03b00eda0614c5940ad6131c9
|
||||||
|
F src/www/admin/static/scripts/web_editor.css d40ba89e0042da03716a45e738870a87810bdd68719a99a442be455ee600af13
|
||||||
|
F src/www/admin/static/scripts/web_editor.js 2a468ebe296331790911d59c5640d9844620a0a14cb67dc823d90b7f26c95fd2
|
||||||
|
F src/www/admin/static/scripts/web_encryption.js 3ddbcf8aee1a21ecf5c76b969ba3a736442e40ec3f7407c23bb4ae8bdbf1b89d
|
||||||
|
F src/www/admin/static/scripts/web_files.js bb326d9c953442cefb014dafd4ce785fe9e866d618af3497796c558905f9cde8
|
||||||
|
F src/www/admin/static/scripts/web_gallery.js 945b4701755b4a3190cf4c436d2086a5e76bc3989f6ff028bd6dd1e03656320a
|
||||||
|
F src/www/admin/static/styles/00-reset.css f7194bdd794e5c85bf67854be876408609a39d66cb36591db021218fc843172e
|
||||||
|
F src/www/admin/static/styles/01-layout.css ceed4a07a76b4b1754397bc30e31f6d74694fd65126d99f5e27f5b821af98909
|
||||||
|
F src/www/admin/static/styles/02-common.css 796f6907d659d94c8d6b9e34fe403090721a41e63862d91b95960d4d66a04d55
|
||||||
|
F src/www/admin/static/styles/03-forms.css 98b68091275f1441772bb4bffa56d24ab57fe8903ae1e3757dd015545a3151c7
|
||||||
|
F src/www/admin/static/styles/04-dialogs.css b54d6fcc0dbc2889a866637974a6b20b723ea656951b5f81ade29f724e127cab
|
||||||
|
F src/www/admin/static/styles/05-navigation.css d163cfca22534f45eadf87a33b64cf00c3145b977d99018317153c8844ca13d9
|
||||||
|
F src/www/admin/static/styles/06-tables-export.css e8aa7570c2347baaa726574c1b9ba1f1d8af26afa05ffedddc086e120cf70f22
|
||||||
|
F src/www/admin/static/styles/07-tables.css 6e376f916abbf49fcb4dbaa4364f04fbe6eee2d86d81ad3072aeef52101b7373
|
||||||
|
F src/www/admin/static/styles/10-accounting.css 7ceb2aea3c8c62d597d5690a537d39ede6260a0e86f67c07113d9d3fffab90a0
|
||||||
|
F src/www/admin/static/styles/config.css c03629a39ab9a4c0c22aecba2bd3a5ff25531d6d23910a4f3d9998f13f17bb99
|
||||||
|
F src/www/admin/static/styles/web.css 2a54776ca23bdf24ad898ed225a13d6332c9aae1284ccacac71e3cd71850c44f
|
||||||
|
F src/www/admin/upgrade.php 513c93bccadb2aa60f0a1357e663d41eafcd2bf4e5c5d0cd73afb344700c1132
|
||||||
|
F src/www/admin/users/_inc.php abdbaa2f4ec0c59547ae197a8d648db4027dfd6c1b2de44090a85643dc73adb5
|
||||||
|
F src/www/admin/users/action.php ee26f54d10acca46fae2bfc23c478abaee4dd98bed45662dd1aa5b27ef18aa59
|
||||||
|
F src/www/admin/users/delete.php c708200474b17b8b7629d3b4ba663761e61e498b4725cdfb20fb4222825bc96d
|
||||||
|
F src/www/admin/users/details.php c1d42dd32cd69c9486d75eedca25a6cc5ec50b83b0763523ddc20a7ffddbc4d1
|
||||||
|
F src/www/admin/users/edit.php af964e43999c4d546360aa5055d595816c73b0dd02c24466a54f7fc647ac2d04
|
||||||
|
F src/www/admin/users/edit_security.php 675d9bee134106cba182829560ef928d1acdfb8ac5dbd94877246f916d519f60
|
||||||
|
F src/www/admin/users/import.php 09125f9e764153dac1ed5dbcf248f6fb03bbd01e9b4db3e6d4506ea49f101b08
|
||||||
|
F src/www/admin/users/index.php 08e654e48d389a4d19e59547f410ddf61a7f412824c581ea908529fe16b83f39
|
||||||
|
F src/www/admin/users/log.php 7ca90afa14599af6c6dc622392b405d22bf6d53b43c219f2f6d0a974028bb4f6
|
||||||
|
F src/www/admin/users/mailing/_inc.php 57578032cef46ba1018a6d63b2a9d5c521215e3f474b3b60943bb931abd1a1a3
|
||||||
|
F src/www/admin/users/mailing/block.php 0a3c768560a5f44f08cecebd15853abb6cb5e4e0569049d3fae5511a9d5715cd
|
||||||
|
F src/www/admin/users/mailing/delete.php 829abccebc1d9f907b56987c450710fbebef2ed38052109cc7882f1d9ec492ce
|
||||||
|
F src/www/admin/users/mailing/details.php 4d906518380e5b008eab1fddd91d711b47f14d86313a4a76c41df1bc251a0b22
|
||||||
|
F src/www/admin/users/mailing/index.php 1da23b3440d917cdb0757c036ab7a43e8a16864bc9147b769431db98335e788a
|
||||||
|
F src/www/admin/users/mailing/new.php 9438ffe5e76306bd9e09a06f962ce9b5483b58b54303beac91509793ba7735b9
|
||||||
|
F src/www/admin/users/mailing/optout.php f2e3a3544878b7e15e9d268e8a56627f726e1aa4317e37a7274070a6d2c0973f
|
||||||
|
F src/www/admin/users/mailing/recipient_data.php 7eb9cf0ebd67d3d7626e6dcee9faa3607de7fdf292c4437ff205642ed38dc24c
|
||||||
|
F src/www/admin/users/mailing/recipients.php 0eab354cfc17b56a7eb2dbdd126b957464eac120fcd0add5ca840f71c75af2bd
|
||||||
|
F src/www/admin/users/mailing/rejected.php 65ed7e261c552c9ce5e01abd171a8e973f55ea05f071463a69b0a3c5ba03b6b7
|
||||||
|
F src/www/admin/users/mailing/verify.php 0d8c00532429618bdb1ca518d761c874132e039027901a1555cb454e24331563
|
||||||
|
F src/www/admin/users/mailing/write.php 70659ff0aaffb58ea98585036a4c6f975ef71ae61abd0d2bdf94dc9b1a6f4246
|
||||||
|
F src/www/admin/users/message.php ef50b2da49b35e1865b21073cb28de7efb8c90dd7eb90cfba8754ccb65ab5ba7
|
||||||
|
F src/www/admin/users/new.php 85a684dbc6faa52ad3e2b34b4c75cbedb0cc2a9cf9360b8f97a7f8f3d53073aa
|
||||||
|
F src/www/admin/users/saved_searches.php cbae2bdad6c708a6a0af69e1c867c7728315e8bf34a1461c69d1e7d40bfdf71d
|
||||||
|
F src/www/admin/users/search.php 7d8a0ea291962cb262c1bf0aa75ac6fbc3de295b2f1a2c6bb6aaf4a3bbcaeba6
|
||||||
|
F src/www/admin/users/selector.php d06d23c96d9d0001bb665307f9836c1dfa29527108aa05e3366a13f238ba0405
|
||||||
|
F src/www/admin/web/_attach.php 5ce5c5a6ce3ea74583d084dbf70837cdfe11f6e98e5b2e4e13fcf4612ef93d9c
|
||||||
|
F src/www/admin/web/_inc.php 61b38f575aab20dbfea9a4e16a3583d4e8fb4dda74015253296e23e6230ade5b
|
||||||
|
F src/www/admin/web/_selector.php acf3fd557a77f05c39ad81736d16621b8d8a714ebf79ebef5da2b8d9c3ae36aa
|
||||||
|
F src/www/admin/web/all.php 6497e3ef800f01db03e0cf88c47415cdad8531bd38381182ebe19d061850eaa3
|
||||||
|
F src/www/admin/web/delete.php 6c70805189cbe52279a094db532b1ebfd75eec55ae4b24ae550687e2cb822042
|
||||||
|
F src/www/admin/web/edit.php 82ce1edb8719890cf118fc1b878b5047f74467a6a0c5a117c7ad8a51180b11b3
|
||||||
|
F src/www/admin/web/index.php 1bb6321afc904b6a23fb092482bcc701141177fb3709788cd34b10eacd7dab6b
|
||||||
|
F src/www/admin/web/new.php f938b8c559cd001605ea6911b2702dfddfa29e751079f9cc9fb1a0b95027c29d
|
||||||
|
F src/www/admin/web/search.php 98e07fd20629e0585ed4b4664bd9fc6b44e8dccb6d6cb28b8b52d707becd68a9
|
||||||
|
F src/www/index.php 7864c3a4fdac4b2976337429d1e8c00f45889f2e87ee3d6e6eabe264b9b2b24c
|
||||||
|
F tests/phpstan.config.php 584e38c18ba41beddd42f3950fea3507db5ca1c3a7acf8e1463877b202f74622
|
||||||
|
F tests/phpstan.neon a05dee1190e8b78ccf641bda959d0470082e65e6bce065fb275981bac8103e7b
|
||||||
|
F tests/psalm.xml cfd86f9bdcd8d968674aa49bd509b8591bd82fa73690c2e92ac1a07f74c3d12c
|
||||||
|
F tests/run.php 43c2b61a01dd66ef5dec76d3164a5313f113ad4f
|
||||||
|
F tests/unit_tests/01_basic/db.php 66b9155618cf937761664cbe5fa03e9dc830a68a
|
||||||
|
F tests/unit_tests/01_basic/paths.php 819d6c04bf6a904ddf21a211feb451f6faf1045a19fe91a99fd5937b76893fe0
|
||||||
|
F tests/unit_tests/01_basic/version.php 3d5d415dd958f5f7504c503fb8ae8aa4d37e8618c77b366618e5cf11ad2cbf6a
|
||||||
|
F tests/unit_tests/02_accounting/money.php b5a7b488bbeba2c166982967b2f613190828ab1a
|
||||||
|
F tools/categories_as_projects.sh 02cc9257edd231e54c643cbddb0cd119e09bf3d9 x
|
||||||
|
F tools/construire_plan_comptable.php 4618b08fe874943c7c9cd161b3a90fd85695453f
|
||||||
|
F tools/doc_md_to_html.php 72736f48da3c23135a273d1c848e71d52de4ebdc1d60d0e3a36e4b4574b19ce9
|
||||||
|
F tools/extract-credit-mutuel-csv.php 853d37e661a71c9160d27897930f57718d52839dd57a7c9c7a46f994044852fc
|
||||||
|
F tools/extract-paypal-csv.php bc690606745e3d6b14352a4e8c89d3a01e6dc11c4b7cad3ea8fdd1d49b96c190
|
||||||
|
F tools/factory/config.local.php c21a4081a63a046ba40cca869bc0a324e9c598e3bfd3e8b66fce25632772c7f1
|
||||||
|
F tools/factory/factory_cron.sh c03a756dec91466571735bea3bdab332e4d8a964bce75b8788d3c40aeacb208a x
|
||||||
|
F tools/factory/factory_cron_emails.sh 7427ba5d8c347a12be09f1017abc04e12a5726eae96c84bcae26dc9151bdaa26
|
||||||
|
F tools/factory/factory_upgrade.sh 21327b0cf6c61a5301588ad990664efd5e365a3e6bdb63073a8adb0b6876e2fe
|
||||||
|
F tools/fossil-verify.sh abbb39b79418d14364a689bd381686e217df35c9ba8dfbf4f7f18e9feebd95df x
|
||||||
|
F tools/make_installer.php 8b0d272bf113a74dc9cce91213bc875229858010a8f1a3830151755af3520d7d
|
||||||
|
F tools/plugin_check_0.8.php df13be68be836729f96a26ec5cb33133d5e6bbce
|
||||||
|
P c64b200ed0d55f953085918860f994bc493073f369a662b16b0237529a4f59da
|
||||||
|
R cd6c0ed44b4e707dd10ba8d5b899143a
|
||||||
|
T +sym-stable *
|
||||||
|
U bohwaz
|
||||||
|
Z 16eef90f5a5efddd361afd30c6f510a9
|
||||||
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
|
iQIzBAEBCgAdFiEExJkkebouil1CwYIBksnacbiI6jQFAmWZWWAACgkQksnacbiI
|
||||||
|
6jRrsBAAjj7Qakj2W6+2nL409awN9Hh+z442p85n6mwMMEIVo6mgV5XqhxKBTvlX
|
||||||
|
posVcQkgR7EuPqzh6C5SfL43CAzZtWIjPrNuD+YtocXC1CQxp6OVbN7AzJTP//xq
|
||||||
|
6O1HqI+Rld6Owk4aUmWze6p26fsYQ3we0bM35tZe6D7Kg2UINcpWqaKUH3OwObuO
|
||||||
|
pl5Emsh4XZSPtF4XQ7GtLuwznOOmtRwY9r0Q7mIwecOMDWz1XRuXhLnaz9a+wc+z
|
||||||
|
3OtLBj+DEiClrJcSV6jt58smkvppXFMAx6fP8CsnhUvB/kuKYcyN0vleLzepJIbY
|
||||||
|
8E98KqR5WaF8XqZPtR2TzgwBEUtFxOco3CPJy5fPoNLGYvh/3US3UG3ksp3FTaY2
|
||||||
|
BEH/wDqcx9/PLmWaJ9Ug8NSuo2STu3opG4xxNBCvuRxeOwdai6gJN0zTi5YS44nl
|
||||||
|
MBh5zN9zjJ2TT3JnxkEC9U0ryec9dc8VbM1cM+Ww7bEPFNvA5/mYHBTbN1HdM3Rw
|
||||||
|
g7Pbhqh/ERunRtz32NW8w10U9FtGHp8cjKOk7AX3gCdggmJRhDlLcmD2ZON/gmPu
|
||||||
|
z2t6nYFFtmANXFwr5stfLkEIEy4byBEwX7V/IfAanfC7lAioy++mfVlvyJLxKJG1
|
||||||
|
c7wPxLZf9Wkdh2F4t3UXMwWihtdDKzMfKxe7NtRNbvQC4LNzEPs=
|
||||||
|
=/3/y
|
||||||
|
-----END PGP SIGNATURE-----
|
1
manifest.uuid
Normal file
1
manifest.uuid
Normal file
|
@ -0,0 +1 @@
|
||||||
|
e39bc64066ab87376ad4450bb15dc71ed8f142d78e16d61abcce7e8655a72283
|
16
remove_check_fees_on_service_user_import.patch
Normal file
16
remove_check_fees_on_service_user_import.patch
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
Index: src/include/lib/Paheko/Services/Services_User.php
|
||||||
|
==================================================================
|
||||||
|
--- src/include/lib/Paheko/Services/Services_User.php
|
||||||
|
+++ src/include/lib/Paheko/Services/Services_User.php
|
||||||
|
@@ -142,11 +142,11 @@
|
||||||
|
|
||||||
|
$id_fee = null;
|
||||||
|
|
||||||
|
if (!empty($row->fee)) {
|
||||||
|
foreach ($fees as $fee) {
|
||||||
|
- if (strcasecmp($fee->label, $row->fee) === 0 && $fee->id === $id_service) {
|
||||||
|
+ if (strcasecmp($fee->label, $row->fee) === 0) {
|
||||||
|
$id_fee = $fee->id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
34
src/.htaccess.www
Normal file
34
src/.htaccess.www
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# Désactiver le multiviews (conflit avec /admin/plugin.php) et les index (sécurité)
|
||||||
|
Options -MultiViews -Indexes
|
||||||
|
DirectoryIndex disabled
|
||||||
|
DirectoryIndex index.php index.html
|
||||||
|
|
||||||
|
# Au cas où
|
||||||
|
<IfModule mod_alias.c>
|
||||||
|
RedirectMatch 403 /include/
|
||||||
|
RedirectMatch 403 /templates/
|
||||||
|
RedirectMatch 403 ^/scripts/
|
||||||
|
RedirectMatch 403 /data/
|
||||||
|
RedirectMatch 403 /.*\.log
|
||||||
|
RedirectMatch 403 /(README|VERSION|COPYING|Makefile|cron\.php)
|
||||||
|
RedirectMatch 403 /config\.(.*)\.php
|
||||||
|
RedirectMatch 403 /sous-domaine\.html
|
||||||
|
RedirectMatch 403 _inc\.php
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
# Redirection dynamique, pour les installations sans vhost dédié
|
||||||
|
# Objectif: supprimer le /www/ de l'URL
|
||||||
|
# Note: il est probable qu'il soit nécessaire d'adapter la configuration
|
||||||
|
# à votre hébergeur !
|
||||||
|
|
||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
RewriteEngine on
|
||||||
|
## Remplacer dans les lignes suivantes
|
||||||
|
## /paheko/ par le nom du sous-répertoire où est installé Paheko
|
||||||
|
RewriteBase /paheko/
|
||||||
|
FallbackResource /paheko/www/_route.php
|
||||||
|
|
||||||
|
## Ne pas modifier les lignes suivantes, les décommenter simplement !
|
||||||
|
RewriteCond %{REQUEST_URI} !www/
|
||||||
|
RewriteRule ^(.*)$ www/$1 [QSA,L]
|
||||||
|
</IfModule>
|
1
src/.php-version
Normal file
1
src/.php-version
Normal file
|
@ -0,0 +1 @@
|
||||||
|
8.1.26
|
114
src/Makefile
Normal file
114
src/Makefile
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
.PHONY: dev-server release deps publish check-dependencies test minify phpstan www htaccess modules installer plugins
|
||||||
|
KD2_FILE := https://fossil.kd2.org/kd2fw/uv/KD2-7.4.zip
|
||||||
|
MODULES_FILE := https://fossil.kd2.org/paheko-modules/zip/trunk/modules.zip
|
||||||
|
PLUGINS_FILE := https://fossil.kd2.org/paheko-plugins/zip/trunk/plugins.zip
|
||||||
|
|
||||||
|
deps:
|
||||||
|
$(eval TMP_KD2=$(shell mktemp -d))
|
||||||
|
#cd ${TMP_KD2}
|
||||||
|
|
||||||
|
wget ${KD2_FILE} -O ${TMP_KD2}/kd2.zip
|
||||||
|
|
||||||
|
rm -rf "include/lib/KD2"
|
||||||
|
unzip "${TMP_KD2}/kd2.zip" -d include/lib
|
||||||
|
|
||||||
|
rm -rf ${TMP_KD2}
|
||||||
|
|
||||||
|
modules:
|
||||||
|
wget ${MODULES_FILE} -O modules.zip
|
||||||
|
unzip -u modules.zip
|
||||||
|
rm -f modules.zip
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
wget ${PLUGINS_FILE} -O plugins.zip
|
||||||
|
unzip -u plugins.zip -d data
|
||||||
|
rm -f plugins.zip
|
||||||
|
|
||||||
|
dev-server:
|
||||||
|
php -S localhost:8082 -d upload_max_filesize=256M -d post_max_size=256M -t www www/_route.php
|
||||||
|
|
||||||
|
test:
|
||||||
|
find . -name '*.php' -not -path './data/*' -print0 | xargs -0 -n1 php -l > /dev/null
|
||||||
|
|
||||||
|
phpstan:
|
||||||
|
phpstan.phar analyze -c ../tests/phpstan.neon include www
|
||||||
|
|
||||||
|
psalm:
|
||||||
|
@# This is required by psalm, but useless
|
||||||
|
@-mkdir vendor
|
||||||
|
@-echo '{"require": {}}' > vendor/autoload.php
|
||||||
|
psalm.phar -c ../tests/psalm.xml
|
||||||
|
|
||||||
|
doc:
|
||||||
|
php ../tools/doc_md_to_html.php
|
||||||
|
|
||||||
|
htaccess:
|
||||||
|
# Removing DOCUMENT_ROOT is important for the cache when using .htaccess, keep it!
|
||||||
|
cat apache-vhost.conf \
|
||||||
|
| sed 's/#RewriteBase/RewriteBase/' \
|
||||||
|
| sed 's/RewriteCond %{DOCUMENT_ROOT}%{REQUEST_/RewriteCond %{REQUEST_/' \
|
||||||
|
> www/.htaccess
|
||||||
|
cat apache-htaccess.conf >> www/.htaccess
|
||||||
|
|
||||||
|
release: test minify doc
|
||||||
|
$(eval VERSION=$(shell cat VERSION))
|
||||||
|
rm -rf /tmp/paheko-build
|
||||||
|
mkdir -p /tmp/paheko-build
|
||||||
|
fossil zip ${VERSION} /tmp/paheko-build/src.zip --name paheko
|
||||||
|
unzip -d /tmp/paheko-build /tmp/paheko-build/src.zip
|
||||||
|
cd include/lib; \
|
||||||
|
rsync --files-from=dependencies.list -r ./ /tmp/paheko-build/paheko/src/include/lib/
|
||||||
|
mv www/admin/static/mini.css /tmp/paheko-build/paheko/src/www/admin/static/admin.css
|
||||||
|
# Generate .htaccess file
|
||||||
|
cd /tmp/paheko-build/paheko/src && make htaccess
|
||||||
|
cd /tmp/paheko-build/paheko/src/www/admin/static; \
|
||||||
|
rm -f font/*.css font/*.json
|
||||||
|
cd /tmp/paheko-build/paheko/src; \
|
||||||
|
rm -f Makefile include/lib/KD2/data/countries.en.json
|
||||||
|
|
||||||
|
# Download modules and only keep the stable ones
|
||||||
|
cd /tmp/paheko-build/paheko/src && \
|
||||||
|
wget https://fossil.kd2.org/paheko-modules/zip/trunk/modules.zip && \
|
||||||
|
unzip -o modules.zip && \
|
||||||
|
rm -rf `find modules/ -name 'ignore' -type f -execdir pwd \;` && \
|
||||||
|
rm -f modules.zip
|
||||||
|
|
||||||
|
# Download plugins and only keep the stable ones
|
||||||
|
cd /tmp/paheko-build/paheko/src/data && \
|
||||||
|
wget https://fossil.kd2.org/paheko-plugins/zip/dev/plugins.zip && \
|
||||||
|
unzip -o plugins.zip && \
|
||||||
|
rm -rf `find plugins/ -name 'ignore' -type f -execdir pwd \;` && \
|
||||||
|
rm -f plugins.zip
|
||||||
|
|
||||||
|
mv /tmp/paheko-build/paheko/src /tmp/paheko-build/paheko-${VERSION}
|
||||||
|
tar czvfh ../build/paheko-${VERSION}.tar.gz --hard-dereference -C /tmp/paheko-build paheko-${VERSION}
|
||||||
|
|
||||||
|
deb:
|
||||||
|
cd ../build/debian; ./makedeb.sh
|
||||||
|
|
||||||
|
windows:
|
||||||
|
cd ../build/windows; make installer
|
||||||
|
|
||||||
|
publish: installer release deb windows
|
||||||
|
$(eval VERSION=$(shell cat VERSION))
|
||||||
|
cd ../build && gpg --armor -u dev@paheko.cloud --detach-sign paheko-${VERSION}.tar.gz
|
||||||
|
fossil uv sync
|
||||||
|
#fossil uv ls | fgrep -v 'paheko-0.8.5' | grep '^paheko-.*\.(tar\.bz2|deb)' | xargs fossil uv rm
|
||||||
|
cd ../build && \
|
||||||
|
fossil uv add paheko-${VERSION}.tar.gz && \
|
||||||
|
fossil uv add paheko-${VERSION}.tar.gz.asc
|
||||||
|
cd ../build/debian && fossil uv add paheko-${VERSION}.deb
|
||||||
|
cd ../tools && fossil uv add install.php && rm install.php
|
||||||
|
fossil uv sync
|
||||||
|
cd ../build/windows && make publish
|
||||||
|
|
||||||
|
check-dependencies:
|
||||||
|
grep -hEo '^use \\?KD2\\[^; ]+|\\KD2\\[^\(:; ]+' -R include/lib/Garradin www | sed -r 's/^use \\?KD2\\|^\\KD2\\//' | sort | uniq
|
||||||
|
|
||||||
|
installer:
|
||||||
|
cd ../tools && php make_installer.php > install.php
|
||||||
|
|
||||||
|
minify:
|
||||||
|
cat `ls www/admin/static/styles/[0-9]*.css` | sed 's/\.\.\///' > www/admin/static/mini.css
|
||||||
|
@# Minify is only gaining 500 gzipped bytes (4kB uncompressed) but making things hard to read/hack
|
||||||
|
@#yui-compressor --nomunge www/admin/static/mini.css -o www/admin/static/mini.css
|
1
src/VERSION
Normal file
1
src/VERSION
Normal file
|
@ -0,0 +1 @@
|
||||||
|
1.3.6
|
21
src/apache-htaccess.conf
Normal file
21
src/apache-htaccess.conf
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# Sinon le reste marchera, sauf les clients OC/NC
|
||||||
|
<IfModule !mod_rewrite.c>
|
||||||
|
# FallbackResource has a bug before Apache 2.4.15, requiring to disable DirectoryIndex
|
||||||
|
# see https://bz.apache.org/bugzilla/show_bug.cgi?id=58292
|
||||||
|
# and https://serverfault.com/questions/559067/apache-hangs-for-five-seconds-with-fallbackresource-when-accessing
|
||||||
|
DirectoryIndex disabled
|
||||||
|
DirectoryIndex index.php
|
||||||
|
|
||||||
|
# Redirect non-existing URLs to the router
|
||||||
|
FallbackResource /_route.php
|
||||||
|
|
||||||
|
# FallbackResource does not work for URLs ending with ".php"
|
||||||
|
# see https://stackoverflow.com/a/66136226
|
||||||
|
ErrorDocument 404 /_route.php
|
||||||
|
|
||||||
|
# NextCloud/ownCloud clients cannot work without mod_rewrite
|
||||||
|
<IfModule mod_alias.c>
|
||||||
|
Redirect 501 /remote.php
|
||||||
|
Redirect 501 /status.php
|
||||||
|
</IfModule>
|
||||||
|
</IfModule>
|
112
src/apache-vhost.conf
Normal file
112
src/apache-vhost.conf
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
Options -Indexes -Multiviews +FollowSymlinks
|
||||||
|
|
||||||
|
DirectoryIndex index.php index.html
|
||||||
|
|
||||||
|
# Some security
|
||||||
|
<IfModule mod_alias.c>
|
||||||
|
RedirectMatch 404 _inc\.php
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
# Recommended, if you have xsendfile module
|
||||||
|
# see https://tn123.org/mod_xsendfile/
|
||||||
|
# Also enable X-SendFile in config.local.php
|
||||||
|
#
|
||||||
|
#<IfModule mod_xsendfile.c>
|
||||||
|
# <Files *.php>
|
||||||
|
# XSendFile On
|
||||||
|
# XSendFilePath /home/paheko/
|
||||||
|
# </Files>
|
||||||
|
#</IfModule>
|
||||||
|
|
||||||
|
# This is to avoid caching mismatch when using mod_deflate
|
||||||
|
# see https://github.com/symfony/symfony-docs/issues/12644
|
||||||
|
<IfModule mod_deflate.c>
|
||||||
|
FileETag None
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
# Allow uploads up to 256 MB where it's required
|
||||||
|
<If "%{REQUEST_URI} =~ m!^/admin/(?:common/files|config/backup)/|^/(?:web)?dav/|^/remote\.php/(?:web)?dav/! && -n %{HTTP_COOKIE}">
|
||||||
|
<IfModule mod_php.c>
|
||||||
|
php_value post_max_size 256M
|
||||||
|
php_value upload_max_filesize 256M
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule mod_php7.c>
|
||||||
|
php_value post_max_size 256M
|
||||||
|
php_value upload_max_filesize 256M
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule !mod_php.c>
|
||||||
|
<IfModule !mod_php7.c>
|
||||||
|
SetEnv PHP_VALUE "post_max_size=256M"
|
||||||
|
|
||||||
|
# There is no way to pass multiple PHP ini settings via PHP_VALUE :-(
|
||||||
|
# so we use PHP_ADMIN_VALUE here. It works unless we have more than 2 settings to change.
|
||||||
|
SetEnv PHP_ADMIN_VALUE "upload_max_filesize=256M"
|
||||||
|
</IfModule>
|
||||||
|
</IfModule>
|
||||||
|
</If>
|
||||||
|
|
||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
AddDefaultCharset utf-8
|
||||||
|
AddCharset utf-8 .html .css .js .txt
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
#RewriteBase /
|
||||||
|
|
||||||
|
RewriteRule \.cache - [R=404]
|
||||||
|
RewriteRule \.well-known/assetlinks.json - [R=404]
|
||||||
|
|
||||||
|
# Stop rewrite for /admin URL, except for /admin/p/ (plugins)
|
||||||
|
RewriteCond %{REQUEST_URI} ^/?admin(?!/p/)
|
||||||
|
RewriteRule ^ - [END]
|
||||||
|
|
||||||
|
# Skip directly to router if possible
|
||||||
|
# Do not try cache if method is not GET or HEAD
|
||||||
|
RewriteCond %{REQUEST_METHOD} !GET|HEAD [OR]
|
||||||
|
|
||||||
|
# Do not try to get from cache if URL is private, or belongs to modules/plugins
|
||||||
|
RewriteCond %{REQUEST_URI} ^/admin|^/?(?:dav|wopi|p|m|api)/|\.php$ [OR]
|
||||||
|
|
||||||
|
# NextCloud routes
|
||||||
|
RewriteCond %{REQUEST_URI} ^/?(?:remote\.php|index\.php|ocs|avatars|status\.php)/ [OR]
|
||||||
|
|
||||||
|
# Private files are not part of the cache
|
||||||
|
RewriteCond %{REQUEST_URI} ^/?(?:documents|user|transaction|ext|attachments|versions)/
|
||||||
|
|
||||||
|
# Skip, go to router directly
|
||||||
|
RewriteRule ^ - [skip=8]
|
||||||
|
|
||||||
|
# Store MD5 hashes in environment variables
|
||||||
|
RewriteCond %{REQUEST_URI} ^(.+)(?:\?|$)
|
||||||
|
RewriteRule ^ "-" [E=CACHE_URI:%1]
|
||||||
|
# Extract file extension (required for Apache to serve the correct mimetype)
|
||||||
|
RewriteCond %{REQUEST_URI} (\.[a-z0-9]+)(?:\?|$)
|
||||||
|
RewriteRule ^ "-" [E=CACHE_EXT:%1]
|
||||||
|
# If no extension, default to .html
|
||||||
|
RewriteCond %{REQUEST_URI} !\.[a-z0-9]+(?:\?|$)
|
||||||
|
RewriteRule ^ "-" [E=CACHE_EXT:.html]
|
||||||
|
RewriteCond expr "md5(%{ENV:CACHE_URI}) =~ /^(.+)$/"
|
||||||
|
RewriteRule ^ "-" [E=CACHE_URI_MD5:%1]
|
||||||
|
RewriteCond expr "md5(tolower(%{HTTP_HOST})) =~ /^((.{2}).+)$/"
|
||||||
|
RewriteRule ^ "-" [E=CACHE_HOST_MD5:%1,E=CACHE_HOST2_MD5:%2]
|
||||||
|
RewriteCond /.cache/%{ENV:CACHE_HOST_MD5}/%{ENV:CACHE_URI_MD5} (.+)
|
||||||
|
RewriteRule ^ "-" [E=CACHE_PATH:%1]
|
||||||
|
|
||||||
|
# Serve symlinks for files
|
||||||
|
RewriteCond %{QUERY_STRING} ="" [OR]
|
||||||
|
RewriteCond %{QUERY_STRING} ^h=[a-f0-9]+$
|
||||||
|
RewriteCond %{DOCUMENT_ROOT}%{ENV:CACHE_PATH}%{ENV:CACHE_EXT} -l
|
||||||
|
RewriteRule ^ %{ENV:CACHE_PATH}%{ENV:CACHE_EXT} [END]
|
||||||
|
|
||||||
|
# Do not try cache for pages if user is logged-in
|
||||||
|
RewriteCond %{HTTP_COOKIE} !pko=
|
||||||
|
# Serve static HTML pages
|
||||||
|
RewriteCond %{QUERY_STRING} =""
|
||||||
|
RewriteCond %{DOCUMENT_ROOT}%{ENV:CACHE_PATH}%{ENV:CACHE_EXT} -f
|
||||||
|
RewriteCond %{DOCUMENT_ROOT}%{ENV:CACHE_PATH}%{ENV:CACHE_EXT} !-l
|
||||||
|
RewriteRule ^ %{ENV:CACHE_PATH}%{ENV:CACHE_EXT} [END]
|
||||||
|
|
||||||
|
# Redirect to router
|
||||||
|
RewriteRule ^ /_route.php [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},END,QSA]
|
||||||
|
</IfModule>
|
905
src/config.dist.php
Normal file
905
src/config.dist.php
Normal file
|
@ -0,0 +1,905 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ce fichier représente un exemple des constantes de configuration
|
||||||
|
* disponibles pour Paheko.
|
||||||
|
*
|
||||||
|
* NE PAS MODIFIER CE FICHIER!
|
||||||
|
*
|
||||||
|
* Pour configurer Paheko, copiez ce fichier en 'config.local.php'
|
||||||
|
* puis décommentez et modifiez ce dont vous avez besoin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Nécessaire pour situer les constantes dans le bon namespace
|
||||||
|
namespace Paheko;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clé secrète, doit être unique à chaque instance de Paheko
|
||||||
|
*
|
||||||
|
* Ceci est utilisé afin de sécuriser l'envoi de formulaires
|
||||||
|
* (protection anti-CSRF).
|
||||||
|
*
|
||||||
|
* Cette valeur peut être modifiée sans autre impact que la déconnexion des utilisateurs
|
||||||
|
* actuellement connectés.
|
||||||
|
*
|
||||||
|
* Si cette constante n'est définie, Paheko ajoutera automatiquement
|
||||||
|
* une valeur aléatoire dans le fichier config.local.php.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const SECRET_KEY = '3xUhIgGwuovRKOjVsVPQ5yUMfXUSIOX2GKzcebsz5OINrYC50r';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var null|int|array
|
||||||
|
*
|
||||||
|
* Forcer la connexion locale
|
||||||
|
*
|
||||||
|
* Si un numéro est spécifié, alors le membre avec l'ID correspondant à ce
|
||||||
|
* numéro sera connecté (sans besoin de mot de passe).
|
||||||
|
*
|
||||||
|
* Exemple: LOCAL_LOGIN = 42 connectera automatiquement le membre avec id = 42
|
||||||
|
* Attention à ne pas utiliser en production !
|
||||||
|
*
|
||||||
|
* Si le nombre spécifié est -1, alors c'est le premier membre trouvé qui
|
||||||
|
* peut gérer la configuration (et donc modifier les droits des membres)
|
||||||
|
* qui sera connecté.
|
||||||
|
*
|
||||||
|
* Si un tableau est spécifié, alors Paheko considérera que l'utilisateur
|
||||||
|
* connecté fourni dans le tableau n'est pas un membre.
|
||||||
|
* Voir la documentation sur l'utilisation avec SSO et LDAP pour plus de détails.
|
||||||
|
*
|
||||||
|
* Exemple :
|
||||||
|
* const LOCAL_LOGIN = [
|
||||||
|
* 'user' => ['_name' => 'bohwaz'],
|
||||||
|
* 'permissions' => ['users' => 9, 'config' => 9]
|
||||||
|
* ];
|
||||||
|
*
|
||||||
|
* Défault : null (connexion automatique désactivée)
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const LOCAL_LOGIN = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autoriser (ou non) l'import de sauvegarde qui a été modifiée ?
|
||||||
|
*
|
||||||
|
* Si mis à true, un avertissement et une confirmation seront demandés
|
||||||
|
* Si mis à false, tout fichier SQLite importé qui ne comporte pas une signature
|
||||||
|
* valide (hash SHA1) sera refusé.
|
||||||
|
*
|
||||||
|
* Ceci ne s'applique qu'à la page "Sauvegarde et restauration" de l'admin,
|
||||||
|
* il est toujours possible de restaurer une base de données non signée en
|
||||||
|
* la recopiant à la place du fichier association.sqlite
|
||||||
|
*
|
||||||
|
* Défaut : true
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const ALLOW_MODIFIED_IMPORT = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Répertoire où se situe le code source de Paheko
|
||||||
|
*
|
||||||
|
* Défaut : répertoire racine de Paheko (__DIR__)
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const ROOT = __DIR__;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Répertoire où sont situées les données de Paheko
|
||||||
|
* (incluant la base de données SQLite, les sauvegardes, le cache, les fichiers locaux et les plugins)
|
||||||
|
*
|
||||||
|
* Défaut : sous-répertoire "data" de la racine
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const DATA_ROOT = ROOT . '/data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Répertoire où est situé le cache,
|
||||||
|
* exemples : graphiques de statistiques, templates Brindille, etc.
|
||||||
|
*
|
||||||
|
* Défaut : sous-répertoire 'cache' de DATA_ROOT
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const CACHE_ROOT = DATA_ROOT . '/cache';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Répertoire où est situé le cache partagé entre instances
|
||||||
|
* Paheko utilisera ce répertoire pour stocker le cache susceptible d'être partagé entre instances, comme
|
||||||
|
* le code PHP généré à partir des templates Smartyer.
|
||||||
|
*
|
||||||
|
* Défaut : sous-répertoire 'shared' de CACHE_ROOT
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const SHARED_CACHE_ROOT = CACHE_ROOT . '/shared';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Motif qui détermine l'emplacement des fichiers de cache du site web.
|
||||||
|
*
|
||||||
|
* Le site web peut créer des fichiers de cache pour les pages et catégories.
|
||||||
|
* Ensuite le serveur web (Apache) servira ces fichiers directement, sans faire
|
||||||
|
* appel au PHP, permettant de supporter beaucoup de trafic si le site web
|
||||||
|
* a une vague de popularité.
|
||||||
|
*
|
||||||
|
* Certaines valeurs sont remplacées :
|
||||||
|
* %host% = hash MD5 du hostname (utile en cas d'hébergement de plusieurs instances)
|
||||||
|
* %host.2% = 2 premiers caractères du hash MD5 du hostname
|
||||||
|
*
|
||||||
|
* Utiliser NULL pour désactiver le cache.
|
||||||
|
*
|
||||||
|
* Défault : CACHE_ROOT . '/web/%host%'
|
||||||
|
*
|
||||||
|
* @var null|string
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const WEB_CACHE_ROOT = CACHE_ROOT . '/web/%host%';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emplacement du fichier de base de données de Paheko
|
||||||
|
*
|
||||||
|
* Défaut : DATA_ROOT . '/association.sqlite'
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const DB_FILE = DATA_ROOT . '/association.sqlite';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emplacement de stockage des plugins
|
||||||
|
*
|
||||||
|
* Défaut : DATA_ROOT . '/plugins'
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const PLUGINS_ROOT = DATA_ROOT . '/plugins';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signaux système
|
||||||
|
*
|
||||||
|
* Permet de déclencher des signaux sans passer par un plugin.
|
||||||
|
* Le fonctionnement des signaux système est strictment identique aux signaux des plugins.
|
||||||
|
* Les signaux système sont exécutés en premier, avant les signaux des plugins.
|
||||||
|
*
|
||||||
|
* Format : pour chaque signal, un tableau comprenant une seule clé et une seule valeur.
|
||||||
|
* La clé est le nom du signal, et la valeur est la fonction.
|
||||||
|
*
|
||||||
|
* Défaut: [] (tableau vide)
|
||||||
|
*/
|
||||||
|
//const SYSTEM_SIGNALS = [['files.delete' => 'MyNamespace\Signals::deleteFile'], ['entity.Accounting\Transaction.save.before' => 'MyNamespace\Signals::saveTransaction']];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adresse URI de la racine du site Paheko
|
||||||
|
* (doit se terminer par un slash)
|
||||||
|
*
|
||||||
|
* Défaut : découverte automatique à partir de SCRIPT_NAME
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const WWW_URI = '/asso/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adresse URL HTTP(S) publique de Paheko
|
||||||
|
*
|
||||||
|
* Défaut : découverte automatique à partir de HTTP_HOST ou SERVER_NAME + WWW_URI
|
||||||
|
* @var null|string
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const WWW_URL = 'http://paheko.chezmoi.tld' . WWW_URI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adresse URL HTTP(S) de l'admin Paheko
|
||||||
|
*
|
||||||
|
* Note : il est possible d'avoir un autre domaine que WWW_URL.
|
||||||
|
*
|
||||||
|
* Défaut : WWW_URL + 'admin/'
|
||||||
|
* @var null|string
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const ADMIN_URL = 'https://admin.paheko.chezmoi.tld/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Affichage des erreurs
|
||||||
|
* Si "true" alors un message expliquant l'erreur et comment rapporter le bug s'affiche
|
||||||
|
* en cas d'erreur. Sinon rien ne sera affiché.
|
||||||
|
*
|
||||||
|
* Défaut : TRUE (pour aider le debug de l'auto-hébergement)
|
||||||
|
*
|
||||||
|
* Il est fortement conseillé de mettre cette valeur à FALSE en production !
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const SHOW_ERRORS = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoi des erreurs par e-mail
|
||||||
|
*
|
||||||
|
* Si renseigné, un email sera envoyé à l'adresse indiquée à chaque fois qu'une erreur
|
||||||
|
* d'exécution sera rencontrée.
|
||||||
|
* Si "false" alors aucun email ne sera envoyé.
|
||||||
|
* Note : les erreurs sont déjà toutes loguées dans error.log à la racine de DATA_ROOT
|
||||||
|
*
|
||||||
|
* Défaut : false
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const MAIL_ERRORS = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoi des erreurs à une API compatible AirBrake/Errbit/Paheko
|
||||||
|
*
|
||||||
|
* Si renseigné avec une URL HTTP(S) valide, chaque erreur système sera envoyée
|
||||||
|
* automatiquement à cette URL.
|
||||||
|
*
|
||||||
|
* Si laissé à null, aucun rapport ne sera envoyé.
|
||||||
|
*
|
||||||
|
* Paheko accepte aussi les rapports d'erreur venant d'autres instances.
|
||||||
|
*
|
||||||
|
* Pour cela utiliser l'URL https://login:password@paheko.site.tld/api/errors/report
|
||||||
|
* (voir aussi API_USER et API_PASSWORD)
|
||||||
|
*
|
||||||
|
* Les erreurs seront ensuite visibles dans
|
||||||
|
* Configuration -> Fonctions avancées -> Journal d'erreurs
|
||||||
|
*
|
||||||
|
* Défaut : null
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const ERRORS_REPORT_URL = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template HTML d'erreur personnalisé (en production)
|
||||||
|
*
|
||||||
|
* Si SHOW_ERRORS est à FALSE un message d'erreur générique (sans détail technique)
|
||||||
|
* est affiché. Il est possible de personnaliser ce message avec cette constante.
|
||||||
|
*
|
||||||
|
* Voir include/init.php pour le template par défaut.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// const ERRORS_TEMPLATE = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loguer / envoyer par mail les erreurs utilisateur ?
|
||||||
|
*
|
||||||
|
* Si positionné à 1, *toutes* les erreurs utilisateur (champ mal rempli dans un formulaire,
|
||||||
|
* formulaire dont le token CSRF a expiré, etc.) seront loguées et/ou envoyées par mail
|
||||||
|
* (selon le réglage choisit ci-dessus).
|
||||||
|
*
|
||||||
|
* Si positionné à 2, alors l'exception sera remontée dans la stack, *et* loguée/envoyée.
|
||||||
|
*
|
||||||
|
* Utile pour le développement.
|
||||||
|
*
|
||||||
|
* Défaut : 0 (ne rien faire)
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
|
||||||
|
// const REPORT_USER_EXCEPTIONS = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activation des détails techniques (utile en auto-hébergement) :
|
||||||
|
* - version de PHP
|
||||||
|
* - page permettant de visualiser les erreurs présentes dans le error.log
|
||||||
|
* - permettre de migrer d'un stockage de fichiers à l'autre
|
||||||
|
* - vérification de nouvelle version (sur la page configuration)
|
||||||
|
*
|
||||||
|
* Ces infos ne sont visibles que par les membres ayant accès à la configuration.
|
||||||
|
*
|
||||||
|
* Défaut : true
|
||||||
|
* (Afin d'aider au rapport de bugs des instances auto-hébergées)
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const ENABLE_TECH_DETAILS = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activation du log SQL (option de développement)
|
||||||
|
*
|
||||||
|
* Si cette constante est renseignée par un chemin de fichier SQLite valide,
|
||||||
|
* alors *TOUTES* les requêtes SQL et leur contenu sera logué dans la base de données indiquée.
|
||||||
|
*
|
||||||
|
* Cette option permet ensuite de parcourir les requêtes via l'interface dans
|
||||||
|
* Configuration -> Fonctions avancées -> Journal SQL pour permettre d'identifier
|
||||||
|
* les requêtes qui mettent trop de temps, et comment elles pourraient
|
||||||
|
* être améliorées. Visualiser les requêtes SQL nécessite d'avoir également activé
|
||||||
|
* ENABLE_TECH_DETAILS.
|
||||||
|
*
|
||||||
|
* ATTENTION : cela signifie que des informations personnelles (mot de passe etc.)
|
||||||
|
* peuvent se retrouver dans le log. Ne pas utiliser à moins de tester en développement.
|
||||||
|
* Cette option peut significativement ralentir le chargement des pages.
|
||||||
|
*
|
||||||
|
* Défaut : null (= désactivé)
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
// const SQL_DEBUG = __DIR__ . '/debug_sql.sqlite';
|
||||||
|
|
||||||
|
/**
|
||||||
|
/**
|
||||||
|
* Mode de journalisation de SQLite
|
||||||
|
*
|
||||||
|
* Paheko recommande le mode 'WAL' de SQLite, qui permet à SQLite
|
||||||
|
* d'être extrêmement rapide.
|
||||||
|
*
|
||||||
|
* Cependant, sur certains hébergeurs utilisant NFS, ce mode peut
|
||||||
|
* provoquer dans certains cas une corruption de la base de données.
|
||||||
|
*
|
||||||
|
* Pour éviter un souci de corruption, depuis la version 1.2.4 'TRUNCATE' est
|
||||||
|
* le mode par défaut.
|
||||||
|
*
|
||||||
|
* Celui-ci ne présente pas de risque, mais la base de données est alors plus
|
||||||
|
* lente.
|
||||||
|
*
|
||||||
|
* Si votre hébergement n'utilise pas NFS, il est recommandé de mettre 'WAL'
|
||||||
|
* ici, cela rendra Paheko beaucoup plus rapide.
|
||||||
|
*
|
||||||
|
* @see https://www.sqlite.org/pragma.html#pragma_journal_mode
|
||||||
|
* @see https://www.sqlite.org/wal.html
|
||||||
|
* @see https://stackoverflow.com/questions/52378361/which-nfs-implementation-is-safe-for-sqlite-database-accessed-by-multiple-proces
|
||||||
|
*
|
||||||
|
* Défaut : 'TRUNCATE'
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
//const SQLITE_JOURNAL_MODE = 'TRUNCATE';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activation du log HTTP (option de développement)
|
||||||
|
*
|
||||||
|
* Si cette constante est renseignée par un fichier texte, *TOUTES* les requêtes HTTP
|
||||||
|
* ainsi que leur contenu y sera enregistré.
|
||||||
|
*
|
||||||
|
* C'est surtout utile pour débuguer les problèmes de WebDAV par exemple.
|
||||||
|
*
|
||||||
|
* ATTENTION : cela signifie que des informations personnelles (mot de passe etc.)
|
||||||
|
* peuvent se retrouver dans le log. Ne pas utiliser à moins de tester en développement.
|
||||||
|
*
|
||||||
|
* Default : null (= désactivé)
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
// const HTTP_LOG_FILE = __DIR__ . '/http.log';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activer la possibilité de faire une mise à jour semi-automatisée
|
||||||
|
* depuis fossil.kd2.org.
|
||||||
|
*
|
||||||
|
* Si mis à TRUE, alors un bouton sera accessible depuis le menu "Configuration"
|
||||||
|
* pour faire une mise à jour en deux clics.
|
||||||
|
*
|
||||||
|
* Il est conseillé de désactiver cette fonctionnalité si vous ne voulez pas
|
||||||
|
* permettre à un utilisateur de casser l'installation !
|
||||||
|
*
|
||||||
|
* Si cette constante est désactivée, mais que ENABLE_TECH_DETAILS est activé,
|
||||||
|
* la vérification de nouvelle version se fera quand même, mais plutôt que de proposer
|
||||||
|
* la mise à jour, Paheko proposera de se rendre sur le site officiel pour
|
||||||
|
* télécharger la mise à jour.
|
||||||
|
*
|
||||||
|
* Défaut : true
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const ENABLE_UPGRADES = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilisation de cron pour les tâches automatiques
|
||||||
|
*
|
||||||
|
* Si "true" on s'attend à ce qu'une tâche automatisée appelle
|
||||||
|
* les scripts suivants:
|
||||||
|
* - scripts/cron.php toutes les 24 heures (envoi des rappels de cotisation,
|
||||||
|
* création des sauvegardes)
|
||||||
|
* - scripts/emails.php toutes les 5 minutes environ (envoi des emails en attente)
|
||||||
|
*
|
||||||
|
* Si "false", les actions de scripts/cron.php seront effectuées quand une personne
|
||||||
|
* se connecte. Et les emails seront envoyés instantanément (ce qui peut ralentir ou
|
||||||
|
* planter si un message a beaucoup de destinataires).
|
||||||
|
*
|
||||||
|
* Défaut : false
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const USE_CRON = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activation de l'envoi de fichier directement par le serveur web.
|
||||||
|
* (X-SendFile)
|
||||||
|
*
|
||||||
|
* Permet d'améliorer la rapidité d'envoi des fichiers.
|
||||||
|
* Supporte les serveurs web suivants :
|
||||||
|
* - Apache avec mod_xsendfile (paquet libapache2-mod-xsendfile)
|
||||||
|
* - Lighttpd
|
||||||
|
*
|
||||||
|
* N'activer que si vous êtes sûr que le module est installé et activé (sinon
|
||||||
|
* les fichiers ne pourront être vus ou téléchargés).
|
||||||
|
* Nginx n'est PAS supporté, car X-Accel-Redirect ne peut gérer que des fichiers
|
||||||
|
* qui sont *dans* le document root du vhost, ce qui n'est pas le cas ici.
|
||||||
|
*
|
||||||
|
* Pour activer X-SendFile mettre dans la config du virtualhost de Paheko:
|
||||||
|
* XSendFile On
|
||||||
|
* XSendFilePath /var/www/paheko
|
||||||
|
*
|
||||||
|
* (remplacer le chemin par le répertoire racine de Paheko)
|
||||||
|
*
|
||||||
|
* Détails : https://tn123.org/mod_xsendfile/
|
||||||
|
*
|
||||||
|
* Défaut : false
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const ENABLE_XSENDFILE = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serveur NTP utilisé pour les connexions avec TOTP
|
||||||
|
* (utilisé seulement si le code OTP fourni est faux)
|
||||||
|
*
|
||||||
|
* Désactiver (false) si vous êtes sûr que votre serveur est toujours à l'heure.
|
||||||
|
*
|
||||||
|
* Défaut : fr.pool.ntp.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const NTP_SERVER = 'fr.pool.ntp.org';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Désactiver l'envoi d'e-mails
|
||||||
|
*
|
||||||
|
* Si positionné à TRUE, l'envoi d'e-mail ne sera pas proposé, et il ne sera
|
||||||
|
* pas non plus possible de récupérer un mot de passe perdu.
|
||||||
|
* Les parties de l'interface relatives à l'envoi d'e-mail seront cachées.
|
||||||
|
*
|
||||||
|
* Ce réglage est utilisé pour la version autonome sous Windows, car Windows
|
||||||
|
* ne permet pas l'envoi d'e-mails.
|
||||||
|
*
|
||||||
|
* Défaut : false
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const DISABLE_EMAIL = false;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hôte du serveur SMTP, mettre à false (défaut) pour utiliser la fonction
|
||||||
|
* mail() de PHP
|
||||||
|
*
|
||||||
|
* Défaut : false
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const SMTP_HOST = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Port du serveur SMTP
|
||||||
|
*
|
||||||
|
* 25 = port standard pour connexion non chiffrée (465 pour Gmail)
|
||||||
|
* 587 = port standard pour connexion SSL
|
||||||
|
*
|
||||||
|
* Défaut : 587
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const SMTP_PORT = 587;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Login utilisateur pour le server SMTP
|
||||||
|
*
|
||||||
|
* mettre à null pour utiliser un serveur local ou anonyme
|
||||||
|
*
|
||||||
|
* Défaut : null
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const SMTP_USER = 'paheko@monserveur.com';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mot de passe pour le serveur SMTP
|
||||||
|
*
|
||||||
|
* mettre à null pour utiliser un serveur local ou anonyme
|
||||||
|
*
|
||||||
|
* Défaut : null
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const SMTP_PASSWORD = 'abcd';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sécurité du serveur SMTP
|
||||||
|
*
|
||||||
|
* NONE = pas de chiffrement
|
||||||
|
* SSL = connexion SSL native
|
||||||
|
* TLS = connexion TLS native (le plus sécurisé)
|
||||||
|
* STARTTLS = utilisation de STARTTLS (moyennement sécurisé)
|
||||||
|
*
|
||||||
|
* Défaut : STARTTLS
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const SMTP_SECURITY = 'STARTTLS';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nom du serveur utilisé dans le HELO SMTP
|
||||||
|
*
|
||||||
|
* Si NULL, alors le nom renseigné comme SERVER_NAME (premier nom du virtual host Apache)
|
||||||
|
* sera utilisé.
|
||||||
|
*
|
||||||
|
* Defaut : NULL
|
||||||
|
*
|
||||||
|
* @var null|string
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const SMTP_HELO_HOSTNAME = 'mail.domain.tld';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adresse e-mail destinée à recevoir les erreurs de mail
|
||||||
|
* (adresses invalides etc.) — Return-Path
|
||||||
|
*
|
||||||
|
* Si laissé NULL, alors l'adresse e-mail de l'association sera utilisée.
|
||||||
|
* En cas d'hébergement de plusieurs associations, il est conseillé
|
||||||
|
* d'utiliser une adresse par association.
|
||||||
|
*
|
||||||
|
* Voir la documentation de configuration sur des exemples de scripts
|
||||||
|
* permettant de traiter les mails reçus à cette adresse.
|
||||||
|
*
|
||||||
|
* Défaut : null
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const MAIL_RETURN_PATH = 'returns@monserveur.com';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adresse e-mail expéditrice des messages (Sender)
|
||||||
|
*
|
||||||
|
* Si vous envoyez des mails pour plusieurs associations, il est souhaitable
|
||||||
|
* de forcer l'adresse d'expéditeur des messages pour passer les règles SPF et DKIM.
|
||||||
|
*
|
||||||
|
* Dans ce cas l'adresse de l'association sera indiquée en "Reply-To", et
|
||||||
|
* l'adresse contenue dans MAIL_SENDER sera dans le From.
|
||||||
|
*
|
||||||
|
* Si laissé NULL, c'est l'adresse de l'association indiquée dans la configuration
|
||||||
|
* qui sera utilisée.
|
||||||
|
*
|
||||||
|
* Défaut : null
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const MAIL_SENDER = 'associations@monserveur.com';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mot de passe pour l'accès à l'API permettant de gérer les mails d'erreur
|
||||||
|
* (voir MAIL_RETURN_PATH)
|
||||||
|
*
|
||||||
|
* Cette adresse HTTP permet de gérer un bounce email reçu en POST.
|
||||||
|
* C'est utile si votre serveur de mail est capable de faire une requête HTTP
|
||||||
|
* à la réception d'un message.
|
||||||
|
*
|
||||||
|
* La requête bounce doit contenir un paramètre "message", contenant l'intégralité
|
||||||
|
* de l'email avec les entêtes.
|
||||||
|
*
|
||||||
|
* Si on définit 'abcd' ici, il faudra faire une requête comme ceci :
|
||||||
|
* curl -F 'message=@/tmp/message.eml' https://bounce:abcd@monasso.com/admin/handle_bounce.php
|
||||||
|
*
|
||||||
|
* En alternative le serveur de mail peut aussi appeler le script
|
||||||
|
* 'scripts/handle_bounce.php'
|
||||||
|
*
|
||||||
|
* Défaut : null (l'API handlebounce est désactivée)
|
||||||
|
*
|
||||||
|
* @type string|null
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const MAIL_BOUNCE_PASSWORD = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Couleur primaire de l'interface admin par défaut
|
||||||
|
* (peut être personnalisée dans la configuration)
|
||||||
|
*
|
||||||
|
* Défaut : #20787a
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const ADMIN_COLOR1 = '#20787a';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Couleur secondaire de l'interface admin
|
||||||
|
* Défaut : #85b9ba
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const ADMIN_COLOR2 = '#85b9ba';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Image de fond par défaut de l'interface admin
|
||||||
|
*
|
||||||
|
* Cette URL doit être absolue (http://...) ou relative à l'admin (/admin/static...)
|
||||||
|
*
|
||||||
|
* Attention si l'image est sur un domaine différent vous devrez activer l'entête CORS:
|
||||||
|
* Access-Control-Allow-Origin "*"
|
||||||
|
*
|
||||||
|
* sinon la personnalisation des couleurs ne fonctionnera pas
|
||||||
|
*
|
||||||
|
* Défaut : [ADMIN_URL]static/bg.png
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const ADMIN_BACKGROUND_IMAGE = 'https://mon-asso.fr/fond_paheko.png';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forcer l'image de fond et couleurs dans l'interface d'administration
|
||||||
|
*
|
||||||
|
* Si positionné à TRUE, les couleurs et l'image de fond définies dans la configuration
|
||||||
|
* seront ignorés.
|
||||||
|
*
|
||||||
|
* Utile pour s'assurer qu'on est sur une instance de test par exemple.
|
||||||
|
*
|
||||||
|
* Défault : false
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
//const FORCE_CUSTOM_COLORS = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Désactiver le formulaire d'installation
|
||||||
|
*
|
||||||
|
* Si TRUE, alors le formulaire d'installation renverra une erreur.
|
||||||
|
*
|
||||||
|
* Utile pour une installation multi-associations.
|
||||||
|
*
|
||||||
|
* Défaut : false
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
//const DISABLE_INSTALL_FORM = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stockage des fichiers
|
||||||
|
*
|
||||||
|
* Indiquer ici le nom d'une classe de stockage de fichiers
|
||||||
|
* (parmis celles disponibles dans lib/Paheko/Files/Backend)
|
||||||
|
*
|
||||||
|
* Indiquer NULL si vous souhaitez stocker les fichier dans la base
|
||||||
|
* de données SQLite (valeur par défaut).
|
||||||
|
*
|
||||||
|
* Classes de stockage possibles :
|
||||||
|
* - SQLite : enregistre dans la base de données (défaut)
|
||||||
|
* - FileSystem : enregistrement des fichiers dans le système de fichier
|
||||||
|
*
|
||||||
|
* ATTENTION : activer FileSystem ET ne pas utiliser de sous-domaine (vhost dédié)
|
||||||
|
* ferait courir de graves risques de piratage à votre serveur web si vous ne protégez
|
||||||
|
* pas correctement le répertoire de stockage des fichiers !
|
||||||
|
*
|
||||||
|
* Défaut : null
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const FILE_STORAGE_BACKEND = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration du stockage des fichiers
|
||||||
|
*
|
||||||
|
* Indiquer dans cette constante la configuration de la classe de stockage
|
||||||
|
* des fichiers.
|
||||||
|
*
|
||||||
|
* Valeurs possibles :
|
||||||
|
* - SQLite : aucune configuration possible
|
||||||
|
* - FileSystem : (string) chemin du répertoire où doivent être stockés les fichiers
|
||||||
|
*
|
||||||
|
* Pour migrer d'un stockage de fichiers à l'autre,
|
||||||
|
* voir Configuration > Avancé (accessible uniquement si ENABLE_TECH_DETAILS est à true)
|
||||||
|
*
|
||||||
|
* Défaut : null
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const FILE_STORAGE_CONFIG = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forcer le quota disponible pour les fichiers
|
||||||
|
*
|
||||||
|
* Si cette constante est renseignée (en octets) alors il ne sera
|
||||||
|
* pas possible de stocker plus que cette valeur.
|
||||||
|
* Tout envoi de fichier sera refusé.
|
||||||
|
*
|
||||||
|
* Défaut : null (dans ce cas c'est le stockage qui détermine la taille disponible, donc généralement l'espace dispo sur le disque dur !)
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const FILE_STORAGE_QUOTA = 10*1024*1024; // Forcer le quota alloué à 10 Mo, quel que soit le backend de stockage
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FILE_VERSIONING_POLICY
|
||||||
|
* Forcer la politique de versionnement des fichiers.
|
||||||
|
*
|
||||||
|
* null: laisser le choix de la politique (dans la configuration)
|
||||||
|
* 'none': ne rien conserver
|
||||||
|
* 'min': conserver 5 versions (1 minute, 1 heure, 1 jour, 1 semaine, 1 mois)
|
||||||
|
* 'avg': conserver 20 versions
|
||||||
|
* 'max': conserver 50 versions
|
||||||
|
*
|
||||||
|
* Note : indiquer 'none' fait qu'aucune nouvelle version ne sera créée,
|
||||||
|
* mais les versions existantes sont conservées.
|
||||||
|
*
|
||||||
|
* Si ce paramètre n'est pas NULL, alors il faudra aussi définir FILE_VERSIONING_MAX_SIZE.
|
||||||
|
*
|
||||||
|
* Défaut : null (laisser le choix dans la configuration)
|
||||||
|
*
|
||||||
|
* @var null|string
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const FILE_VERSIONING_POLICY = 'min';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FILE_VERSIONING_MAX_SIZE
|
||||||
|
* Forcer la taille maximale des fichiers à versionner (en Mio)
|
||||||
|
*
|
||||||
|
* N'a aucun effet si le versionnement de fichiers est désactivé.
|
||||||
|
*
|
||||||
|
* Défaut : null (laisser le choix de la taille dans la configuration)
|
||||||
|
*
|
||||||
|
* @var int|null
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const FILE_VERSIONING_MAX_SIZE = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adresse de découverte d'un client d'édition de documents (WOPI)
|
||||||
|
* (type OnlyOffice, Collabora, MS Office)
|
||||||
|
*
|
||||||
|
* Cela permet de savoir quels types de fichiers sont éditables
|
||||||
|
* avec l'éditeur web.
|
||||||
|
*
|
||||||
|
* Si NULL, alors l'édition de documents est désactivée.
|
||||||
|
*
|
||||||
|
* Défaut : null
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const WOPI_DISCOVERY_URL = 'http://localhost:9980/hosting/discovery';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDF_COMMAND
|
||||||
|
* Commande qui sera exécutée pour créer un fichier PDF à partir d'un HTML.
|
||||||
|
*
|
||||||
|
* Si laissé sur 'auto', Paheko essaiera de détecter une solution entre
|
||||||
|
* PrinceXML, Chromium, wkhtmltopdf ou weasyprint (dans cet ordre).
|
||||||
|
* Si aucune solution n'est disponible, une erreur sera affichée.
|
||||||
|
*
|
||||||
|
* Il est possible d'indiquer NULL pour désactiver l'export en PDF.
|
||||||
|
*
|
||||||
|
* Il est possible d'indiquer uniquement le nom du programme :
|
||||||
|
* 'chromium', 'prince', 'weasyprint', ou 'wkhtmltopdf'.
|
||||||
|
* Dans ce cas, Paheko utilisera les paramètres par défaut de ce programme.
|
||||||
|
*
|
||||||
|
* Alternativement, il est possible d'indiquer la commande complète avec
|
||||||
|
* les options, par exemple '/usr/bin/chromium --headless --print-to-pdf=%2$s %1$s'
|
||||||
|
* Dans ce cas :
|
||||||
|
* - %1$s sera remplacé par le chemin du fichier HTML existant,
|
||||||
|
* - %2$s sera remplacé par le chemin du fichier PDF à créer.
|
||||||
|
*
|
||||||
|
* Si vous utilisez une extension pour générer les PDF (comme DomPDF), alors
|
||||||
|
* laisser cette constante sur 'auto'.
|
||||||
|
*
|
||||||
|
* Exemples :
|
||||||
|
* 'weasyprint'
|
||||||
|
* 'wkhtmltopdf -q --print-media-type --enable-local-file-access %s %s'
|
||||||
|
*
|
||||||
|
* Si vous utilisez Prince, un message mentionnant l'utilisation de Prince
|
||||||
|
* sera joint aux e-mails utilisant des fichiers PDF, conformément à la licence :
|
||||||
|
* https://www.princexml.com/purchase/license_faq/#non-commercial
|
||||||
|
*
|
||||||
|
* Défaut : 'auto'
|
||||||
|
* @var null|string
|
||||||
|
*/
|
||||||
|
//const PDF_COMMAND = 'auto';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDF_USAGE_LOG
|
||||||
|
* Chemin vers le fichier où enregistrer la date de chaque export en PDF
|
||||||
|
*
|
||||||
|
* Ceci est utilisé notamment pour estimer le prix de la licence PrinceXML.
|
||||||
|
*
|
||||||
|
* Défaut : NULL
|
||||||
|
* @var null|string
|
||||||
|
*/
|
||||||
|
//const PDF_USAGE_LOG = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CALC_CONVERT_COMMAND
|
||||||
|
* Outil de conversion de formats de tableur vers un format propriétaire
|
||||||
|
*
|
||||||
|
* Paheko gère nativement les exports en ODS (OpenDocument : LibreOffice)
|
||||||
|
* et CSV, et imports en CSV.
|
||||||
|
*
|
||||||
|
* En indiquant ici le nom d'un outil, Paheko autorisera aussi
|
||||||
|
* l'import en XLSX, XLS et ODS, et l'export en XLSX.
|
||||||
|
*
|
||||||
|
* Pour cela il procédera simplement à une conversion entre les formats natifs
|
||||||
|
* ODS/CSV et XLSX ou XLS.
|
||||||
|
*
|
||||||
|
* Note : installer ces commandes peut introduire des risques de sécurité sur le serveur.
|
||||||
|
*
|
||||||
|
* Les outils supportés sont :
|
||||||
|
* - ssconvert (apt install gnumeric) (plus rapide)
|
||||||
|
* - unoconv (apt install unoconv) (utilise LibreOffice)
|
||||||
|
* - unoconvert (https://github.com/unoconv/unoserver/) en spécifiant l'interface
|
||||||
|
*
|
||||||
|
* Défault : null (= fonctionnalité désactivée)
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
//const CALC_CONVERT_COMMAND = 'unoconv';
|
||||||
|
//const CALC_CONVERT_COMMAND = 'ssconvert';
|
||||||
|
//const CALC_CONVERT_COMMAND = 'unoconvert --interface localhost --port 2022';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOCUMENT_THUMBNAIL_COMMANDS
|
||||||
|
* Indique les commandes à utiliser pour générer des miniatures pour les documents
|
||||||
|
* (LibreOffice, OOXML, PDF, SVG, vidéos, etc.)
|
||||||
|
*
|
||||||
|
* Les options possibles sont (par ordre de rapidité) :
|
||||||
|
* - mupdf : les miniatures PDF/SVG/XPS/EPUB sont générées avec mutool
|
||||||
|
* (apt install mupdf-tools)
|
||||||
|
* - collabora : les miniatures de documents bureautiques sont générées
|
||||||
|
* par le serveur Collabora, via l'API dont l'URL est indiquée dans WOPI_DISCOVERY_URL
|
||||||
|
* - unoconvert : les miniatures des documents Office/LO sont générées
|
||||||
|
* avec unoconvert <https://github.com/unoconv/unoserver/>
|
||||||
|
* - ffmpeg : les miniatures de vidéos seront générées avec ffmpeg
|
||||||
|
*
|
||||||
|
* Bien que Collabora/Unoconvert puissent générer des miniatures de PDF, il est plutôt
|
||||||
|
* conseillé d'utiliser mupdf quand même, il est plus rapide et léger.
|
||||||
|
*
|
||||||
|
* Note : cette option créera de nombreux fichiers de cache, et risque d'augmenter
|
||||||
|
* la charge serveur de manière importante.
|
||||||
|
*
|
||||||
|
* Défaut : null (fonctionnalité désactivée)
|
||||||
|
* @var null|array
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const DOCUMENT_THUMBNAIL_COMMANDS = ['mupdf', 'collabora', 'ffmpeg'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDFTOTEXT_COMMAND
|
||||||
|
* Outil de conversion de PDF au format texte.
|
||||||
|
*
|
||||||
|
* Utilisé pour indexer un fichier PDF pour pouvoir rechercher dans son contenu
|
||||||
|
* parmi les documents.
|
||||||
|
*
|
||||||
|
* Il est possible de spécifier ici la commande suivante :
|
||||||
|
* - mupdf (apt install mupdf-tools)
|
||||||
|
*
|
||||||
|
* Toute autre commande sera ignorée.
|
||||||
|
*
|
||||||
|
* Défaut : null (= fonctionnalité désactivée)
|
||||||
|
*/
|
||||||
|
//const PDFTOTEXT_COMMAND = 'mupdf';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API_USER et API_PASSWORD
|
||||||
|
* Login et mot de passe système de l'API
|
||||||
|
*
|
||||||
|
* Une API est disponible via l'URL https://login:password@paheko.association.tld/api/...
|
||||||
|
* Voir https://fossil.kd2.org/paheko/wiki?name=API pour la documentation
|
||||||
|
*
|
||||||
|
* Ces deux constantes permettent d'indiquer un nom d'utilisateur
|
||||||
|
* et un mot de passe pour accès à l'API.
|
||||||
|
*
|
||||||
|
* Cet utilisateur est distinct de ceux définis dans la page de gestion des
|
||||||
|
* identifiants d'accès à l'API, et aura accès à TOUT en écriture/administration.
|
||||||
|
*
|
||||||
|
* Défaut: null
|
||||||
|
*/
|
||||||
|
//const API_USER = 'coraline';
|
||||||
|
//const API_PASSWORD = 'thisIsASecretPassword42';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DISABLE_INSTALL_PING
|
||||||
|
*
|
||||||
|
* Lors de l'installation, ou d'une mise à jour, la version installée de Paheko,
|
||||||
|
* ainsi que celle de PHP et de SQLite, sont envoyées à Paheko.cloud.
|
||||||
|
*
|
||||||
|
* Cela permet de savoir quelles sont les versions utilisées, et également de compter
|
||||||
|
* le nombre d'installations effectuées.
|
||||||
|
*
|
||||||
|
* Aucune donnée personnelle n'est envoyée. Un identifiant anonyme est envoyé,
|
||||||
|
* permettant d'identifier l'installation et éviter les doublons.
|
||||||
|
* (voir le code dans lib/.../Install.php)
|
||||||
|
*
|
||||||
|
* Le code de stockage des statistiques est visible à :
|
||||||
|
* https://paheko.cloud/ping/
|
||||||
|
*
|
||||||
|
* Pour désactiver cet envoi il suffit de placer cette constante à TRUE.
|
||||||
|
*
|
||||||
|
* Défaut : false
|
||||||
|
*/
|
||||||
|
//const DISABLE_INSTALL_PING = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Informations légale sur l'hébergeur
|
||||||
|
*
|
||||||
|
* Ce texte (HTML) est affiché en bas de la page "mentions légales"
|
||||||
|
* (.../admin/legal.php)
|
||||||
|
*
|
||||||
|
* S'il est omis, l'association sera indiquée comme étant auto-hébergée.
|
||||||
|
*
|
||||||
|
* Défaut : null
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
//const LEGAL_HOSTING_DETAILS = 'OVH<br />5 rue de l'hébergement<br />ROUBAIX';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message d'avertissement
|
||||||
|
*
|
||||||
|
* Sera affiché en haut de toutes les pages de l'administration.
|
||||||
|
*
|
||||||
|
* Code HTML autorisé.
|
||||||
|
* Utiliser NULL pour désactiver le message.
|
||||||
|
*
|
||||||
|
* Défaut : null
|
||||||
|
*
|
||||||
|
* @var null|string
|
||||||
|
*/
|
||||||
|
//const ALERT_MESSAGE = 'Ceci est un compte de test.';
|
9
src/config.local.php
Normal file
9
src/config.local.php
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
namespace Paheko;
|
||||||
|
|
||||||
|
const SECRET_KEY = 'N7Ve3u8OcAtXuM3bF7tF3JX1uDFZAwcR7cmLm9hTV5RWPjcSdSUJh/zRuVOxnTKoaex+bMnmCm+bxAnLjZsYSw==';
|
||||||
|
|
||||||
|
// use mailcatcher
|
||||||
|
const SMTP_HOST = "localhost";
|
||||||
|
const SMTP_PORT = 1025;
|
||||||
|
const SMTP_SECURITY = "NONE";
|
435
src/include/data/1.1.0_schema.sql
Normal file
435
src/include/data/1.1.0_schema.sql
Normal file
|
@ -0,0 +1,435 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS config (
|
||||||
|
key TEXT PRIMARY KEY NOT NULL,
|
||||||
|
value TEXT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS users_categories
|
||||||
|
-- Users categories, mainly used to manage rights
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
|
||||||
|
-- Permissions, 0 = no access, 1 = read-only, 2 = read-write, 9 = admin
|
||||||
|
perm_web INTEGER NOT NULL DEFAULT 1,
|
||||||
|
perm_documents INTEGER NOT NULL DEFAULT 1,
|
||||||
|
perm_users INTEGER NOT NULL DEFAULT 1,
|
||||||
|
perm_accounting INTEGER NOT NULL DEFAULT 1,
|
||||||
|
|
||||||
|
perm_subscribe INTEGER NOT NULL DEFAULT 0,
|
||||||
|
perm_connect INTEGER NOT NULL DEFAULT 1,
|
||||||
|
perm_config INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
hidden INTEGER NOT NULL DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS users_categories_hidden ON users_categories (hidden);
|
||||||
|
|
||||||
|
-- Membres de l'asso
|
||||||
|
-- Table dynamique générée par l'application
|
||||||
|
-- voir Garradin\Membres\Champs.php
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS membres_sessions
|
||||||
|
-- Sessions
|
||||||
|
(
|
||||||
|
selecteur TEXT NOT NULL,
|
||||||
|
hash TEXT NOT NULL,
|
||||||
|
id_membre INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
expire INT NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (selecteur, id_membre)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS services
|
||||||
|
-- Types de services (cotisations)
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
|
||||||
|
duration INTEGER NULL CHECK (duration IS NULL OR duration > 0), -- En jours
|
||||||
|
start_date TEXT NULL CHECK (start_date IS NULL OR date(start_date) = start_date),
|
||||||
|
end_date TEXT NULL CHECK (end_date IS NULL OR (date(end_date) = end_date AND date(end_date) >= date(start_date)))
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS services_fees
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
|
||||||
|
amount INTEGER NULL,
|
||||||
|
formula TEXT NULL, -- Formule de calcul du montant de la cotisation, si cotisation dynamique (exemple : membres.revenu_imposable * 0.01)
|
||||||
|
|
||||||
|
id_service INTEGER NOT NULL REFERENCES services (id) ON DELETE CASCADE,
|
||||||
|
id_account INTEGER NULL REFERENCES acc_accounts (id) ON DELETE SET NULL CHECK (id_account IS NULL OR id_year IS NOT NULL), -- NULL if fee is not linked to accounting, this is reset using a trigger if the year is deleted
|
||||||
|
id_year INTEGER NULL REFERENCES acc_years (id) ON DELETE SET NULL, -- NULL if fee is not linked to accounting
|
||||||
|
id_analytical INTEGER NULL REFERENCES acc_accounts (id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS services_users
|
||||||
|
-- Enregistrement des cotisations et activités
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_user INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_service INTEGER NOT NULL REFERENCES services (id) ON DELETE CASCADE,
|
||||||
|
id_fee INTEGER NULL REFERENCES services_fees (id) ON DELETE CASCADE, -- This can be NULL if there is no fee for the service
|
||||||
|
|
||||||
|
paid INTEGER NOT NULL DEFAULT 0,
|
||||||
|
expected_amount INTEGER NULL,
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date),
|
||||||
|
expiry_date TEXT NULL CHECK (date(expiry_date) IS NULL OR date(expiry_date) = expiry_date)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS su_unique ON services_users (id_user, id_service, date);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS su_service ON services_users (id_service);
|
||||||
|
CREATE INDEX IF NOT EXISTS su_fee ON services_users (id_fee);
|
||||||
|
CREATE INDEX IF NOT EXISTS su_paid ON services_users (paid);
|
||||||
|
CREATE INDEX IF NOT EXISTS su_expiry ON services_users (expiry_date);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS services_reminders
|
||||||
|
-- Rappels de devoir renouveller une cotisation
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_service INTEGER NOT NULL REFERENCES services (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
delay INTEGER NOT NULL, -- Délai en jours pour envoyer le rappel
|
||||||
|
|
||||||
|
subject TEXT NOT NULL,
|
||||||
|
body TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS services_reminders_sent
|
||||||
|
-- Enregistrement des rappels envoyés à qui et quand
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
id_user INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_service INTEGER NOT NULL REFERENCES services (id) ON DELETE CASCADE,
|
||||||
|
id_reminder INTEGER NOT NULL REFERENCES services_reminders (id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
sent_date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(sent_date) IS NOT NULL AND date(sent_date) = sent_date),
|
||||||
|
due_date TEXT NOT NULL CHECK (date(due_date) IS NOT NULL AND date(due_date) = due_date)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS srs_index ON services_reminders_sent (id_user, id_service, id_reminder, due_date);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS srs_reminder ON services_reminders_sent (id_reminder);
|
||||||
|
CREATE INDEX IF NOT EXISTS srs_user ON services_reminders_sent (id_user);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- COMPTA
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS acc_charts
|
||||||
|
-- Plans comptables : il peut y en avoir plusieurs
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
country TEXT NOT NULL,
|
||||||
|
code TEXT NULL, -- NULL = plan comptable créé par l'utilisateur
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
archived INTEGER NOT NULL DEFAULT 0 -- 1 = archivé, non-modifiable
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS acc_accounts
|
||||||
|
-- Comptes des plans comptables
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_chart INTEGER NOT NULL REFERENCES acc_charts ON DELETE CASCADE,
|
||||||
|
|
||||||
|
code TEXT NOT NULL, -- peut contenir des lettres, eg. 53A, 53B, etc.
|
||||||
|
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
|
||||||
|
position INTEGER NOT NULL, -- position actif/passif/charge/produit
|
||||||
|
type INTEGER NOT NULL DEFAULT 0, -- Type de compte spécial : banque, caisse, en attente d'encaissement, etc.
|
||||||
|
user INTEGER NOT NULL DEFAULT 1 -- 0 = fait partie du plan comptable original, 1 = a été ajouté par l'utilisateur
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS acc_accounts_codes ON acc_accounts (code, id_chart);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_accounts_type ON acc_accounts (type);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_accounts_position ON acc_accounts (position);
|
||||||
|
|
||||||
|
-- Balance des comptes par exercice
|
||||||
|
CREATE VIEW IF NOT EXISTS acc_accounts_balances
|
||||||
|
AS
|
||||||
|
SELECT id_year, id, label, code, type, debit, credit,
|
||||||
|
CASE -- 3 = dynamic asset or liability depending on balance
|
||||||
|
WHEN position = 3 AND (debit - credit) > 0 THEN 1 -- 1 = Asset (actif) comptes fournisseurs, tiers créditeurs
|
||||||
|
WHEN position = 3 THEN 2 -- 2 = Liability (passif), comptes clients, tiers débiteurs
|
||||||
|
ELSE position
|
||||||
|
END AS position,
|
||||||
|
CASE
|
||||||
|
WHEN position IN (1, 4) -- 1 = asset, 4 = expense
|
||||||
|
OR (position = 3 AND (debit - credit) > 0)
|
||||||
|
THEN
|
||||||
|
debit - credit
|
||||||
|
ELSE
|
||||||
|
credit - debit
|
||||||
|
END AS balance,
|
||||||
|
CASE WHEN debit - credit > 0 THEN 1 ELSE 0 END AS is_debt
|
||||||
|
FROM (
|
||||||
|
SELECT t.id_year, a.id, a.label, a.code, a.position, a.type,
|
||||||
|
SUM(l.credit) AS credit,
|
||||||
|
SUM(l.debit) AS debit
|
||||||
|
FROM acc_accounts a
|
||||||
|
INNER JOIN acc_transactions_lines l ON l.id_account = a.id
|
||||||
|
INNER JOIN acc_transactions t ON t.id = l.id_transaction
|
||||||
|
GROUP BY t.id_year, a.id
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS acc_years
|
||||||
|
-- Exercices
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
|
||||||
|
start_date TEXT NOT NULL CHECK (date(start_date) IS NOT NULL AND date(start_date) = start_date),
|
||||||
|
end_date TEXT NOT NULL CHECK (date(end_date) IS NOT NULL AND date(end_date) = end_date),
|
||||||
|
|
||||||
|
closed INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
id_chart INTEGER NOT NULL REFERENCES acc_charts (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_years_closed ON acc_years (closed);
|
||||||
|
|
||||||
|
-- Make sure id_account is reset when a year is deleted
|
||||||
|
CREATE TRIGGER IF NOT EXISTS acc_years_delete BEFORE DELETE ON acc_years BEGIN
|
||||||
|
UPDATE services_fees SET id_account = NULL, id_year = NULL WHERE id_year = OLD.id;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS acc_transactions
|
||||||
|
-- Opérations comptables
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
type INTEGER NOT NULL DEFAULT 0, -- Type d'écriture, 0 = avancée (normale)
|
||||||
|
status INTEGER NOT NULL DEFAULT 0, -- Statut (bitmask)
|
||||||
|
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
notes TEXT NULL,
|
||||||
|
reference TEXT NULL, -- N° de pièce comptable
|
||||||
|
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date) IS NOT NULL AND date(date) = date),
|
||||||
|
|
||||||
|
validated INTEGER NOT NULL DEFAULT 0, -- 1 = écriture validée, non modifiable
|
||||||
|
|
||||||
|
hash TEXT NULL,
|
||||||
|
prev_hash TEXT NULL,
|
||||||
|
|
||||||
|
id_year INTEGER NOT NULL REFERENCES acc_years(id),
|
||||||
|
id_creator INTEGER NULL REFERENCES membres(id) ON DELETE SET NULL,
|
||||||
|
id_related INTEGER NULL REFERENCES acc_transactions(id) ON DELETE SET NULL -- écriture liée (par ex. remboursement d'une dette)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_year ON acc_transactions (id_year);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_date ON acc_transactions (date);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_related ON acc_transactions (id_related);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_type ON acc_transactions (type, id_year);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_status ON acc_transactions (status);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS acc_transactions_lines
|
||||||
|
-- Lignes d'écritures d'une opération
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
|
||||||
|
id_transaction INTEGER NOT NULL REFERENCES acc_transactions (id) ON DELETE CASCADE,
|
||||||
|
id_account INTEGER NOT NULL REFERENCES acc_accounts (id), -- N° du compte dans le plan comptable
|
||||||
|
|
||||||
|
credit INTEGER NOT NULL,
|
||||||
|
debit INTEGER NOT NULL,
|
||||||
|
|
||||||
|
reference TEXT NULL, -- Référence de paiement, eg. numéro de chèque
|
||||||
|
label TEXT NULL,
|
||||||
|
|
||||||
|
reconciled INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
id_analytical INTEGER NULL REFERENCES acc_accounts(id) ON DELETE SET NULL,
|
||||||
|
|
||||||
|
CONSTRAINT line_check1 CHECK ((credit * debit) = 0),
|
||||||
|
CONSTRAINT line_check2 CHECK ((credit + debit) > 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_lines_transaction ON acc_transactions_lines (id_transaction);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_lines_account ON acc_transactions_lines (id_account);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_lines_analytical ON acc_transactions_lines (id_analytical);
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_lines_reconciled ON acc_transactions_lines (reconciled);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS acc_transactions_users
|
||||||
|
-- Liaison des écritures et des membres
|
||||||
|
(
|
||||||
|
id_user INTEGER NOT NULL REFERENCES membres (id) ON DELETE CASCADE,
|
||||||
|
id_transaction INTEGER NOT NULL REFERENCES acc_transactions (id) ON DELETE CASCADE,
|
||||||
|
id_service_user INTEGER NULL REFERENCES services_users (id) ON DELETE SET NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (id_user, id_transaction)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS acc_transactions_users_service ON acc_transactions_users (id_service_user);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS plugins
|
||||||
|
(
|
||||||
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
|
officiel INTEGER NOT NULL DEFAULT 0,
|
||||||
|
nom TEXT NOT NULL,
|
||||||
|
description TEXT NULL,
|
||||||
|
auteur TEXT NULL,
|
||||||
|
url TEXT NULL,
|
||||||
|
version TEXT NOT NULL,
|
||||||
|
menu INTEGER NOT NULL DEFAULT 0,
|
||||||
|
menu_condition TEXT NULL,
|
||||||
|
config TEXT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS plugins_signaux
|
||||||
|
-- Association entre plugins et signaux (hooks)
|
||||||
|
(
|
||||||
|
signal TEXT NOT NULL,
|
||||||
|
plugin TEXT NOT NULL REFERENCES plugins (id),
|
||||||
|
callback TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (signal, plugin)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS api_credentials
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
label TEXT NOT NULL,
|
||||||
|
key TEXT NOT NULL,
|
||||||
|
secret TEXT NOT NULL,
|
||||||
|
created TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
last_use TEXT NULL,
|
||||||
|
access_level INT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS api_credentials_key ON api_credentials (key);
|
||||||
|
|
||||||
|
---------- FILES ----------------
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS files
|
||||||
|
-- Files metadata
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
path TEXT NOT NULL,
|
||||||
|
parent TEXT NOT NULL,
|
||||||
|
name TEXT NOT NULL, -- File name
|
||||||
|
type INTEGER NOT NULL, -- File type, 1 = file, 2 = directory
|
||||||
|
mime TEXT NULL,
|
||||||
|
size INT NULL,
|
||||||
|
modified TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(modified) = modified),
|
||||||
|
image INT NOT NULL DEFAULT 0,
|
||||||
|
|
||||||
|
CHECK (type = 2 OR (mime IS NOT NULL AND size IS NOT NULL))
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Unique index as this is used to make up a file path
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS files_unique ON files (path);
|
||||||
|
CREATE INDEX IF NOT EXISTS files_parent ON files (parent);
|
||||||
|
CREATE INDEX IF NOT EXISTS files_name ON files (name);
|
||||||
|
CREATE INDEX IF NOT EXISTS files_modified ON files (modified);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS files_contents
|
||||||
|
-- Files contents (empty if using another storage backend)
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY REFERENCES files(id) ON DELETE CASCADE,
|
||||||
|
compressed INT NOT NULL DEFAULT 0,
|
||||||
|
content BLOB NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE VIRTUAL TABLE IF NOT EXISTS files_search USING fts4
|
||||||
|
-- Search inside files content
|
||||||
|
(
|
||||||
|
tokenize=unicode61, -- Available from SQLITE 3.7.13 (2012)
|
||||||
|
path TEXT NOT NULL,
|
||||||
|
title TEXT NULL,
|
||||||
|
content TEXT NOT NULL, -- Text content
|
||||||
|
notindexed=path
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS web_pages
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
parent TEXT NOT NULL, -- Parent path, empty = web root
|
||||||
|
path TEXT NOT NULL, -- Full page directory name
|
||||||
|
uri TEXT NOT NULL, -- Page identifier
|
||||||
|
file_path TEXT NOT NULL, -- Full file path for contents
|
||||||
|
type INTEGER NOT NULL, -- 1 = Category, 2 = Page
|
||||||
|
status TEXT NOT NULL,
|
||||||
|
format TEXT NOT NULL,
|
||||||
|
published TEXT NOT NULL CHECK (datetime(published) = published),
|
||||||
|
modified TEXT NOT NULL CHECK (datetime(modified) = modified),
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
content TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS web_pages_path ON web_pages (path);
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS web_pages_uri ON web_pages (uri);
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS web_pages_file_path ON web_pages (file_path);
|
||||||
|
CREATE INDEX IF NOT EXISTS web_pages_parent ON web_pages (parent);
|
||||||
|
CREATE INDEX IF NOT EXISTS web_pages_published ON web_pages (published);
|
||||||
|
CREATE INDEX IF NOT EXISTS web_pages_title ON web_pages (title);
|
||||||
|
|
||||||
|
-- FIXME: rename to english
|
||||||
|
CREATE TABLE IF NOT EXISTS recherches
|
||||||
|
-- Recherches enregistrées
|
||||||
|
(
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
id_membre INTEGER NULL REFERENCES membres (id) ON DELETE CASCADE, -- Si non NULL, alors la recherche ne sera visible que par le membre associé
|
||||||
|
intitule TEXT NOT NULL,
|
||||||
|
creation TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(creation) IS NOT NULL AND datetime(creation) = creation),
|
||||||
|
cible TEXT NOT NULL, -- "membres" ou "compta"
|
||||||
|
type TEXT NOT NULL, -- "json" ou "sql"
|
||||||
|
contenu TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compromised_passwords_cache
|
||||||
|
-- Cache des hash de mots de passe compromis
|
||||||
|
(
|
||||||
|
hash TEXT NOT NULL PRIMARY KEY
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS compromised_passwords_cache_ranges
|
||||||
|
-- Cache des préfixes de mots de passe compromis
|
||||||
|
(
|
||||||
|
prefix TEXT NOT NULL PRIMARY KEY,
|
||||||
|
date INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS emails (
|
||||||
|
-- List of emails addresses
|
||||||
|
-- We are not storing actual email addresses here for privacy reasons
|
||||||
|
-- So that we can keep the record (for opt-out reasons) even when the
|
||||||
|
-- email address has been removed from the users table
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
hash TEXT NOT NULL,
|
||||||
|
verified INTEGER NOT NULL DEFAULT 0,
|
||||||
|
optout INTEGER NOT NULL DEFAULT 0,
|
||||||
|
invalid INTEGER NOT NULL DEFAULT 0,
|
||||||
|
fail_count INTEGER NOT NULL DEFAULT 0,
|
||||||
|
sent_count INTEGER NOT NULL DEFAULT 0,
|
||||||
|
fail_log TEXT NULL,
|
||||||
|
last_sent TEXT NULL,
|
||||||
|
added TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS emails_hash ON emails (hash);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS emails_queue (
|
||||||
|
-- List of emails waiting to be sent
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
sender TEXT NULL,
|
||||||
|
recipient TEXT NOT NULL,
|
||||||
|
recipient_hash TEXT NOT NULL,
|
||||||
|
subject TEXT NOT NULL,
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
content_html TEXT NULL,
|
||||||
|
sending INTEGER NOT NULL DEFAULT 0, -- Will be changed to 1 when the queue run will start
|
||||||
|
sending_started TEXT NULL, -- Will be filled with the datetime when the email sending was started
|
||||||
|
context INTEGER NOT NULL
|
||||||
|
);
|
4
src/include/data/1.1.21_migration.sql
Normal file
4
src/include/data/1.1.21_migration.sql
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
ALTER TABLE services_fees ADD COLUMN id_analytical INTEGER NULL REFERENCES acc_accounts (id) ON DELETE SET NULL;
|
||||||
|
|
||||||
|
UPDATE acc_charts SET code = 'PCA_2018' WHERE code = 'PCA2018';
|
||||||
|
UPDATE acc_charts SET code = 'PCA_1999' WHERE code = 'PCA1999';
|
3
src/include/data/1.1.25_migration.sql
Normal file
3
src/include/data/1.1.25_migration.sql
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
UPDATE plugins_signaux SET signal = 'home.banner' WHERE signal = 'accueil.banniere';
|
||||||
|
UPDATE plugins_signaux SET signal = 'reminder.send.after' WHERE signal = 'rappels.auto';
|
||||||
|
UPDATE plugins_signaux SET signal = 'email.send.before' WHERE signal = 'email.envoi';
|
23
src/include/data/1.1.29_migration.sql
Normal file
23
src/include/data/1.1.29_migration.sql
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
CREATE TEMP TABLE tmp_new_accounts (id_chart, code, label, position);
|
||||||
|
|
||||||
|
-- Add missing accounts
|
||||||
|
INSERT INTO tmp_new_accounts (code, label, position) VALUES
|
||||||
|
('438', 'Organismes sociaux - Charges à payer et produits à recevoir', 2),
|
||||||
|
('4382', 'Charges sociales sur congés à payer', 2),
|
||||||
|
('4386', 'Autres charges à payer', 2),
|
||||||
|
('4387', 'Produits à recevoir', 2);
|
||||||
|
|
||||||
|
UPDATE tmp_new_accounts SET id_chart = (SELECT id FROM acc_charts WHERE code = 'PCA_2018');
|
||||||
|
|
||||||
|
INSERT OR IGNORE INTO acc_accounts (id_chart, code, label, position, user) SELECT *, 0 FROM tmp_new_accounts WHERE id_chart IS NOT NULL;
|
||||||
|
|
||||||
|
DROP TABLE tmp_new_accounts;
|
||||||
|
|
||||||
|
CREATE TEMP TABLE IF NOT EXISTS su_fix_fee (id);
|
||||||
|
|
||||||
|
INSERT INTO su_fix_fee
|
||||||
|
SELECT su.id FROM services_users su LEFT JOIN services_fees sf ON sf.id = su.id_fee AND sf.id_service = sf.id_service
|
||||||
|
WHERE sf.id IS NULL AND su.id_fee IS NOT NULL;
|
||||||
|
|
||||||
|
-- Remove id_fee from subscriptions where it belongs to another service
|
||||||
|
UPDATE services_users SET id_fee = NULL WHERE id IN (SELECT id FROM su_fix_fee);
|
445
src/include/data/charts/be_pcmn_2019.csv
Normal file
445
src/include/data/charts/be_pcmn_2019.csv
Normal file
|
@ -0,0 +1,445 @@
|
||||||
|
code,label,description,position,bookmark
|
||||||
|
1,"FONDS SOCIAL, PROVISIONS POUR RISQUES ET CHARGE ET DETTES À PLUS D’UN AN",,Passif,
|
||||||
|
10,Fonds de l’association ou de la fondation,,Passif,
|
||||||
|
12,Plus-values de réévaluation,,Passif,
|
||||||
|
120,Plus-values de réévaluation sur immobilisations incorporelles,,Passif,
|
||||||
|
121,Plus-values de réévaluation sur immobilisations corporelles,,Passif,
|
||||||
|
122,Plus-values de réévaluation sur immobilisations financières,,Passif,
|
||||||
|
124,Reprises de réductions de valeurs sur placements de trésorerie,,Passif,
|
||||||
|
13,Fonds affectés et autres réserves,,Passif,
|
||||||
|
130,Fonds affectés pour investissements,,Passif,
|
||||||
|
131,Fonds affectés pour passif social,,Passif,
|
||||||
|
132,Réserves immunisés,,Passif,
|
||||||
|
139,Autres fonds affectés et autres réserves,,Passif,
|
||||||
|
14,Résultats reportés (+)(-),Bénéfice ou déficit,Actif ou passif,
|
||||||
|
15,Subsides en capital,,Passif,
|
||||||
|
16,Provisions et impôts différés,,Passif,
|
||||||
|
160,Provisions pour pensions et obligations similaires,,Passif,
|
||||||
|
161,Provisions pour charge fiscales,,Passif,
|
||||||
|
162,Provisions pour grosses réparations et gros entretiens,,Passif,
|
||||||
|
163,Provisions pour obligations environnementales,,Passif,
|
||||||
|
164,Provisions pour autres risques et charge,,Passif,
|
||||||
|
167,"Provisions pour remboursement de subsides, legs et dons avec droit de reprise",,Passif,
|
||||||
|
168,Impôts différés,,Passif,
|
||||||
|
17,Dettes à plus d'un an,,Passif,
|
||||||
|
170,Emprunts subordonnés,,Passif,
|
||||||
|
171,Emprunts obligataires non subordonnés,,Passif,
|
||||||
|
172,Dettes de location-financement et dettes assimilées,,Passif,
|
||||||
|
173,Établissements de crédit,,Passif,
|
||||||
|
1730,Dettes en comptes,,Passif,
|
||||||
|
1731,Promesses,,Passif,
|
||||||
|
1732,Crédits d'acceptation,,Passif,
|
||||||
|
174,Autres emprunts,,Passif,
|
||||||
|
175,Dettes commerciales,,Passif,
|
||||||
|
1750,Fournisseurs,,Passif,
|
||||||
|
1751,Effets à payer,,Passif,
|
||||||
|
176,Acomptes sur commandes,,Passif,
|
||||||
|
178,Cautionnements en numéraire,,Passif,
|
||||||
|
179,Autres dettes,,Passif,
|
||||||
|
1790,Productives d’intérêts,,Passif,
|
||||||
|
1791,Non productives d’intérêts ou assorties d’un intérêt anormalement faible,,Passif,
|
||||||
|
2,"FRAIS D’ÉTABLISSEMENT, ACTIFS IMMOBILISÉS ET CRÉANCES À PLUS D’UN AN",,Actif,
|
||||||
|
20,Frais d'établissement,,Actif,
|
||||||
|
200,Frais de constitution,,Actif,
|
||||||
|
201,Frais d'émission d'emprunt,,Actif,
|
||||||
|
202,Autres frais d'établissement,,Actif,
|
||||||
|
204,Frais de restructuration,,Actif,
|
||||||
|
21,Immobilisations incorporelles,Actifs immobilisés,Actif,
|
||||||
|
210,Frais de recherche et de développement,,Actif,
|
||||||
|
211,"Concessions, brevets, licences, savoir-faire, marques et droits similaires",,Actif,
|
||||||
|
212,Goodwill,,Actif,
|
||||||
|
213,Acomptes versés,,Actif,
|
||||||
|
22,Terrains et constructions,,Actif,
|
||||||
|
220,Terrains,,Actif,
|
||||||
|
221,Constructions,,Actif,
|
||||||
|
222,Terrains bâtis,,Actif,
|
||||||
|
223,Autres droits réels sur des immeubles,,Actif,
|
||||||
|
23,"Installations, machines et outillage ",,Actif,
|
||||||
|
24,Mobilier et matériel roulant,,Actif,
|
||||||
|
25,Immobilisations détenues en location-financement et droits similaires,,Actif,
|
||||||
|
250,Terrains et construction,,Actif,
|
||||||
|
251,"Installations, machines et outillage",,Actif,
|
||||||
|
252,Mobilier et matériel roulant,,Actif,
|
||||||
|
26,Autres immobilisations corporelles,,Actif,
|
||||||
|
27,Immobilisations corporelles en cours et acomptes versés,,Actif,
|
||||||
|
28,Immobilisations financières,,Actif,
|
||||||
|
280,Participations dans des sociétés liées,,Actif,
|
||||||
|
2800,Valeur d'acquisition,,Actif,
|
||||||
|
2801,Montants non appelés,,Actif,
|
||||||
|
2808,Plus-values actées,,Actif,
|
||||||
|
2809,Réductions de valeur actées,,Actif,
|
||||||
|
281,Créances sur des entités liées,,Actif,
|
||||||
|
2810,Créances en compte,,Actif,
|
||||||
|
2811,Effets à recevoir,,Actif,
|
||||||
|
2812,Titres à revenu fixe,,Actif,
|
||||||
|
2817,Créances douteuses,,Actif,
|
||||||
|
2819,Réductions de valeurs actées,,Actif,
|
||||||
|
282,Participations dans des sociétés avec lesquelles il existe un lien de participation,,Actif,
|
||||||
|
2820,Valeur d'acquisition,,Actif,
|
||||||
|
2821,Montants non appelés,,Actif,
|
||||||
|
2828,Plus-values actées,,Actif,
|
||||||
|
2829,Réductions de valeurs actées,,Actif,
|
||||||
|
283,Créances sur des sociétés avec lesquelles il existe un lien de participation,,Actif,
|
||||||
|
2830,Créances en compte,,Actif,
|
||||||
|
2831,Effets à recevoir,,Actif,
|
||||||
|
2832,Titres à revenu fixe,,Actif,
|
||||||
|
2837,Créances douteuses,,Actif,
|
||||||
|
2839,Réductions de valeurs actées,,Actif,
|
||||||
|
284,Autres actions et parts,,Actif,
|
||||||
|
2840,Valeur d'acquisition,,Actif,
|
||||||
|
2841,Montants non appelés,,Actif,
|
||||||
|
2848,Plus-values actées,,Actif,
|
||||||
|
2849,Réductions de valeurs actées,,Actif,
|
||||||
|
285,Autres créances,,Actif,
|
||||||
|
2850,Créances en compte,,Actif,
|
||||||
|
2851,Effets à recevoir,,Actif,
|
||||||
|
2852,Titres à revenu fixe,,Actif,
|
||||||
|
2857,Créances douteuses,,Actif,
|
||||||
|
2859,Réductions de valeurs actées,,Actif,
|
||||||
|
288,Cautionnements versés en numéraire,,Actif,
|
||||||
|
29,Créances à plus d'un an,,Actif,
|
||||||
|
290,Créances commerciales,,Actif,
|
||||||
|
2900,Clients,,Actif,
|
||||||
|
2901,Effets à recevoir,,Actif,
|
||||||
|
2906,Acomptes versés,,Actif,
|
||||||
|
2907,Créances douteuses,,Actif,
|
||||||
|
2909,Réductions de valeurs actées,,Actif,
|
||||||
|
291,Autres créances,,Actif,
|
||||||
|
2910,Créances en compte,,Actif,
|
||||||
|
2911,Effets à recevoir,,Actif,
|
||||||
|
2912,Subsides à recevoir,,Actif,
|
||||||
|
2915,Créances non productives d’intérêts ou assorties d’un intérêt anormalement faible,,Actif,
|
||||||
|
2916,Créances douteuses,,Actif,
|
||||||
|
2919,Réductions de valeurs actées,,Actif,
|
||||||
|
3,STOCKS ET COMMANDES EN COURS D'EXÉCUTION,,Actif,
|
||||||
|
30,Matières premières,,Actif,
|
||||||
|
300,Valeur d'acquisition,,Actif,
|
||||||
|
309,Réductions de valeur actées,,Actif,
|
||||||
|
31,Fournitures,,Actif,
|
||||||
|
310,Valeur d'acquisition,,Actif,
|
||||||
|
319,Réductions de valeur actées,,Actif,
|
||||||
|
32,En-cours de fabrication,,Actif,
|
||||||
|
320,Valeur d'acquisition,,Actif,
|
||||||
|
329,Réductions de valeur actées,,Actif,
|
||||||
|
33,Produit finis,,Actif,
|
||||||
|
330,Valeur d'acquisition,,Actif,
|
||||||
|
339,Réductions de valeur actées,,Actif,
|
||||||
|
34,Marchandises,,Actif,
|
||||||
|
340,Valeur d'acquisition,,Actif,
|
||||||
|
349,Réductions de valeur actées,,Actif,
|
||||||
|
35,Immeubles destinés a la vente,,Actif,
|
||||||
|
350,Valeur d'acquisition,,Actif,
|
||||||
|
359,Réductions de valeur actées,,Actif,
|
||||||
|
36,Acomptes versés sur achats pour stocks,,Actif,
|
||||||
|
360,Acomptes versés,,Actif,
|
||||||
|
369,Réductions de valeur actées,,Actif,
|
||||||
|
37,Commandes en cours d'exécution,,Actif,
|
||||||
|
370,Valeur d'acquisition,,Actif,
|
||||||
|
371,Bénéfice pris en compte,,Actif,
|
||||||
|
379,Réductions de valeur actées,,Actif,
|
||||||
|
4,CRÉANCES ET DETTES À UN AN AU PLUS,,Passif,
|
||||||
|
40,Créances commerciales,,Passif,
|
||||||
|
400,Clients,,Passif,
|
||||||
|
401,Effets à recevoir,,Passif,
|
||||||
|
404,Produit à recevoir,,Passif,
|
||||||
|
406,Acomptes versés,,Passif,
|
||||||
|
407,Créances douteuses,,Passif,
|
||||||
|
409,Réductions de valeurs actées,,Passif,
|
||||||
|
41,Autres créances,,Passif,
|
||||||
|
410,Autres tiers,,Passif,
|
||||||
|
411,Tva à récupérer,,Passif,
|
||||||
|
412,Impôts et précomptes à récupérer,,Passif,
|
||||||
|
4120,4120 à 4124,,Passif,
|
||||||
|
4125,4125 à 4127 Autres impôts et taxes belges,,Passif,
|
||||||
|
4128,Impôts et taxes étrangers,,Passif,
|
||||||
|
413,Subsides à recevoir,,Passif,
|
||||||
|
414,Produit à recevoir,,Passif,
|
||||||
|
415,Créances non productives d’intérêts ou assorties d’un intérêt anormalement faible,,Passif,
|
||||||
|
416,Créances diverses,,Passif,
|
||||||
|
417,Créances douteuses,,Passif,
|
||||||
|
418,Cautionnements versés en numéraire,,Passif,
|
||||||
|
419,Réductions de valeurs actées,,Passif,
|
||||||
|
42,Dettes à plus d'un an échéant dans l'année (même subdivision que le compte 17),,Passif,
|
||||||
|
43,Dettes financières,,Passif,
|
||||||
|
430,Établissements de crédit – Emprunts en compte à terme fixe,,Passif,
|
||||||
|
431,Établissements de crédit – Promesses,,Passif,
|
||||||
|
432,Établissements de crédit – Crédits d'acceptation,,Passif,
|
||||||
|
433,Établissements de crédit – Dettes en compte courant,,Passif,
|
||||||
|
439,Autres emprunts,,Passif,
|
||||||
|
44,Dettes commerciales,,Passif,
|
||||||
|
440,Fournisseurs,,Passif,
|
||||||
|
441,Effets à payer,,Passif,
|
||||||
|
444,Factures à recevoir,,Passif,
|
||||||
|
45,"Dettes fiscales, salariales et sociales",,Passif,
|
||||||
|
450,Dettes fiscales estimées,,Passif,
|
||||||
|
4505, à 4507 Autres impôts et taxes belges,,Passif,
|
||||||
|
4508,Impôts et taxes étrangers,,Passif,
|
||||||
|
451,Tva à payer,,Passif,
|
||||||
|
452,Impôts et taxes à payer,,Passif,
|
||||||
|
4525,Autres impôts et taxes belges,,Passif,
|
||||||
|
4528,Impôts et taxes étrangers,,Passif,
|
||||||
|
453,Précomptes retenus,,Passif,
|
||||||
|
454,Office national de la Sécurité sociale,,Passif,
|
||||||
|
455,Rémunérations,,Passif,
|
||||||
|
456,Pécules de vacances,,Passif,
|
||||||
|
459,Autres dettes sociales,,Passif,
|
||||||
|
46,Acomptes sur commandes,,Passif,
|
||||||
|
48,Dettes diverses,,Passif,
|
||||||
|
480,Obligations et coupons échus,,Passif,
|
||||||
|
483,Subsides à rembourser,,Passif,
|
||||||
|
488,Cautionnements reçus en numéraire,,Passif,
|
||||||
|
489,Autres dettes diverses,,Passif,
|
||||||
|
4890,Productives d’intérêts,,Passif,
|
||||||
|
4891,Non productives d’intérêts ou assorties d’un intérêt anormalement faible,,Passif,
|
||||||
|
49,Comptes de régularisation et d'attente,,Actif,
|
||||||
|
490,Charge à reporter,,Actif,
|
||||||
|
491,Produit acquis,,Actif,
|
||||||
|
492,Charge à imputer,,Passif,
|
||||||
|
493,Produit à reporter,,Passif,
|
||||||
|
4931,Produit à reporter (créditeur),,Passif,
|
||||||
|
4932,Produit à reporter (débiteur),,Actif,
|
||||||
|
499,Comptes d'attente,,Passif,
|
||||||
|
5,PLACEMENTS DE TRÉSORERIE ET VALEURS DISPONIBLES,,Actif,
|
||||||
|
50,"Placements de trésorerie autres que actions et parts, titres à revenu fixe et dépôts à terme",,Actif,
|
||||||
|
500,Valeur d'acquisition,,Actif,
|
||||||
|
509,Réductions de valeurs actées,,Actif,
|
||||||
|
51,Actions et parts,,Actif,
|
||||||
|
510,Valeur d'acquisition,,Actif,
|
||||||
|
511,Montants non appelés,,Actif,
|
||||||
|
519,Réductions de valeur actées,,Actif,
|
||||||
|
52,Titres à revenu fixe,,Actif,
|
||||||
|
520,Valeur d'acquisition,,Actif,
|
||||||
|
529,Réductions de valeurs actées,,Actif,
|
||||||
|
53,Dépôts à terme,,Actif,
|
||||||
|
530,De plus d'un an,,Actif,
|
||||||
|
531,De plus d'un mois et à un an au plus,,Actif,
|
||||||
|
532,D'un mois au plus,,Actif,
|
||||||
|
539,Réductions de valeur actées,,Actif,
|
||||||
|
54,Valeurs échues à l'encaissement,,Actif,
|
||||||
|
55,Établissements de crédit,,Actif,
|
||||||
|
56,Comptes bancaires,,Actif,Favori
|
||||||
|
57,Caisses,,Actif,
|
||||||
|
570,Caisses-espèces,,Actif,Favori
|
||||||
|
578,Caisses-timbres,,Actif,
|
||||||
|
58,Virements internes,,Actif,
|
||||||
|
6,CHARGES,,Charge,
|
||||||
|
60,Approvisionnements et marchandises,,Charge,
|
||||||
|
600,Achats de matières premières,,Charge,Favori
|
||||||
|
601,Achats de fournitures,,Charge,Favori
|
||||||
|
602,"Achats de services, travaux et études",,Charge,Favori
|
||||||
|
603,Sous-traitances générales,,Charge,Favori
|
||||||
|
604,Achats de marchandises,,Charge,Favori
|
||||||
|
605,Achats d'immeubles destinés à la vente,,Charge,
|
||||||
|
608,"Remises, ristournes et rabais obtenus",,Charge,
|
||||||
|
609,Variation des stocks,,Charge,
|
||||||
|
6090,de matières premières,,Charge,
|
||||||
|
6091,de fournitures,,Charge,
|
||||||
|
6094,de marchandises,,Charge,
|
||||||
|
6095,d'immeubles destinés à la vente,,Charge,
|
||||||
|
61,Services et biens divers,,Charge,Favori
|
||||||
|
617,Personnel intérimaire et personnes mises à la disposition de l’association ou de la fondation,,Charge,
|
||||||
|
618,"Rémunérations, primes pour assurances extralégales, pensions de retraite et de survie des administrateurs qui ne sont pas attribuées en vertu d'un contrat de travail",,Charge,
|
||||||
|
62,"Rémunérations, charges sociales et pensions",,Charge,
|
||||||
|
620,Rémunérations et avantages sociaux directs,,Charge,Favori
|
||||||
|
6200,Administrateurs ou gérants,,Charge,
|
||||||
|
6201,Personnel de direction,,Charge,
|
||||||
|
6202,Employés,,Charge,
|
||||||
|
6203,Ouvriers,,Charge,
|
||||||
|
6204,Autres membres du personnel,,Charge,
|
||||||
|
621,Cotisations patronales pour assurances sociales,,Charge,
|
||||||
|
622,Primes patronales pour assurances extra-légales,,Charge,
|
||||||
|
623,Autres frais du personnel,,Charge,
|
||||||
|
624,Pensions de retraite et de survie,,Charge,
|
||||||
|
6240,Administrateurs ou gérants (27),,Charge,
|
||||||
|
6241,Personnel,,Charge,
|
||||||
|
63,"Amortissements, réductions de valeur et provisions pour risques et charges",,Charge,
|
||||||
|
630,Dotations aux amortissements et aux réductions de valeur sur immobilisations,,Charge,
|
||||||
|
6300,Dotations aux amortissements sur frais d'établissement,,Charge,
|
||||||
|
6301,Dotation aux amortissements sur immobilisations incorporelles,,Charge,
|
||||||
|
6302,Dotation aux amortissements sur immobilisations corporelles,,Charge,
|
||||||
|
6308,Dotation aux réductions de valeurs sur immobilisations incorporelles,,Charge,
|
||||||
|
6309,Dotation aux réductions de valeurs sur immobilisations corporelles,,Charge,
|
||||||
|
631,Réductions de valeur sur stocks,,Charge,
|
||||||
|
6310,Dotations,,Charge,
|
||||||
|
6311,Reprises,,Charge,
|
||||||
|
632,Réductions de valeur sur commandes en cours d'exécution,,Charge,
|
||||||
|
6320,Dotations,,Charge,
|
||||||
|
6321,Reprises,,Charge,
|
||||||
|
633,Réductions de valeur sur créances commerciales à plus d'un an,,Charge,
|
||||||
|
6330,Dotations,,Charge,
|
||||||
|
6331,Reprises,,Charge,
|
||||||
|
634,Réductions de valeur sur créances à un an au plus,,Charge,
|
||||||
|
6340,Dotations,,Charge,
|
||||||
|
6341,Reprises,,Charge,
|
||||||
|
635,Provisions pour pensions et obligations similaires,,Charge,
|
||||||
|
6350,Dotations,,Charge,
|
||||||
|
6351,Utilisations et reprises,,Charge,
|
||||||
|
636,Provisions pour grosses réparations et gros entretiens,,Charge,
|
||||||
|
6360,Dotations,,Charge,
|
||||||
|
6361,Utilisations et reprises,,Charge,
|
||||||
|
637,Provisions pour obligations environnementales,,Charge,
|
||||||
|
6370,Dotations,,Charge,
|
||||||
|
6371,Utilisations et reprises,,Charge,
|
||||||
|
638,Provisions pour subsides et legs à rembourser et pour dons avec droit de reprise,,Charge,
|
||||||
|
6380,Dotations,,Charge,
|
||||||
|
6381,Utilisations et reprises,,Charge,
|
||||||
|
639,Provisions pour autres risques et charges,,Charge,
|
||||||
|
6390,Dotations,,Charge,
|
||||||
|
6391,Utilisations et reprises,,Charge,
|
||||||
|
64,Autres charges d'exploitation,,Charge,
|
||||||
|
640,Charges fiscales,,Charge,
|
||||||
|
641,Moins-values sur réalisations courantes d'immobilisations corporelles,,Charge,
|
||||||
|
642,Moins-values sur réalisations de créances commerciales,,Charge,
|
||||||
|
643,Dons,,Charge,
|
||||||
|
644,644-648 Charges d'exploitations diverses,À subdiviser,Charge,
|
||||||
|
649,Charges d'exploitation portées à l'actif au titre de frais de restructuration (–),,Charge,
|
||||||
|
65,Charges financières,,Charge,
|
||||||
|
650,Charges des dettes,,Charge,
|
||||||
|
6500,"Intérêts, commissions et frais afférents aux dettes",,Charge,
|
||||||
|
6501,Amortissements frais d'émission d'emprunts et des primes de remboursement,,Charge,
|
||||||
|
6502,Intérêts intercalaires portés à l'actif,,Charge,
|
||||||
|
651,Réductions de valeur sur actifs circulants,,Charge,
|
||||||
|
6510,Dotations,,Charge,
|
||||||
|
6511,Reprises,,Charge,
|
||||||
|
652,Moins-values sur réalisation d'actifs circulants,,Charge,
|
||||||
|
653,Charges d'escompte de créances,,Charge,
|
||||||
|
654,Différences de change,,Charge,
|
||||||
|
655,Écarts de conversion des devises,,Charge,
|
||||||
|
656,Provisions à caractère financier,,Charge,
|
||||||
|
6560,Dotations,,Charge,
|
||||||
|
6561,Utilisations et reprises,,Charge,
|
||||||
|
657,Charges financières diverses,À subdiviser,Charge,
|
||||||
|
659,Charges financières portées à l'actif au titre de frais de restructuration,,Charge,
|
||||||
|
66,Charges d’exploitation ou financières non récurrentes,,Charge,
|
||||||
|
660,Amortissements et réductions de valeur non récurrents (dotations),,Charge,
|
||||||
|
6600,sur frais d'établissement,,Charge,
|
||||||
|
6601,sur immobilisations incorporelles,,Charge,
|
||||||
|
6602,sur immobilisations corporelles,,Charge,
|
||||||
|
661,Réduction de valeur sur immobilisations financières (dotation),,Charge,
|
||||||
|
662,Provisions pour risques et charges non récurrents,,Charge,
|
||||||
|
6620,Provisions pour risques et charges d’exploitation non récurrents,,Charge,
|
||||||
|
66200,Dotations,,Charge,
|
||||||
|
66201,Utilisations,,Charge,
|
||||||
|
6621,Provisions pour risques et charges financiers non récurrents,,Charge,
|
||||||
|
66210,Dotations,,Charge,
|
||||||
|
66211,Utilisation,,Charge,
|
||||||
|
663,Moins-values sur réalisation d'actifs immobilisés,,Charge,
|
||||||
|
6630,Moins-values sur réalisation d'immobilisations incorporelles et corporelles,,Charge,
|
||||||
|
6631,Moins-values sur réalisations d'actifs immobilisés,,Charge,
|
||||||
|
664,664 à 667 Autres charges d'exploitation non récurrentes,À subdiviser,Charge,
|
||||||
|
668,Autres charges financières non récurrentes,,Charge,
|
||||||
|
6690,Charges d’exploitation portées à l’actif au titre de frais de restructuration,,Charge,
|
||||||
|
6691,Charges financières non récurrentes portées à l'actif au titre de frais de restructuration,,Charge,
|
||||||
|
67,Impôts,,Charge,
|
||||||
|
670, Impôts belges sur le résultat de l’exercice,,Charge,
|
||||||
|
6701,Excédent de versements d'impôts et de précomptes porté à l’actif (–),,Charge,
|
||||||
|
6702, Charges fiscales estimées,,Charge,
|
||||||
|
6710,Suppléments d'impôts dus ou versés,,Charge,
|
||||||
|
6711, Suppléments d'impôts estimés,,Charge,
|
||||||
|
6712,Provisions fiscales constituées," Impôts étrangers sur le résultat de l’exercice, impôts étrangers sur le résultat d'exercices antérieurs",Charge,
|
||||||
|
68, Transferts aux impôts différés et aux réserves immunisées,,Charge,
|
||||||
|
680, Transferts aux impôts différés,,Charge,
|
||||||
|
689,Transferts aux réserves immunisées,,Charge,
|
||||||
|
69,Affectations et prélèvements,,Charge,
|
||||||
|
690,Résultat négatif de l'exercice antérieur reporté,,Passif,
|
||||||
|
691,Transfert aux fonds affectés et autres réserves,,Actif,
|
||||||
|
692,Résultat positif à reporter,,Actif,
|
||||||
|
7,PRODUITS,,Produit,
|
||||||
|
70,Chiffre d'affaires,,Produit,
|
||||||
|
700,Ventes et prestations de services,,Produit,Favori
|
||||||
|
708,"Remises, ristournes et rabais accordés",,Produit,
|
||||||
|
71,Variation des stocks et des commandes en cours d’exécution,,Produit,
|
||||||
|
712,Des en-cours de fabrication,,Produit,Favori
|
||||||
|
713,Des produits finis,,Produit,Favori
|
||||||
|
715,Des immeubles construits destinés à la vente,,Produit,
|
||||||
|
717,Des commandes en cours d'exécution,,Produit,
|
||||||
|
7170,Valeur d'acquisition,,Produit,
|
||||||
|
7171,Bénéfice pris en compte,,Produit,
|
||||||
|
72,Production immobilisée,,Produit,
|
||||||
|
73,"Cotisations, dons, legs et subsides",,Produit,Favori
|
||||||
|
730,Cotisations,,Produit,Favori
|
||||||
|
731,Dons,,Produit,Favori
|
||||||
|
732,Legs,,Produit,Favori
|
||||||
|
733,Subsides,,Produit,Favori
|
||||||
|
74,Autres produits d’exploitation,,Produit,Favori
|
||||||
|
741,Plus-values sur réalisations courantes d'immobilisations corporelles,,Produit,
|
||||||
|
742,Plus-values sur réalisation de créances commerciales,,Produit,
|
||||||
|
743,743-749 Produits d'exploitation divers,À subdiviser,Produit,
|
||||||
|
75,Produits financiers,,Produit,Favori
|
||||||
|
750,Produits des immobilisations financières,,Produit,
|
||||||
|
751,Produits des actifs circulants,,Produit,
|
||||||
|
752,Plus-values sur la réalisation d'actifs circulants,,Produit,
|
||||||
|
753,(libellé vide dans la version officielle),,Produit,
|
||||||
|
754,Différences de change,,Produit,
|
||||||
|
755,Écarts de conversion des devises,,Produit,
|
||||||
|
756,756-759 Produits financiers divers,À subdiviser,Produit,
|
||||||
|
76,Produits d'exploitation ou financiers non récurrents,,Produit,
|
||||||
|
760,Reprise d'amortissements et réductions de valeur,,Produit,
|
||||||
|
7600,Reprise sur immobilisations incorporelles,,Produit,
|
||||||
|
7601,Reprise sur immobilisations corporelles,,Produit,
|
||||||
|
761,Reprises de réductions de valeur sur immobilisations financières,,Produit,
|
||||||
|
762,Reprises de provisions pour risques et charges non récurrents,,Produit,
|
||||||
|
7620,Reprises de provisions pour risques et charges d’exploitation non récurrents,,Produit,
|
||||||
|
7621,Reprises de provisions pour risques et charges financiers non récurrents,,Produit,
|
||||||
|
763,Plus-values sur réalisation d'actifs immobilisés,,Produit,
|
||||||
|
7630,Plus-values sur réalisation d'immobilisations incorporelles et corporelles,,Produit,
|
||||||
|
7631,Plus-values sur réalisations d'actifs immobilisés,,Produit,
|
||||||
|
764,764-768 Autres produits d’exploitation non récurrents,À subdiviser,Produit,
|
||||||
|
769,Autres produits financiers non récurrents,,Produit,
|
||||||
|
77,Régularisation d'impôts,,Produit,
|
||||||
|
78,Prélèvement sur les réserves immunisées et les impôts différés,,Produit,
|
||||||
|
780,Prélèvement sur les impôts différés,,Produit,
|
||||||
|
789,Prélèvement sur les réserves immunisées,,Produit,
|
||||||
|
79,Affectations et prélèvements,,Produit,
|
||||||
|
790,Résultat positif de l'exercice antérieur reporté,Résultat excédentaire,Produit,
|
||||||
|
791,Autres réserves,,Produit,
|
||||||
|
792,Résultat négatif à reporter,Résultat déficitaire,Charge,
|
||||||
|
890,Ouverture,,,
|
||||||
|
891,Clôture,,,
|
||||||
|
0,DROITS ET ENGAGEMENTS HORS BILAN,Sont portés dans les comptes de la classe 0 les droits et engagements autres que ceux qui doivent être portés dans les comptes des classes 1 à 5.,,
|
||||||
|
00,Garanties constituées par des tiers pour compte de l’association ou de la fondation,,,
|
||||||
|
000,"Créanciers de l'association ou de la fondation, bénéficiaires de garanties de tiers",,,
|
||||||
|
001,Tiers constituants de garanties pour compte de l’association ou de la fondation,,,
|
||||||
|
01,Garanties personnelles pour compte de tiers,,,
|
||||||
|
010,Débiteurs pour engagements sur effets en circulation,,,
|
||||||
|
011,Créanciers d'engagements sur effets en circulation,,,
|
||||||
|
0110,Effets cédés par l’association ou la fondation sous son endos,,,
|
||||||
|
0111,Autres engagements sur effets en circulation,,,
|
||||||
|
012,Débiteurs pour autres garanties personnelles,,,
|
||||||
|
013,Créanciers d'autres garanties personnelles,,,
|
||||||
|
02,Garanties réelles constituées sur avoirs propres,,,
|
||||||
|
020,"Créanciers de l'association ou de la fondation, bénéficiaires de garanties réelles",,,
|
||||||
|
021,Garanties réelles constituées pour compte propre,,,
|
||||||
|
022,"Créanciers de tiers, bénéficiaires de garanties réelles",,,
|
||||||
|
023,Garanties réelles constituées pour compte de tiers,,,
|
||||||
|
03,Garanties reçues,,,
|
||||||
|
032,Garanties reçues,,,
|
||||||
|
033,Constituants de garanties,,,
|
||||||
|
04,Biens et valeurs détenus par des tiers en leur nom mais aux risques et profits de l’association ou de la fondation,,,
|
||||||
|
040,"Tiers, détenteurs en leur nom mais aux risques et profits de l'association ou de la fondation de biens et de valeurs",,,
|
||||||
|
041,Biens et valeurs détenus par des tiers en leur nom mais aux risques et profits de l’association ou de la fondation,,,
|
||||||
|
05,Engagements d'acquisition et de cession d’immobilisations,,,
|
||||||
|
050,Engagements d'acquisition,,,
|
||||||
|
051,Créanciers d'engagements d'acquisition,,,
|
||||||
|
052,Débiteurs pour engagements de cession,,,
|
||||||
|
053,Engagements de cession,,,
|
||||||
|
06,Marchés à terme,,,
|
||||||
|
060,Marchandises achetées à terme - à recevoir,,,
|
||||||
|
061,Créanciers pour marchandises achetées à terme,,,
|
||||||
|
062,Débiteurs pour marchandises vendues à terme,,,
|
||||||
|
063,Marchandises vendues à terme - à livrer,,,
|
||||||
|
064,Devises achetées à terme - à recevoir,,,
|
||||||
|
065,Créanciers pour devises achetées à terme,,,
|
||||||
|
066,Débiteurs pour devises vendues à terme,,,
|
||||||
|
067,Devises vendues à terme - à livrer,,,
|
||||||
|
07,Biens et valeurs de tiers détenus par l'association ou la fondation,,,
|
||||||
|
070,Droits d'usage à long terme,,,
|
||||||
|
0700,Sur terrains et constructions,,,
|
||||||
|
0701,"Sur installations, machines et outillage",,,
|
||||||
|
0702,Sur mobilier et matériel roulant,,,
|
||||||
|
071,Créanciers de loyers et redevances,,,
|
||||||
|
072,"Biens et valeurs de tiers reçus en dépôt, en consignation ou à façon",,,
|
||||||
|
073,Commettants et déposants de biens et de valeurs,,,
|
||||||
|
074,Biens et valeurs détenus pour compte ou aux risques et profits de tiers,,,
|
||||||
|
075,Créanciers de biens et valeurs détenus pour compte de tiers ou à leurs risques et profits,,,
|
||||||
|
09,Droits et engagements divers,,,
|
|
167
src/include/data/charts/ch_asso.csv
Normal file
167
src/include/data/charts/ch_asso.csv
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
Numéro,Libellé,Description,Position,Favori
|
||||||
|
1,Actifs,,Actif,
|
||||||
|
10,Liquidités,,Actif,
|
||||||
|
100,Caisses,,Actif,
|
||||||
|
1000,Caisse,,Actif,Favori
|
||||||
|
1005,Caisse Euro,,Actif,Favori
|
||||||
|
1010,CCP,,Actif,
|
||||||
|
102,Banques,,Actif,
|
||||||
|
1020,Compte bancaire,,Actif,Favori
|
||||||
|
1030,Dépôts à court terme (< 3 mois),,Actif,
|
||||||
|
109,Comptes d’attente,,Actif,
|
||||||
|
1090,Dépôts en attente,,Actif,Favori
|
||||||
|
11,Titres cotés en bourse et détenus à court terme,,Actif,
|
||||||
|
1100,Titres,,Actif,
|
||||||
|
12,Débiteurs,,Actif,
|
||||||
|
120,Débiteurs résultant de la vente de biens et de prestations de services,,Actif,
|
||||||
|
1200,Débiteurs résultant de la vente de biens et de prestations de services,,Actif,
|
||||||
|
125,Autres débiteurs,,Actif,
|
||||||
|
1250,Autres débiteurs,,Actif,
|
||||||
|
13,Stocks,,Actif,
|
||||||
|
1300,Stocks divers,,Actif,
|
||||||
|
14,Actifs transitoires (comptes de régularisation d’actifs),,Actif,
|
||||||
|
1400,Impôts anticipés,,Actif,
|
||||||
|
1410,Produits à recevoir,,Actif,
|
||||||
|
1420,Charges payées d'avance,,Actif,
|
||||||
|
15,Immobilisations financières,,Actif,
|
||||||
|
1500,Cautions loyers,,Actif,
|
||||||
|
16,Participations,,Actif,
|
||||||
|
1600,Participations dans d’autres entités,,Actif,
|
||||||
|
17,Immobilisations corporelles,,Actif,
|
||||||
|
1700,Mobilier,,Actif,
|
||||||
|
1710,Informatique,,Actif,
|
||||||
|
18,Immobilisations incorporelles,,Actif,
|
||||||
|
1800,Licences informatiques,,Actif,
|
||||||
|
2,Passifs,,Passif,
|
||||||
|
20,Créanciers,,Passif,
|
||||||
|
2000,Fournisseurs,,Passif,
|
||||||
|
2050,Autres dettes à court terme,,Passif,
|
||||||
|
21,Dettes à court terme liées aux charges de personnel,,Passif,
|
||||||
|
2100,Créanciers caisse AVS,,Passif,
|
||||||
|
2110,Créanciers LAA,,Passif,
|
||||||
|
2120,Créanciers LPP,,Passif,
|
||||||
|
2130,Créanciers impôt source,,Passif,
|
||||||
|
2140,Créanciers assurance indemnités journalières maladie,,Passif,
|
||||||
|
2180,Salaires à payer,,Passif,
|
||||||
|
22,Dettes financières à court terme,,Passif,
|
||||||
|
2200,Emprunts bancaires à rembourser dans l'année,,Passif,
|
||||||
|
23,Passifs transitoires (comptes de régularisation de passifs),,Passif,
|
||||||
|
2310,Produits constatés d'avance,,Passif,
|
||||||
|
2320,Charges à payer,,Passif,
|
||||||
|
24,Dettes à long terme,,Passif,
|
||||||
|
2400,Emprunts bancaires à rembourser à plus d'une année,,Passif,
|
||||||
|
2410,Autres dettes à long terme,,Passif,
|
||||||
|
26,Provisions,,Passif,
|
||||||
|
28,Fonds affectés (Swiss GAAP RPC),À subdiviser par projet,Passif,
|
||||||
|
29,Fonds propres,,Passif,
|
||||||
|
2900,Capital initial versé (ou capital de fondation),,Passif,
|
||||||
|
2910,Réserve associative,,Passif,
|
||||||
|
2990,Résultats reportés (fonds libres),,Passif,
|
||||||
|
2999,Résultat de l'exercice,,Passif,
|
||||||
|
29991,Résultat positif,,Passif,
|
||||||
|
29999,Résultat négatif,,Passif,
|
||||||
|
3,Charges,,Charge,
|
||||||
|
30,Charges directes de projets,À subdiviser par projet,Charge,
|
||||||
|
31,Charges de personnel,,Charge,
|
||||||
|
310,Salaires,,Charge,
|
||||||
|
3100,Salaires,,Charge,Favori
|
||||||
|
311,Charges sociales,,Charge,
|
||||||
|
3110,AVS-AI-AC-AMAT,,Charge,
|
||||||
|
3111,LAA professionnelle,,Charge,
|
||||||
|
3112,LAA complémentaire,,Charge,
|
||||||
|
3113,Assurance indemnités journalières maladie,,Charge,
|
||||||
|
3114,LPP,,Charge,
|
||||||
|
312,Autres charges de personnel,,Charge,
|
||||||
|
3120,Frais de formation,,Charge,Favori
|
||||||
|
3128,Autres frais de personnel,,Charge,
|
||||||
|
315,Compensations charges de personnel (revenus présentés en déduction des charges de personnel),,Charge,
|
||||||
|
3150,Indemnités d'assurance pour charges du personnel,,Charge,
|
||||||
|
3151,Mise à disposition de personnes,,Charge,
|
||||||
|
3152,Commission perception IS,,Charge,
|
||||||
|
3159,Autres compensations charges salariales,,Charge,
|
||||||
|
32,Charges de locaux,,Charge,
|
||||||
|
3200,Loyers,,Charge,Favori
|
||||||
|
3210,"Charges – Eau, gaz, électricité ",,Charge,Favori
|
||||||
|
3220,Frais d'entretiens locaux,,Charge,Favori
|
||||||
|
3230,Assurance RC et choses,,Charge,
|
||||||
|
3280,Frais de location de salles,,Charge,Favori
|
||||||
|
33,Administration et informatique,,Charge,
|
||||||
|
330,Administration,,Charge,
|
||||||
|
3300,Fournitures de bureau,,Charge,Favori
|
||||||
|
3301,Télécommunications,,Charge,Favori
|
||||||
|
3302,Frais de port,,Charge,Favori
|
||||||
|
3303,Documents et abonnements,,Charge,
|
||||||
|
3304,Frais de cotisations,,Charge,
|
||||||
|
3306,Frais de réunion,,Charge,
|
||||||
|
335,Informatique,,Charge,
|
||||||
|
3350,Frais de licence,Par exemple pour décompter la contribution à un logiciel comptable ;-),Charge,Favori
|
||||||
|
3351,Frais de maintenance,,Charge,
|
||||||
|
3352,Petit matériel informatique,,Charge,Favori
|
||||||
|
34,Frais de promotion et de représentation,,Charge,
|
||||||
|
340,Matériel de promotion,,Charge,
|
||||||
|
3400,Impression de matériel de promotion,,Charge,
|
||||||
|
3401,Conception de matériel de promotion,,Charge,
|
||||||
|
3409,Autre matériel de promotion,,Charge,
|
||||||
|
341,Site internet et communication en ligne,,Charge,
|
||||||
|
3410,"Frais de maintenance de site internet, plateforme web, outils de communication en ligne",,Charge,
|
||||||
|
3411,"Conception de site internet, plateforme web, outils de communication en ligne",,Charge,
|
||||||
|
3419,Autres frais liés à la communication en ligne,,Charge,
|
||||||
|
346,Frais de représentation,,Charge,
|
||||||
|
3460,Frais de voyage,,Charge,
|
||||||
|
3461,Frais de repas,,Charge,Favori
|
||||||
|
3469,Autres frais de représentation,,Charge,
|
||||||
|
35,Mises à disposition gratuites (contrepartie : subventions non monétaires en 45),,Charge,
|
||||||
|
36,Autres charges d’exploitation,,Charge,
|
||||||
|
360,Amortissements et dépréciations d’actifs,,Charge,
|
||||||
|
3600,Amortissements,,Charge,
|
||||||
|
3601,Dépréciations d’actifs,,Charge,
|
||||||
|
361,Charges sur débiteurs douteux,,Charge,
|
||||||
|
3610,Variation provision sur débiteurs douteux,,Charge,
|
||||||
|
3620,Pertes sur débiteurs douteux,,Charge,
|
||||||
|
369,Autres charges d’exploitation,,Charge,
|
||||||
|
3690,Autres charges d’exploitation,,Charge,
|
||||||
|
37,"Charges hors exploitation, exceptionnelles, uniques ou hors périodes",,Charge,
|
||||||
|
370,Charges hors exploitation,,Charge,
|
||||||
|
3700,Charges hors exploitation,,Charge,
|
||||||
|
371,Charges exceptionnelles ou uniques,,Charge,
|
||||||
|
3710,Charges exceptionnelles ou uniques,,Charge,
|
||||||
|
372,Charges hors périodes,,Charge,
|
||||||
|
3720,Charges liées aux exercices précédents,,Charge,
|
||||||
|
38,Charges financières,,Charge,
|
||||||
|
3800,Charges d'intérêts,,Charge,
|
||||||
|
3810,Frais bancaires,,Charge,Favori
|
||||||
|
3820,Pertes de change,,Charge,
|
||||||
|
39,Variation des fonds affectés (Swiss GAAP RPC),,Charge,
|
||||||
|
3900,Attribution aux fonds affectés,,Charge,
|
||||||
|
3910,Produits internes de fonds affectés,,Produit,
|
||||||
|
4,Revenus,,Produit,
|
||||||
|
40,Revenus de ventes et de prestations,,Produit,
|
||||||
|
4000,Revenu de prestations,,Produit,Favori
|
||||||
|
4010,Revenu de ventes,,Produit,Favori
|
||||||
|
41,Revenus des fonds affectés,,Produit,
|
||||||
|
410,Subventions,,Produit,Favori
|
||||||
|
4130,Donateurs privés – fonds affectés,,Produit,
|
||||||
|
42,Dons non affectés,,Produit,
|
||||||
|
4220,Donateurs privés – non affectés,,Produit,
|
||||||
|
43,Cotisations de membres,,Produit,
|
||||||
|
4400,Cotisations de membres,,Produit,Favori
|
||||||
|
45,Subventions non monétaires (contrepartie : mises à disposition gratuites en 35),,Produit,
|
||||||
|
46,Autres produits d’exploitation,,Produit,
|
||||||
|
4600,Dissolutions de provisions,,Produit,
|
||||||
|
47,"Produits hors exploitation, exceptionnels, uniques ou hors périodes ",,Produit,
|
||||||
|
470,Produits hors exploitation,,Produit,
|
||||||
|
4700,Produits hors exploitation,,Produit,
|
||||||
|
471,Produits exceptionnels ou uniques,,Produit,
|
||||||
|
4710,Produits exceptionnels ou uniques,,Produit,
|
||||||
|
472,Produits hors période,,Produit,
|
||||||
|
4720,Produits liés aux exercices précédents,,Produit,
|
||||||
|
48,Revenus financiers,,Produit,
|
||||||
|
4800,Revenus d'intérêts,,Produit,
|
||||||
|
4820,Gains de change,,Produit,
|
||||||
|
49,Variation des fonds affectés (Swiss GAAP RPC),,Produit,
|
||||||
|
4900,Utilisation des fonds affectés,,Produit,
|
||||||
|
4910,Charges internes de fonds affectés,,Charge,
|
||||||
|
5,Comptes de tiers,,Actif ou passif,
|
||||||
|
9,Bilan,,,
|
||||||
|
9100,Bilan d'ouverture,,,
|
||||||
|
9101,Bilan de clôture,,,
|
|
587
src/include/data/charts/fr_cse_2015.csv
Normal file
587
src/include/data/charts/fr_cse_2015.csv
Normal file
|
@ -0,0 +1,587 @@
|
||||||
|
code,label,description,position,bookmark
|
||||||
|
1,"Classe 1 — Comptes de capitaux (Fonds propres, emprunts et dettes assimilés)",,Passif,
|
||||||
|
10,FONDS ASSOCIATIFS ET RÉSERVES,,Passif,
|
||||||
|
102,Fonds associatifs sans droit de reprise,,Passif,
|
||||||
|
1021,Première situation nette établie,,Passif,
|
||||||
|
1022,Fonds statutaires,,Passif,
|
||||||
|
1023,Dotations non consomptibles,,Passif,
|
||||||
|
10231,Dotations non consomptibles initiales,,Passif,
|
||||||
|
10232,Dotations non consomptibles complémentaires,,Passif,
|
||||||
|
1024,Autres fonds propres sans droit de reprise,,Passif,
|
||||||
|
103,Fonds associatif avec droit de reprise,,Passif,
|
||||||
|
1032,Fonds statutaires,,Passif,
|
||||||
|
1034,Autres fonds propres avec droit de reprise,,Passif,
|
||||||
|
105,Écarts de réévaluation,,Passif,
|
||||||
|
1051,Écarts réévaluation sur biens sans droit reprise,,Passif,
|
||||||
|
1052,Écarts réévaluation sur biens avec droit reprise,,Passif,
|
||||||
|
106,Réserves,,Passif,
|
||||||
|
1061,Réserves « Attributions économiques et professionnelles »,,Actif ou passif,
|
||||||
|
1062,Réserves « Activités sociales et culturelles »,,Passif,
|
||||||
|
1063,Réserves Indisponibles,,Passif,
|
||||||
|
1064,Réserves statutaires,,Passif,
|
||||||
|
1068,Réserves réglementées,,Passif,
|
||||||
|
1069,Réserves pour projet de l’entité,,Passif,
|
||||||
|
108,Dotations consomptibles,,Passif,
|
||||||
|
1081,Dotations consomptibles,,Passif,
|
||||||
|
1089,Dotation consomptibles inscrites au compte de résultat,,Passif,
|
||||||
|
11,REPORT à NOUVEAU,,Passif,
|
||||||
|
110,Report à nouveau (Solde créditeur),,Passif,
|
||||||
|
1101,Report à nouveau « Attributions économiques et professionnelles » (solde créditeur),,Passif,
|
||||||
|
1102,Report à nouveau « Activités sociales et culturelles » (solde créditeur),,Passif,
|
||||||
|
119,Report à nouveau (Solde débiteur),,Passif,
|
||||||
|
1191,Report à nouveau « Attributions économiques et professionnelles » (solde débiteur),,Passif,
|
||||||
|
1192,Report à nouveau « Activités sociales et culturelles » (solde débiteur),,Passif,
|
||||||
|
12,RÉSULTAT NET DE L'EXERCICE,,Passif,
|
||||||
|
120,Résultat de l'exercice (excédent),,Passif,
|
||||||
|
1201,Résultat de l’exercice « Attributions économiques et professionnelles » (excédent),,Passif,
|
||||||
|
1202,Résultat de l’exercice « Activités sociales et culturelles » (excédent),,Passif,
|
||||||
|
129,Résultat de l'exercice (déficit),,Passif,
|
||||||
|
1291,Résultat de l’exercice « Attributions économiques et professionnelles » (déficit),,Passif,
|
||||||
|
1292,Résultat de l’exercice « Activités sociales et culturelles » (déficit),,Passif,
|
||||||
|
13,SUBVENTIONS D'INVESTISSEMENTS,,Passif,
|
||||||
|
131,Subventions d'équipement,,Passif,
|
||||||
|
1311,État,,Passif,
|
||||||
|
1312,Régions,,Passif,
|
||||||
|
1313,Départements,,Passif,
|
||||||
|
1314,Communes,,Passif,
|
||||||
|
1315,Collectivités publiques,,Passif,
|
||||||
|
1316,Entreprises publiques,,Passif,
|
||||||
|
1317,Entreprises et organismes privés,,Passif,
|
||||||
|
139,Subventions inscrites au compte de résultat,,Passif,
|
||||||
|
14,PROVISIONS RÉGLEMENTÉES,,Passif,
|
||||||
|
148,Autres provisions réglementées,,Passif,
|
||||||
|
15,PROVISIONS POUR RISQUES ET CHARGES,,Passif,
|
||||||
|
151,Provisions pour risques,,Passif,
|
||||||
|
152,Provisions pour charges sur legs ou donations,,Passif,
|
||||||
|
153,Provisions pour pensions et obligations simil,,Passif,
|
||||||
|
155,Provisions pour impôts,,Passif,
|
||||||
|
157,Provisions pour charges à répartir,,Passif,
|
||||||
|
158,Autres provisions pour charges,,Passif,
|
||||||
|
16,EMPRUNTS ET DETTES ASSIMILÉES,,Passif,
|
||||||
|
163,Autres emprunts obligataires,,Passif,
|
||||||
|
1631,Titres associatifs et assimilés,,Passif,
|
||||||
|
164,Emprunts auprès des établissements de crédit,,Passif,
|
||||||
|
165,Dépôts et cautionnements reçus,,Passif,
|
||||||
|
1651,Dépôts,,Passif,
|
||||||
|
1655,Cautionnements,,Passif,
|
||||||
|
167,Emprunts et dettes sous conditions particulières,,Passif,
|
||||||
|
168,Autres emprunts et dettes assimilées,,Passif,
|
||||||
|
18,COMPTES DE LIAISONS,,Passif,
|
||||||
|
181,Apports permanents siège-établissements,,Passif,
|
||||||
|
185,Biens & prestations de services échangés siège-établissements,,Passif,
|
||||||
|
186,Biens & prestations de services entre établissements - Charges,,Passif,
|
||||||
|
187,Biens & prestations de services entre établissements - Produits,,Passif,
|
||||||
|
19,FONDS DÉDIÉS OU REPORTÉS,,Passif,
|
||||||
|
191,Fonds reportés liés aux legs ou donations,,Passif,
|
||||||
|
1911,Legs ou donations,,Passif,
|
||||||
|
1912,Donations temporaires d’usufruit,,Passif,
|
||||||
|
194,Fonds dédiés sur subventions fonctionnement,,Passif,
|
||||||
|
195,Fonds dédiés sur contributions financières autres organismes,,Passif,
|
||||||
|
196,Fonds dédiés sur ressources liées à la générosité,,Passif,
|
||||||
|
2,Classe 2 — Comptes d'immobilisations,,Actif,
|
||||||
|
20,IMMOBILISATIONS INCORPORELLES,,Actif,
|
||||||
|
201,Frais d'établissement,,Actif,
|
||||||
|
203,Frais de recherche et de développement,,Actif,
|
||||||
|
204,Donations temporaires d’usufruit,,Actif,
|
||||||
|
205,"Brevets, licences, marques...",,Actif,
|
||||||
|
206,Droit au bail,,Actif,
|
||||||
|
208,Autres immobilisations incorporelles,,Actif,
|
||||||
|
21,IMMOBILISATIONS CORPORELLES,,Actif,
|
||||||
|
211,Terrains,,Actif,
|
||||||
|
212,Agencements / aménagements de terrains,,Actif,
|
||||||
|
2131,Bâtiments,,Actif,
|
||||||
|
2135,"Installations, agencements...de constructions",,Actif,
|
||||||
|
214,Constructions sur sol d'autrui,,Actif,
|
||||||
|
215,"Installations techniques, matériel, outillage",,Actif,
|
||||||
|
2154,Matériel industriel,,Actif,
|
||||||
|
2155,Outillage industriel,,Actif,
|
||||||
|
218,Autres immobilisations corporelles,,Actif,
|
||||||
|
2181,"Installations, agencements, aménagements divers",,Actif,
|
||||||
|
2182,Matériel de transport,,Actif,
|
||||||
|
2183,Matériel de bureau et matériel informatique,D’une valeur supérieure à 500€,Actif,
|
||||||
|
2184,Mobilier,D’une valeur supérieure à 500€,Actif,
|
||||||
|
23,IMMOBILISATIONS EN COURS,,Actif,
|
||||||
|
231,Immobilisations corporelles en cours,,Actif,
|
||||||
|
238,"Avances, acomptes sur immobilisations corporelles",,Actif,
|
||||||
|
24,BIEN DESTINÉS À ÊTRE CÉDÉS,,Actif,
|
||||||
|
240,Biens reçus par legs ou donations à céder,,Actif,
|
||||||
|
26,PARTICIPATIONS ET CRÉANCES RATTACHÉES,,Actif,
|
||||||
|
261,Titres de participation,,Actif,
|
||||||
|
266,Autres formes de participation,,Actif,
|
||||||
|
267,Créances rattachées à des participations,,Actif,
|
||||||
|
269,Versements restants sur participations,,Actif,
|
||||||
|
27,IMMOBILISATIONS FINANCIÈRES,,Actif,
|
||||||
|
271,Titres immobilisés (droit de propriété),,Actif,
|
||||||
|
272,Titres immobilisés (droit de créance),,Actif,
|
||||||
|
274,Prêts,,Actif,
|
||||||
|
2742,Prêts aux partenaires,,Actif,
|
||||||
|
275,Dépôts et cautionnements versés,,Actif,
|
||||||
|
276,Autres créances immobilisées,,Actif,
|
||||||
|
28,AMORTISSEMENTS DES IMMOBILISATIONS,,Actif,
|
||||||
|
280,Amortissements des immobilisations incorporelles,,Actif,
|
||||||
|
2801,Amortissements frais d'établissement,,Actif,
|
||||||
|
2804,Amortissements donations temporaires d’usufruit,,Actif,
|
||||||
|
2805,"Amortissements brevets, licences, marques...",,Actif,
|
||||||
|
2806,Amortissements droit au bail,,Actif,
|
||||||
|
2808,Amortissements autres immo.incorporelles,,Actif,
|
||||||
|
2812,"Amortissements agencements, aménagements de terrains",,Actif,
|
||||||
|
28131,Amortissements bâtiments,,Actif,
|
||||||
|
28135,"Amortissements installations, agencements...",,Actif,
|
||||||
|
2814,Amt.constructions sur sol d'autrui,,Actif,
|
||||||
|
2815,"Amortissements installations techniques, matériel, outillage",,Actif,
|
||||||
|
28181,"Amortissements installations, agencements, aménagements",,Actif,
|
||||||
|
28182,Amortissements matériel de transport,,Actif,
|
||||||
|
28183,"Amortissement matériel de bureau, informatique",D’une valeur supérieure à 500€,Actif,
|
||||||
|
28184,Amortissements du mobilier,D’une valeur supérieure à 500€,Actif,
|
||||||
|
29,DÉPRÉCIATIONS DES IMMOBILISATIONS,,Actif,
|
||||||
|
2904,Donations temporaires d'usufruit,,Actif,
|
||||||
|
2905,"Brevets, licences, marques...",,Actif,
|
||||||
|
2906,Droit au bail,,Actif,
|
||||||
|
2908,Autres immobilisations incorporelles,,Actif,
|
||||||
|
2911,Terrains,,Actif,
|
||||||
|
2931,Immobilisations corporelles en cours,,Actif,
|
||||||
|
294,Biens reçus par legs ou donations à céder,,Actif,
|
||||||
|
2961,Titres de participations,,Actif,
|
||||||
|
2966,Autres formes de participations,,Actif,
|
||||||
|
2967,Créances rattachées à des participations,,Actif,
|
||||||
|
2971,Titres immobilisés (droit de propriété),,Actif,
|
||||||
|
2972,Titres immobilisés (droit de créance),,Actif,
|
||||||
|
2974,Prêts,,Actif,
|
||||||
|
2975,Dépôts et cautionnements versés,,Actif,
|
||||||
|
2976,Autres créances immobilisées,,Actif,
|
||||||
|
3,Classe 3 — Comptes de stocks,,Actif,
|
||||||
|
31,MATIÈRES PREMIÈRES ET FOURNITURES,,Actif,
|
||||||
|
318,Matières premières et fournitures,,Actif,
|
||||||
|
32,AUTRES APPROVISIONNEMENTS,,Actif,
|
||||||
|
321,Matières consommables,,Actif,
|
||||||
|
322,Fournitures consommables,,Actif,
|
||||||
|
326,Emballages,,Actif,
|
||||||
|
33,EN-COURS DE PRODUCTION DE BIENS,,Actif,
|
||||||
|
331,Produits en cours,,Actif,
|
||||||
|
335,Travaux en cours,,Actif,
|
||||||
|
34,En-cours de production de services,,Actif,
|
||||||
|
341,Études en cours,,Actif,
|
||||||
|
345,Prestations de services en cours,,Actif,
|
||||||
|
35,STOCKS DE PRODUITS,,Actif,
|
||||||
|
351,Produits intermédiaires,,Actif,
|
||||||
|
355,Produits finis,,Actif,
|
||||||
|
358,Produits résiduels,,Actif,
|
||||||
|
37,STOCKS DE MARCHANDISES,,Actif,
|
||||||
|
370,Stocks de marchandises,,Actif,
|
||||||
|
39,PROVISIONS POUR DÉPRÉCIATIONS STOCKS & EN-COURS,,Actif,
|
||||||
|
391,Matières premières et fournitures,,Actif,
|
||||||
|
392,Autres approvisionnements,,Actif,
|
||||||
|
393,En-cours de production de biens,,Actif,
|
||||||
|
394,En-cours de production de services,,Actif,
|
||||||
|
395,Stocks de produits,,Actif,
|
||||||
|
397,Stocks de marchandises,,Actif,
|
||||||
|
4,Classe 4 — Comptes de tiers,,Actif ou passif,
|
||||||
|
40,FOURNISSEURS ET COMPTES RATTACHÉS,,Actif ou passif,
|
||||||
|
401,Fournisseurs,,Actif ou passif,
|
||||||
|
4010,Autres fournisseurs,,Actif ou passif,Favori
|
||||||
|
403,Fournisseurs - Effets à payer,,Passif,
|
||||||
|
404,Fournisseurs d'immobilisations,,Actif ou passif,
|
||||||
|
405,Fournisseurs d'immobilisations - Effets à payer,,Passif,
|
||||||
|
408,Fournisseurs - Factures non parvenues,,Passif,
|
||||||
|
4091,Fournisseurs - Avances & acomptes,,Actif,
|
||||||
|
41,BÉNÉFICIAIRES ET COMPTES RATTACHÉS,,Actif ou passif,
|
||||||
|
410,Bénéficiaires et comptes rattachés,,Actif ou passif,
|
||||||
|
411,Bénéficiaires,,Actif ou passif,
|
||||||
|
4110,Autres bénéficiaires,Pour les dettes ou créances des membres,Actif ou passif,Favori
|
||||||
|
413,Bénéficiaires - Effets à recevoir,,Actif,
|
||||||
|
416,Bénéficiaires douteux ou litigieux,,Actif,
|
||||||
|
418,Bénéficiaires non encore facturés,,Actif,
|
||||||
|
419,Bénéficiaires créditeurs,,Passif,
|
||||||
|
4191,Bénéficiaires créditeurs : avances et acomptes,,Passif,
|
||||||
|
4198,"Rabais, remises, ristournes à accorder et autres avoirs à établir ",,Passif,
|
||||||
|
42,PERSONNEL ET COMPTES RATTACHÉS,,Actif ou passif,
|
||||||
|
421,Personnel : Rémunérations dues,,Passif,
|
||||||
|
4210,Autres membres du personnel,Dettes dues aux salarié⋅e⋅s,Actif ou passif,Favori
|
||||||
|
422,"Comités d'entreprise, d'établissement",,Actif ou passif,
|
||||||
|
425,Personnel : Avances & acomptes,,Actif,
|
||||||
|
427,Personnel - Oppositions,,Passif,
|
||||||
|
4286,Personnel- Charges à payer,,Passif,
|
||||||
|
4287,Personnel- Produits à recevoir,,Actif,
|
||||||
|
43,SÉCURITÉ SOCIALE & AUTRES ORGANISMES SOCIAUX,,Passif,
|
||||||
|
431,Sécurité sociale,,Passif,
|
||||||
|
4372,Mutuelles,,Passif,
|
||||||
|
4373,Caisses de retraites et de prévoyance,,Passif,
|
||||||
|
4378,Autres organismes sociaux,,Passif,
|
||||||
|
44,État ET AUTRES COLLECTIVITÉS PUBLIQUES,,Actif,
|
||||||
|
441,État - Subventions à recevoir,,Actif,
|
||||||
|
4421,Prélèvements à la source- Impôt sur le revenu,,Actif ou passif,
|
||||||
|
444,État - Impôts sur les bénéfices,,Actif ou passif,
|
||||||
|
4452,TVA due intracommunautaire,,Actif ou passif,
|
||||||
|
4455,Taxes sur CA à décaisser,,Actif,
|
||||||
|
44562,TVA déductible sur immobilisations,,Actif,
|
||||||
|
44566,TVA déductible sur autres biens et services,,Actif,
|
||||||
|
44571,TVA normale collectée,,Actif,
|
||||||
|
445711,TVA réduite collectée,,Actif,
|
||||||
|
445712,TVA super-réduite collectée,,Actif,
|
||||||
|
445713,TVA intermédiaire collectée,,Actif,
|
||||||
|
4458,Taxe sur CA à régulariser ou en attente,,Actif,
|
||||||
|
447,"Autres impôts, taxes et versements assimilés",,Actif,
|
||||||
|
4486,État - Charges à payer,,Passif,
|
||||||
|
4487,État - Produits à recevoir,,Actif,
|
||||||
|
45,"CONFÉDÉRATION, FÉDÉRATION, UNIONS, etc. AFFILIÉES",,Actif ou passif,
|
||||||
|
451,"Confédération, fédération et associations affiliées",,Actif ou passif,
|
||||||
|
455,Partenaires - comptes courants,,Actif ou passif,
|
||||||
|
46,DÉBITEURS DIVERS ET CREDIT.DVS,,Actif ou passif,
|
||||||
|
461,Créances reçues par legs ou donations,,Actif,
|
||||||
|
466,Dettes des legs ou donations,,Passif,
|
||||||
|
4671,Débiteurs divers,,Actif ou passif,
|
||||||
|
4672,Créditeurs divers,,Actif ou passif,
|
||||||
|
4681,Frais des bénévoles,,Actif ou passif,
|
||||||
|
4686,Divers - Charges à payer,,Passif,
|
||||||
|
4687,Divers - Produits à recevoir,,Actif,
|
||||||
|
47,COMPTES D'ATTENTE,,Actif ou passif,
|
||||||
|
4715,Compte de transit,,Actif ou passif,
|
||||||
|
4718,Compte d'attente,,Actif ou passif,
|
||||||
|
48,COMPTES DE RÉGULARISATION,,Actif ou passif,
|
||||||
|
481,Charges à répartir,,Passif,
|
||||||
|
486,Charges constatées d'avance,,Actif,
|
||||||
|
487,Produits constatés d'avance,,Passif,
|
||||||
|
49,DÉPRÉCIATIONS DES COMPTES DE TIERS,,Actif ou passif,
|
||||||
|
491,Provisions pour dépréciation des comptes d'usagers,,Passif,
|
||||||
|
496,Provisions pour dépréciations des comptes débiteurs divers,,Passif,
|
||||||
|
5,Classe 5 — Comptes financiers,,Actif,
|
||||||
|
50,VALEURS MOBILIÈRES DE PLACEMENT,,Actif,
|
||||||
|
503,Actions,,Actif,
|
||||||
|
506,Obligations,,Actif,
|
||||||
|
508,Autres valeurs mobilières de placement et créances assimilées,,Actif,
|
||||||
|
51,"BANQUES, ÉTABLISSEMENTS FINANCIERS",,Actif,
|
||||||
|
5112,Chèques à encaisser,,Actif ou passif,Favori
|
||||||
|
5115,Paiements par carte à encaisser,,Actif ou passif,
|
||||||
|
512,Banques,,Actif ou passif,
|
||||||
|
512A,Compte courant Fonctionnement,,Actif ou passif,Favori
|
||||||
|
512B,Compte courant Œuvres Sociales,,Actif ou passif,Favori
|
||||||
|
5186,Intérêts courus à payer,,Passif,
|
||||||
|
5187,Intérêts courus à recevoir,,Actif,
|
||||||
|
53,Caisses,,Actif ou passif,
|
||||||
|
530,Caisse,,Actif ou passif,Favori
|
||||||
|
58,VIREMENTS INTERNES,,Actif ou passif,
|
||||||
|
580,Virements internes,,Actif ou passif,
|
||||||
|
59,DÉPRÉCIATIONS DES COMPTES FINANCIERS,,Actif ou passif,
|
||||||
|
5903,Actions,,Actif ou passif,
|
||||||
|
5906,Obligations,,Actif ou passif,
|
||||||
|
5908,Autres valeurs mobilières de placement et créances assimilées,,Actif ou passif,
|
||||||
|
6,Classe 6 — Comptes de charges,,Charge,
|
||||||
|
60,ACHATS (SAUF 603),,Charge,
|
||||||
|
601,Achats stockés - Matières premières et fournitures,,Charge,
|
||||||
|
6010,Achats stockés de matières et fournitures,,Charge,
|
||||||
|
6011,Achats stockés - Matières premières,,Charge,
|
||||||
|
6017,Achats stockés - Fournitures,,Charge,
|
||||||
|
602,Achats stockés - Autres approvisionnements,,Charge,
|
||||||
|
6021,Achats stockés - Matières consommables,,Charge,
|
||||||
|
60221,Achats stockés - Combustibles,,Charge,
|
||||||
|
60222,Achats stockés - Produits d'entretien,,Charge,
|
||||||
|
60223,Achats stockés - Fournitures d'atelier,,Charge,
|
||||||
|
60224,Achats stockés - Fournitures de magasin,,Charge,
|
||||||
|
60225,Fournitures de bureau,,Charge,
|
||||||
|
6026,Achats stockés - Emballages,,Charge,
|
||||||
|
603,Variations de stocks,,Charge,
|
||||||
|
6031,Variations de stocks matières & fournitures,,Charge,
|
||||||
|
6032,Variations stocks autres approvisionnements,,Charge,
|
||||||
|
6037,Variations de stocks de marchandises,,Charge,
|
||||||
|
604,Achats d'études et prestations de services,,Charge,
|
||||||
|
605,"Achats matériel, équipements & travaux",,Charge,
|
||||||
|
606,Achats non stockés de matières et fournitures,,Charge,Favori
|
||||||
|
6061,"Fournitures non stockables (eau, énergie...)","Facture d'eau, d’électricité, etc.",Charge,Favori
|
||||||
|
60611,Eau,,Charge,Favori
|
||||||
|
60612,Électricité,,Charge,Favori
|
||||||
|
60613,Chauffage,,Charge,Favori
|
||||||
|
6063,Fournitures d'entretien et petit équipement,"Vis, et matériel de bricolage (sauf outils) par exemple",Charge,Favori
|
||||||
|
6064,Fournitures administratives,"Cartouches d'encre, papier, matériel bureautique, etc.",Charge,Favori
|
||||||
|
6065,Petits logiciels,Par exemple contribution à un logiciel de gestion associative génial :-),Charge,Favori
|
||||||
|
6068,Autres fournitures & matières,,Charge,Favori
|
||||||
|
607,Achats de marchandises,Marchandises destinées à être revendues en l'état.,Charge,Favori
|
||||||
|
608,Frais accessoires d'achats,,Charge,
|
||||||
|
60811,Frais accessoires d'achats sur matières,,Charge,
|
||||||
|
60817,Frais accessoires d'achats sur fournitures,,Charge,
|
||||||
|
609,"Rabais, remises et ristournes sur achats",,Charge,
|
||||||
|
6091,"Rabais, remises, ristournes sur achats matières et fournitures",,Charge,
|
||||||
|
6092,"Rabais, remises, ristournes sur achats et autres approvisionnements",,Charge,
|
||||||
|
6097,"Rabais, remises, ristournes sur achats de marchandises",,Charge,
|
||||||
|
61,SERVICES EXTÉRIEURS,,Charge,
|
||||||
|
611,Sous-traitance générale,,Charge,
|
||||||
|
6122,Redevance crédit-bail mobilier,,Charge,
|
||||||
|
6125,Redevances crédit-bail immobilier,,Charge,
|
||||||
|
6132,Locations immobilières,Locations versées pour un local ou du matériel.,Charge,Favori
|
||||||
|
6135,Locations mobilières,,Charge,
|
||||||
|
6136,Malis sur emballages,,Charge,
|
||||||
|
614,Charges locatives et de copropriété,,Charge,
|
||||||
|
6152,Entretien sur biens immobiliers,,Charge,
|
||||||
|
6155,Entretien sur biens mobiliers,,Charge,
|
||||||
|
6156,Maintenance,,Charge,
|
||||||
|
616,Primes d'assurance,"Frais d’assurance local, activité, etc.",Charge,Favori
|
||||||
|
6161,Primes d'assurances multirisques,,Charge,
|
||||||
|
6164,Primes d'assurances / risques d'exploitation,,Charge,
|
||||||
|
6165,Primes d'assurances / insolvabilité usagers,,Charge,
|
||||||
|
6168,Autres assurances,,Charge,
|
||||||
|
617,Etudes et recherches,,Charge,
|
||||||
|
6181,Documentation générale,,Charge,
|
||||||
|
6183,Documentation technique,,Charge,
|
||||||
|
6185,"Frais de colloques, séminaires, conférences",,Charge,
|
||||||
|
6187,Prestations administratives,,Charge,
|
||||||
|
62,AUTRES SERVICES EXTÉRIEURS,,Charge,
|
||||||
|
621,Personnel extérieur à l'association,,Charge,
|
||||||
|
6211,Personnel intérimaire,,Charge,
|
||||||
|
6214,Personnel détaché ou prêté à l'association,,Charge,
|
||||||
|
62141,Mises à disposition de personnel salarié,Frais de mise à disposition via un groupement d’employeurs,Charge,Favori
|
||||||
|
622,Rémunérations d'intermédiaires et honoraires,,Charge,
|
||||||
|
6221,Commissions ... sur achats,,Charge,
|
||||||
|
6222,Commissions... sur ventes,,Charge,
|
||||||
|
6226,Honoraires,,Charge,
|
||||||
|
62264,Honoraires sur legs ou donations à céder,,Charge,
|
||||||
|
6227,Frais d'actes et de contentieux,,Charge,
|
||||||
|
6228,Rémunérations divers intermédiaires & honoraires,,Charge,
|
||||||
|
623,"Publicité, publications, relations publiques","Bulletins, affiches, communication, etc.",Charge,Favori
|
||||||
|
6231,Annonces et insertions,,Charge,
|
||||||
|
6232,Fêtes et cérémonies,,Charge,
|
||||||
|
6233,Foires et expositions,,Charge,
|
||||||
|
6234,Cadeaux,,Charge,
|
||||||
|
6236,Catalogues et imprimés,,Charge,
|
||||||
|
6237,Publications,,Charge,
|
||||||
|
6238,"Divers : pourboires, dons courants",,Charge,
|
||||||
|
624,Transports de biens...,,Charge,
|
||||||
|
6241,Transports sur achats,,Charge,
|
||||||
|
6242,Transports sur ventes,,Charge,
|
||||||
|
6243,Transports entre établissements,,Charge,
|
||||||
|
6244,Transports administratifs,,Charge,
|
||||||
|
6247,Transports collectifs du personnel,,Charge,
|
||||||
|
6248,Transports divers,,Charge,
|
||||||
|
625,"Déplacements, missions et réceptions","Billet de train, remboursement de frais kilométrique, etc.",Charge,Favori
|
||||||
|
6251,Voyages et déplacements,,Charge,
|
||||||
|
6255,Frais de déménagement,,Charge,
|
||||||
|
6256,Frais de missions,,Charge,
|
||||||
|
6257,"Frais de réceptions, représentations",,Charge,
|
||||||
|
626,Frais postaux et de télécommunications,"Facture d'accès à Internet, timbres, etc.",Charge,Favori
|
||||||
|
6261,Liaisons spécialisées,,Charge,
|
||||||
|
6263,"Affranchissements, frais postaux",,Charge,
|
||||||
|
6265,Téléphone,,Charge,
|
||||||
|
627,Services bancaires et assimilés,Frais bancaires,Charge,Favori
|
||||||
|
628,Divers,,Charge,Favori
|
||||||
|
6281,Cotisations (liées à l'activité économique),,Charge,
|
||||||
|
6284,Frais de recrutement du personnel,,Charge,
|
||||||
|
63,"IMPÔTS, TAXES ET VERSEMENTS ASSIMILÉS",,Charge,
|
||||||
|
631,Sur rémunérations - administration des impôts,,Charge,
|
||||||
|
6311,Taxe sur les salaires,,Charge,
|
||||||
|
633,Sur rémunérations - autres organismes,,Charge,
|
||||||
|
6331,Versement de transport,,Charge,
|
||||||
|
6332,Allocation logement,,Charge,
|
||||||
|
6333,Formation professionnelle continue,,Charge,
|
||||||
|
6334,Participations employeurs à l'effort de construction,,Charge,
|
||||||
|
635,Autres - Administration des impôts,,Charge,
|
||||||
|
63512,Taxes foncières,,Charge,
|
||||||
|
63513,Autres impôts locaux,,Charge,
|
||||||
|
6354,Droits d'enregistrement et de timbre,,Charge,
|
||||||
|
637,Autres - Autres organismes,,Charge,
|
||||||
|
64,CHARGES DE PERSONNEL,,Charge,
|
||||||
|
641,Rémunérations du personnel,,Charge,
|
||||||
|
6411,"Salaires, appointements",,Charge,
|
||||||
|
6412,Congés payés,,Charge,
|
||||||
|
6413,Primes et gratifications,,Charge,
|
||||||
|
6414,Indemnités et avantages divers,,Charge,
|
||||||
|
6415,Supplément familial,,Charge,
|
||||||
|
645,Charges de sécurité sociale et de prévoyance,,Charge,
|
||||||
|
6451,Cotisations à l'URSSAF,,Charge,
|
||||||
|
6452,Cotisations aux mutuelles,,Charge,
|
||||||
|
6453,Cotisations caisses de retraites et de prévoyance,,Charge,
|
||||||
|
6458,Cotisations aux autres organismes sociaux,,Charge,
|
||||||
|
647,Autres charges sociales,,Charge,
|
||||||
|
6472,Versements aux comités d'entreprise et d'établissement,,Charge,
|
||||||
|
6473,Versement aux comités d'hygiène et de sécurité,,Charge,
|
||||||
|
6474,Versements aux autres œuvres sociales,,Charge,
|
||||||
|
6475,"Médecine du travail, pharmacie",,Charge,
|
||||||
|
648,Autres charges de personnel,,Charge,
|
||||||
|
6481,Indemnités du personnel de culte,,Charge,
|
||||||
|
6485,Charges sociales sur indemnités de culte,,Charge,
|
||||||
|
6488,Autres charges de personnel,,Charge,
|
||||||
|
65,AUTRES CHARGES DE GESTION COURANTE,,Charge,
|
||||||
|
6511,"Redevances pour concessions, brevets, licences",,Charge,
|
||||||
|
6516,Droits d'auteur et de reproduction,,Charge,
|
||||||
|
6518,Autres droits et valeurs similaires,,Charge,
|
||||||
|
652,Licences fédérales,Licences payées pour les adhérents (par exemple fédération sportive etc.),Charge,Favori
|
||||||
|
653,Charges de la générosité du public,,Charge,
|
||||||
|
6531,Autres charges sur legs ou donations,,Charge,
|
||||||
|
654,Pertes sur créances irrécouvrables,,Charge,
|
||||||
|
655,Quotes-parts sur opérations faites en commun,,Charge,
|
||||||
|
657,Aides financières,,Charge,
|
||||||
|
6571,Aides financières octroyées,,Charge,
|
||||||
|
6572,Quotes-parts de générosité reversée,,Charge,
|
||||||
|
658,Charges diverses de gestion courante,,Charge,Favori
|
||||||
|
6586,Cotisations (vie statutaire),,Charge,
|
||||||
|
6588,Charges diverses de gestion courante,,Charge,
|
||||||
|
66,CHARGES FINANCIÈRES,,Charge,
|
||||||
|
661,Charges d'intérêts,,Charge,
|
||||||
|
665,Escomptes accordés,,Charge,
|
||||||
|
666,Pertes de changes,,Charge,
|
||||||
|
667,Charges nettes sur cessions de valeurs mobilières de placement,,Charge,
|
||||||
|
668,Autres charges financières,,Charge,
|
||||||
|
67,Charges exceptionnelles,,Charge,
|
||||||
|
670,Charges exceptionnelles,Autres dépenses exceptionnelles,Charge,Favori
|
||||||
|
6712,"Pénalités, amendes fiscales et pénales",,Charge,
|
||||||
|
6713,"Dons, libéralités",,Charge,
|
||||||
|
6714,Créances devenues irrécouvrables,,Charge,
|
||||||
|
6718,Autres charges exceptionnelles de gestion,,Charge,
|
||||||
|
673,Apports ou affectations en numéraire,,Charge,
|
||||||
|
675,Valeurs comptables des éléments d'actifs cédés,,Charge,
|
||||||
|
6750,Valeurs comptables des actifs cédés,,Charge,
|
||||||
|
6754,Immobilisations reçues par legs ou donations,,Charge,
|
||||||
|
678,Autres charges exceptionnelles sur opération en capital,,Charge,
|
||||||
|
68,"Dotation AUX AMORTISSEMENTS, DÉPRÉCIATIONS ET ENGAGEMENTS",,Charge,
|
||||||
|
6811,Dotation aux amortissements des immobilisations,,Charge,
|
||||||
|
6812,Dotation aux amortissements charges à répartir,,Charge,
|
||||||
|
6815,Dotation aux provisions d'exploitation,,Charge,
|
||||||
|
6816,Dotation provisions pour dépréciations des immobillisations,,Charge,
|
||||||
|
68164,Dotation pr dépréc. d’actifs reçus par legs ou donations,,Charge,
|
||||||
|
6817,Dotation aux dépréciations des actifs circulants,,Charge,
|
||||||
|
68173,Dotations dépréciations stocks et en-cours,,Charge,
|
||||||
|
68174,Dotations dépréciations créances,,Charge,
|
||||||
|
686,Dotation aux amortissements & Provisions - Charges financières,,Charge,
|
||||||
|
68662,Dotation aux amortissements & provisions immobilisations financières,,Charge,
|
||||||
|
68665,Dotation aux amortissements & provisions valeurs mobilières de placement,,Charge,
|
||||||
|
687,Dotation aux amortissements & Provisions - Charges exceptionnelles,,Charge,
|
||||||
|
689,Reports en fonds dédiés,,Charge,
|
||||||
|
6891,Reports en fonds reportés,,Charge,
|
||||||
|
6894,Reports en fonds dédiés / subventions d’exploitation,,Charge,
|
||||||
|
6895,Reports en fonds dédiés / contributions financières d'autres organismes,,Charge,
|
||||||
|
6896,Reports en fonds dédiés / ressources générosité,,Charge,
|
||||||
|
69,IMPÔTS SUR LES BÉNÉFICES,,Charge,
|
||||||
|
695,Impôts sur les bénéfices,,Charge,
|
||||||
|
7,Classe 7 — Comptes de produits,,Produit,
|
||||||
|
70,"VENTES PROD.FINIS, MARCHANDISES, PRESTATIONS",,Produit,
|
||||||
|
701,Ventes de produits finis,Vente de produits fabriqués par l'association.,Produit,Favori
|
||||||
|
702,Ventes de produits intermédiaires,,Produit,
|
||||||
|
703,Ventes de produits résiduels,,Produit,
|
||||||
|
704,Travaux,,Produit,
|
||||||
|
705,Études,,Produit,Favori
|
||||||
|
706,Prestations de services,,Produit,Favori
|
||||||
|
7063,Parrainages,,Produit,
|
||||||
|
707,Ventes de marchandises,Ventes de produits achetés et revendus en l’état,Produit,Favori
|
||||||
|
7073,Ventes de dons en nature,,Produit,
|
||||||
|
708,Produits des activités annexes,,Produit,
|
||||||
|
7081,Produits des services exploités dans l’intérêt du personnel,,Produit,
|
||||||
|
7083,Locations diverses,,Produit,
|
||||||
|
7085,Ports et frais accessoires facturés,,Produit,
|
||||||
|
7088,Autres produits d'activités annexes,,Produit,
|
||||||
|
709,"Rabais, remises, ristournes accordés",,Produit,
|
||||||
|
7091,"Rabais, remises, ristournes sur ventes de produits finis",,Produit,
|
||||||
|
7092,"Rabais, remises, ristournes sur ventes de produits intermédiaires",,Produit,
|
||||||
|
7094,"Rabais, remises, ristournes sur travaux",,Produit,
|
||||||
|
7095,"Rabais, remises, ristournes sur études",,Produit,
|
||||||
|
7096,"Rabais, remises, ristournes sur prest.de services",,Produit,
|
||||||
|
7097,"Rabais, remises, ristournes sur ventes marchandises",,Produit,
|
||||||
|
71,PRODUCTION STOCKÉE,,Produit,
|
||||||
|
713,"Variation de stocks (en-cours, productions)",,Produit,
|
||||||
|
7133,Variation des en-cours de production de biens,,Produit,
|
||||||
|
7134,Variation des en-cours de production services,,Produit,
|
||||||
|
7135,Variations de stocks de produits,,Produit,
|
||||||
|
72,PRODUCTION IMMOBILISÉE,,Produit,
|
||||||
|
721,Production immobilisée incorporelle,,Produit,
|
||||||
|
722,Production immobilisée corporelle,,Produit,
|
||||||
|
73,CONCOURS PUBLICS,,Produit,
|
||||||
|
730,Concours publics,,Produit,
|
||||||
|
74,SUBVENTION D'EXPLOITATION,,Produit,
|
||||||
|
740,Subventions reçues,,Produit,Favori
|
||||||
|
7403,Autres subventions,,Produit,Favori
|
||||||
|
748,Subventions d'exploitation diverses,,Produit,
|
||||||
|
75,AUTRES PRODUITS DE GESTION COURANTE,,Produit,
|
||||||
|
751,"Redevances pour concessions, licences...",,Produit,
|
||||||
|
753,Versements des fondateurs ou consommation dot,,Produit,
|
||||||
|
7531,Versements des fondateurs,,Produit,
|
||||||
|
7532,Quotes-parts de dotation consomptible virée a,,Produit,
|
||||||
|
754,Ressources liées à la générosité du public,Dons reçus,Produit,Favori
|
||||||
|
7541,Dons manuels,,Produit,
|
||||||
|
75411,Dons manuels,,Produit,
|
||||||
|
75412,Abandons de frais par les bénévoles,,Produit,
|
||||||
|
7542,Mécénats,,Produit,
|
||||||
|
7543,"Legs, donations et assurances-vie",,Produit,
|
||||||
|
75431,Assurances-vie,,Produit,
|
||||||
|
75432,Legs ou donations,,Produit,
|
||||||
|
75433,Autres produits sur legs ou donations,,Produit,
|
||||||
|
755,Contributions financières,,Produit,
|
||||||
|
7551,Contributions financières d’autres organismes,,Produit,
|
||||||
|
7552,Quotes-parts de générosité reçues,,Produit,
|
||||||
|
756,Cotisations,Cotisations des adhérent⋅e⋅s,Produit,Favori
|
||||||
|
7561,Cotisations sans contrepartie,,Produit,
|
||||||
|
7562,Cotisations avec contrepartie,,Produit,
|
||||||
|
756201,Subvention de fonctionnement reçue l'employeur,Produits affectés à la section « Attributions économiques et professionnelles »,Produit,Favori
|
||||||
|
756202,Contribution reçue de l'employeur,Produits affectés à la section « Activités sociales et culturelles »,Produit,Favori
|
||||||
|
757,Gains de change / créances et dettes d’exploitation,,Produit,
|
||||||
|
758,Produits divers de gestion courante,,Produit,
|
||||||
|
7588,Autres produits divers de gestion courante,,Produit,
|
||||||
|
76,PRODUITS FINANCIERS,,Produit,
|
||||||
|
761,Produits des participations,,Produit,
|
||||||
|
762,Produits des autres immobilisations financières,,Produit,
|
||||||
|
763,Revenus des autres créances,,Produit,
|
||||||
|
764,Revenus des valeurs mobilières de placement,,Produit,
|
||||||
|
765,Escomptes obtenus,,Produit,
|
||||||
|
766,Gains de change,,Produit,
|
||||||
|
767,Produits nets sur cession valeurs mobilières de placement,,Produit,
|
||||||
|
768,Autres produits financiers,,Produit,
|
||||||
|
77,PRODUITS EXCEPTIONNELS,,Produit,
|
||||||
|
771,Produits exceptionnels sur opération de gestion,,Produit,
|
||||||
|
7713,Libéralités perçues,,Produit,
|
||||||
|
7718,Autres produits exceptionnels sur opération de gestion,,Produit,
|
||||||
|
775,Produits des cessions d'actif,,Produit,
|
||||||
|
7754,Immobilisations reçues en legs ou donations à céder,,Produit,
|
||||||
|
777,Quote-part subvention d'investissement virée au résultat,,Produit,
|
||||||
|
778,Autres produits exceptionnels,,Produit,
|
||||||
|
7780,Manifestations diverses,"Revenus provenant de manifestations au profit de l'association : droit d'entrée, location d'emplacement en vide grenier, ventes, etc.",Produit,Favori
|
||||||
|
78,"REPRISES SUR AMORTISSEMENTS, DÉPRÉCIATIONS, ENGAGEMENTS",,Produit,
|
||||||
|
781,Reprises / Amortissements & Provisions d'exploitation,,Produit,
|
||||||
|
7811,Amortissements immobilisations corporelles & incorporelles,,Produit,
|
||||||
|
7815,Reprises sur provisions d'exploitation,,Produit,
|
||||||
|
7816,Dépréciations immobilisations corporelles & incorporelles,,Produit,
|
||||||
|
78164,Reprises dépréciations d’actifs reçus par legs ou donations destinés à être cédés,,Produit,
|
||||||
|
7817,Dépréciations actifs circulant,,Produit,
|
||||||
|
786,Reprises sur provisions pour risques et dépréciations ,À inscrire dans les produits exceptionnels,Produit,
|
||||||
|
7865,Risques & charges financiers,,Produit,
|
||||||
|
7866,Déprec.des éléments financiers,,Produit,
|
||||||
|
787, Reprises sur provisions pour risques et dépréciations,À inscrire dans les produits exceptionnels,Produit,
|
||||||
|
7872,Provisions réglementées - Immobilisations,,Produit,
|
||||||
|
7873,Provisions réglementées - stocks,,Produit,
|
||||||
|
7874,Autres provisions réglementées,,Produit,
|
||||||
|
7875,Risques et charges,,Produit,
|
||||||
|
7876,Dépréciations exceptionnelles,,Produit,
|
||||||
|
789,Utilisations fonds reportés et de fonds dédiés,,Produit,
|
||||||
|
7891,Utilisations de fonds reportés,,Produit,
|
||||||
|
7894,Utilisations des fonds dédiés / subventions,,Produit,
|
||||||
|
7895,Utilisations des fonds dédiés / contributions,,Produit,
|
||||||
|
7896,Utilisations des fonds dédiés / générosité,,Produit,
|
||||||
|
79,TRANSFERT DE CHARGES,,Produit,
|
||||||
|
791,Transferts de charges d'exploitation,,Produit,
|
||||||
|
796,Transferts de charges financières,,Produit,
|
||||||
|
797,Transferts de charges exceptionnelles,,Produit,
|
||||||
|
8,Classe 8 — Comptes spéciaux,,,
|
||||||
|
80,ENGAGEMENTS,,,
|
||||||
|
801,Engagements donnés par l’entité,,,
|
||||||
|
8011,"Avals, cautions, garanties",,,
|
||||||
|
8014,Effets circulant sous l’endos de l’entité,,,
|
||||||
|
8016,Redevances crédit-bail restant à courir,,,
|
||||||
|
80161,Crédit-bail mobilier,,,
|
||||||
|
80165,Crédit-bail immobilier,,,
|
||||||
|
8018,Autres engagements donnés,,,
|
||||||
|
802,Engagements reçus par l’entité,,,
|
||||||
|
8021,"Avals, cautions, garanties",,,
|
||||||
|
8024,Créances escomptées non échues,,,
|
||||||
|
8026,Engagements reçus pour utilisation en crédit-bail,,,
|
||||||
|
80261,Crédit-bail mobilier,,,
|
||||||
|
80265,Crédit-bail immobilier,,,
|
||||||
|
8028,Autres engagements reçus,,,
|
||||||
|
809,Contrepartie des engagements,,,
|
||||||
|
8091,Contrepartie 801,,,
|
||||||
|
8092,Contrepartie 802,,,
|
||||||
|
86,EMPLOI DES CONTRIBUTIONS VOLONTAIRES EN NATURE,,,
|
||||||
|
860,"Secours en nature (alimentaires, vestimentaires…)",,Charge,
|
||||||
|
861,"Mise à disposition gratuite de biens (locaux, matériels…)",,Charge,
|
||||||
|
862,Prestations,,Charge,
|
||||||
|
864,Personnel bénévole,,Charge,
|
||||||
|
87,CONTRIBUTIONS VOLONTAIRES EN NATURE,,,
|
||||||
|
870,Bénévolat,,Produit,
|
||||||
|
871,Prestations en nature,,Produit,
|
||||||
|
875,Dons en nature,,Produit,
|
||||||
|
89,COMPTES DE BILAN,,,
|
||||||
|
890,Bilan d'ouverture,,Actif ou passif,
|
||||||
|
891,Bilan de clôture,,Actif ou passif,
|
|
295
src/include/data/charts/fr_pca_1999.csv
Normal file
295
src/include/data/charts/fr_pca_1999.csv
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
code,label,description,position,bookmark
|
||||||
|
1,"Classe 1 — Comptes de capitaux (Fonds propres, emprunts et dettes assimilés)",,Passif,
|
||||||
|
10,FONDS ASSOCIATIFS ET RÉSERVES,,Passif,
|
||||||
|
102,Fonds associatif sans droit de reprise,,Passif,
|
||||||
|
1021,Valeur du patrimoine intégré,,Passif,
|
||||||
|
1022,Fonds statutaire,,Passif,
|
||||||
|
1024,Apports sans droit de reprise,,Passif,
|
||||||
|
103,Fonds associatif avec droit de reprise,,Passif,
|
||||||
|
1034,Apports avec droit de reprise,,Passif,
|
||||||
|
105,Écarts de réévaluation,,Passif,
|
||||||
|
106,Réserves,,Passif,
|
||||||
|
1063,Réserves statutaires ou contractuelles,,Passif,
|
||||||
|
1064,Réserves réglementées,,Passif,
|
||||||
|
1068,Autres réserves (dont réserves pour projet associatif),,Passif,
|
||||||
|
11,REPORT À NOUVEAU,,Passif,
|
||||||
|
110,Report à nouveau (Solde créditeur),,Passif,
|
||||||
|
119,Report à nouveau (Solde débiteur),,Passif,
|
||||||
|
12,RÉSULTAT NET DE L'EXERCICE,,Passif,
|
||||||
|
120,Résultat de l'exercice (excédent),,Passif,
|
||||||
|
129,Résultat de l'exercice (déficit),,Passif,
|
||||||
|
13,SUBVENTIONS D'INVESTISSEMENT AFFECTÉES A DES BIENS NON RENOUVELABLES,,Passif,
|
||||||
|
131,Subventions d'investissement (renouvelables),,Passif,
|
||||||
|
139,Subventions d'investissement inscrites au compte de résultat,,Passif,
|
||||||
|
14,PROVISIONS REGLEMENTÉES,,Passif,
|
||||||
|
15,PROVISIONS,,Passif,
|
||||||
|
151,Provisions pour risques,,Passif,
|
||||||
|
157,Provisions pour charges à répartir sur plusieurs exercices,,Passif,
|
||||||
|
158,Autres provisions pour charges,,Passif,
|
||||||
|
16,EMPRUNTS ET DETTES ASSIMILÉES,,Passif,
|
||||||
|
164,Emprunts auprès des établissements de crédits,,Passif,
|
||||||
|
165,Dépôts et cautionnements reçus,,Passif,
|
||||||
|
167,Emprunts et dettes assorties de conditions particulières,,Passif,
|
||||||
|
168,Autres emprunts et dettes assimilés,,Passif,
|
||||||
|
17,DETTES RATTACHÉES À DES PARTICIPATIONS,,Passif,
|
||||||
|
18,COMPTES DE LIAISON DES ÉTABLISSEMENTS,,Passif,
|
||||||
|
181,Apports permanents entre siège social et établissements,,Passif,
|
||||||
|
185,Biens et prestations de services échangés entre établissements et siège social,,Passif,
|
||||||
|
186,Biens et prestations de services échangés entre établissements (charges),,Passif,
|
||||||
|
187,Biens et prestations de services échangés entre établissements (produits),,Passif,
|
||||||
|
19,FONDS DÉDIÉS,,Passif,
|
||||||
|
194,Fonds dédiés sur subventions de fonctionnement,,Passif,
|
||||||
|
195,Fonds dédiés sur dons manuels affectés,,Passif,
|
||||||
|
197,Fonds dédiés sur legs et donations affectés,,Passif,
|
||||||
|
198,Excédent disponible après affectation au projet associatif,,Passif,
|
||||||
|
199,Reprise des fonds affectés au projet associatif,,Passif,
|
||||||
|
2,Classe 2 — Comptes d'immobilisations,,Actif,
|
||||||
|
20,IMMOBILISATIONS INCORPORELLES,,Actif,
|
||||||
|
200,Immobilisations incorporelles,,Actif,
|
||||||
|
21,IMMOBILISATIONS CORPORELLES,,Actif,
|
||||||
|
210,Investissements,,Actif,
|
||||||
|
22,IMMOBILISATIONS GREVÉES DE DROITS,,Actif,
|
||||||
|
228,Immobilisations grevées de droits,,Actif,
|
||||||
|
229,Droits des propriétaires,,Actif,
|
||||||
|
23,IMMOBILISATIONS EN COURS,,Actif,
|
||||||
|
231,Immobilisations corporelles en cours,,Actif,
|
||||||
|
238,Avances et acomptes versés sur commande d'immobilisations corporelles,,Actif,
|
||||||
|
26,PARTICIPATIONS ET CRÉANCES RATTACHÉES A DES PARTICIPATIONS,,Actif,
|
||||||
|
261,Titres de participation,,Actif,
|
||||||
|
27,AUTRES IMMOBILISATIONS FINANCIÈRES,,Actif,
|
||||||
|
270,Participations financières,,Actif,
|
||||||
|
275,Dépôts et cautionnements versés,,Actif,
|
||||||
|
28,AMORTISSEMENTS DES IMMOBILISATIONS,,Actif,
|
||||||
|
280,Amortissements des immobilisations incorporelles,,Actif,
|
||||||
|
281,Amortissements des immobilisations corporelles,,Actif,
|
||||||
|
29,DÉPRÉCIATION DES IMMOBILISATIONS,,Actif,
|
||||||
|
290,Dépréciation des immobilisations incorporelles,,Actif,
|
||||||
|
291,Dépréciation des immobilisations corporelles,,Actif,
|
||||||
|
3,Classe 3 — Comptes de stocks,,Actif,
|
||||||
|
31,MATIERES PREMIERES ET FOURNITURES,,Actif,
|
||||||
|
311,Matières,,Actif,
|
||||||
|
317,Fournitures,,Actif,
|
||||||
|
32,AUTRES APPROVISIONNEMENTS,,Actif,
|
||||||
|
321,Matières consommables,,Actif,
|
||||||
|
322,Fournitures consommables,,Actif,
|
||||||
|
33,EN-COURS DE PRODUCTION DE BIENS,,Actif,
|
||||||
|
331,Produits en cours,,Actif,
|
||||||
|
335,Travaux en cours,,Actif,
|
||||||
|
34,EN-COURS DE PRODUCTION DE SERVICES,,Actif,
|
||||||
|
35,STOCKS DE PRODUITS,,Actif,
|
||||||
|
351,Produits intermédiaires,,Actif,
|
||||||
|
355,Produits finis,,Actif,
|
||||||
|
358,Produits résiduels,,Actif,
|
||||||
|
3581,Déchets,,Actif,
|
||||||
|
3585,Rebuts,,Actif,
|
||||||
|
3586,Matière de récupération,,Actif,
|
||||||
|
37,STOCKS DE MARCHANDISES,,Actif,
|
||||||
|
370,Autres stocks de marchandises,,Actif,
|
||||||
|
39,PROVISIONS POUR DEPRECIATION DES STOCKS ET EN-COURS,,Actif,
|
||||||
|
391,Provisions pour dépréciation des matières premières et fournitures,,Actif,
|
||||||
|
4,Classe 4 — Comptes de tiers,,Actif ou passif,
|
||||||
|
40,FOURNISSEURS ET COMPTES RATTACHÉS,,Passif,
|
||||||
|
401,Fournisseurs,,Passif,
|
||||||
|
4010,Autres fournisseurs,,Actif ou passif,Favori
|
||||||
|
408,Fournisseurs - Factures non parvenues,,Passif,
|
||||||
|
409,Avances aux fournisseurs,,Actif,
|
||||||
|
41,USAGERS ET COMPTES RATTACHÉS,,Actif,
|
||||||
|
411,Usagers,,Actif,
|
||||||
|
4110,Autres usagers,,Actif ou passif,Favori
|
||||||
|
419,Avances aux usagers,,Passif,
|
||||||
|
42,PERSONNEL ET COMPTES RATTACHÉS,,Passif,
|
||||||
|
421,Personnel - Rémunérations dues,,Passif,
|
||||||
|
4210,Autres membres du personnel,,Actif ou passif,
|
||||||
|
425,Personnel - Avances et acomptes,,Actif,
|
||||||
|
428,Personnel - Charges à payer et produits à recevoir,,Actif ou passif,
|
||||||
|
43,SÉCURITÉ SOCIALE ET AUTRES ORGANISMES SOCIAUX,,Passif,
|
||||||
|
430,Dettes et crédits envers les organismes sociaux,,Passif,
|
||||||
|
431,Sécurité sociale,,Passif,
|
||||||
|
437,Autres organismes sociaux,,Passif,
|
||||||
|
4372,Mutuelles,,Passif,
|
||||||
|
4373,Caisse de retraite et de prévoyance,,Passif,
|
||||||
|
4374,Caisse d'allocations de chômage - Pôle emploi,,Passif,
|
||||||
|
4375,AGESSA,,Passif,
|
||||||
|
4378,Autres organismes sociaux - Divers,,Passif,
|
||||||
|
438,Organismes sociaux - Charges à payer et produits à recevoir,,Actif ou passif,
|
||||||
|
4382,Charges sociales sur congés à payer,,Passif,
|
||||||
|
4386,Autres charges à payer,,Passif,
|
||||||
|
4387,Produits à recevoir,,Actif,
|
||||||
|
439,Avances auprès des organismes sociaux,,Passif,
|
||||||
|
44,ÉTAT ET AUTRES COLLECTIVITÉS PUBLIQUES,,Actif,
|
||||||
|
441,État - Subventions à recevoir,,Actif,
|
||||||
|
4411,Subventions d'investissement,,Actif,
|
||||||
|
4417,Subventions d'exploitation,,Actif,
|
||||||
|
4418,Subventions d'équilibre,,Actif,
|
||||||
|
4419,Avances sur subventions,,Actif,
|
||||||
|
442,État - Impôts et taxes recouvrables sur des tiers,,Passif,
|
||||||
|
444,État - Impôts sur les bénéfices,,Actif ou passif,
|
||||||
|
445,État - Taxes sur le chiffre d'affaires,,Actif ou passif,
|
||||||
|
4455,Taxes sur le chiffre d'affaires à décaisser,,Actif,
|
||||||
|
44551,TVA à décaisser,,Actif,
|
||||||
|
44558,Taxes assimilées à la TVA,,Actif,
|
||||||
|
4456,Taxes sur le chiffre d'affaires déductibles,,Actif,
|
||||||
|
44562,TVA sur immobilisations,,Actif,
|
||||||
|
44566,TVA sur autres biens et services,,Actif,
|
||||||
|
4457,Taxes sur le chiffre d'affaires collectées par l'association,,Actif,
|
||||||
|
4458,Taxes sur le chiffre d'affaires à régulariser ou en attente,,Actif,
|
||||||
|
44581,Acomptes - Régime simplifié d'imposition,,Actif,
|
||||||
|
44582,Acomptes - Régime du forfait,,Actif,
|
||||||
|
44583,Remboursement de taxes sur le chiffre d'affaires demandé,,Actif,
|
||||||
|
44584,TVA récupérée d'avance,,Actif,
|
||||||
|
44586,Taxes sur le chiffre d'affaires sur factures non parvenues,,Actif,
|
||||||
|
44587,Taxes sur le chiffre d'affaires sur factures à établir,,Actif,
|
||||||
|
447,"Autres impôts, taxes et versements assimilés",,Passif,
|
||||||
|
4471,"Autres impôts, taxes et versements assimilés sur rémunérations (Administration des impôts)",,Passif,
|
||||||
|
44711,Taxe sur les salaires,,Passif,
|
||||||
|
44713,Participation des employeurs à la formation professionnelle continue,,Passif,
|
||||||
|
44714,Cotisation par défaut d'investissement obligatoire dans la construction,,Passif,
|
||||||
|
44718,"Autres impôts, taxes et versements assimilés",,Passif,
|
||||||
|
4473,"Autres impôts, taxes et versements assimilés sur rémunérations (Autres organismes)",,Passif,
|
||||||
|
44733,Participation des employeurs à la formation professionnelle continue,,Passif,
|
||||||
|
44734,Participation des employeurs à l'effort de construction (versements à fonds perdus),,Passif,
|
||||||
|
4475,"Autres impôts, taxes et versements assimilés (Administration des impôts)",,Passif,
|
||||||
|
4477,"Autres impôts, taxes et versements assimilés (Autres organismes)",,Passif,
|
||||||
|
448,État - Charges à payer et produits à recevoir,,Passif,
|
||||||
|
4482,Charges fiscales sur congés à payer,,Passif,
|
||||||
|
4486,Autres charges à payer,,Passif,
|
||||||
|
4487,Produits à recevoir,,Actif,
|
||||||
|
449,Avances auprès de l'état et des collectivités publiques,,Passif,
|
||||||
|
45,"CONFÉDÉRATION, FÉDÉRATION, UNIONS ET ASSOCIATIONS AFFILIÉES",,Actif ou passif,
|
||||||
|
451,"Confédération, fédération et associations affiliées - Compte courant",,Actif ou passif,
|
||||||
|
455,Sociétaires - Comptes courants,,Actif ou passif,
|
||||||
|
46,DÉBITEURS DIVERS ET CRÉDITEURS DIVERS,,Actif ou passif,
|
||||||
|
467,Autres comptes débiteurs et créditeurs,,Actif ou passif,
|
||||||
|
468,Divers - Charges à payer et produits à recevoir,,Actif ou passif,
|
||||||
|
4686,Charges à payer,,Passif,
|
||||||
|
4687,Produits à recevoir,,Actif,
|
||||||
|
47,COMPTES TRANSITOIRES OU D'ATTENTE,,Actif ou passif,
|
||||||
|
471,Recettes à classer,,Passif,
|
||||||
|
472,Dépenses à classer et à régulariser,,Actif,
|
||||||
|
48,COMPTES DE RÉGULARISATION,,Actif ou passif,
|
||||||
|
481,Charges à répartir sur plusieurs exercices,,Actif,
|
||||||
|
486,Charges constatées d'avance,,Actif,
|
||||||
|
487,Produits constatés d'avance,,Passif,
|
||||||
|
49,DEPRECIATION DES COMPTES DE TIERS,,Actif,
|
||||||
|
491,Dépréciation des comptes clients,,Actif,
|
||||||
|
496,Dépréciation des comptes débiteurs divers,,Actif,
|
||||||
|
5,Classe 5 — Comptes financiers,,Actif,
|
||||||
|
50,VALEURS MOBILIÈRES DE PLACEMENT,,Actif,
|
||||||
|
51,"BANQUES, ÉTABLISSEMENTS FINANCIERS ET ASSIMILÉS",,Actif,
|
||||||
|
511,Valeurs à l'encaissement,,Actif,
|
||||||
|
5112,Chèques à encaisser,,Actif ou passif,Favori
|
||||||
|
5115,Paiements par carte à encaisser,,Actif ou passif,
|
||||||
|
512,Banques,,Actif ou passif,
|
||||||
|
53,CAISSE,,Actif,
|
||||||
|
530,Caisse,,Actif ou passif,Favori
|
||||||
|
54,RÉGIES D'AVANCES ET ACCRÉDITIFS,,Actif,
|
||||||
|
58,VIREMENTS INTERNES,,Actif,
|
||||||
|
59,PROVISIONS POUR DÉPRÉCIATION DES COMPTES FINANCIERS,,Actif,
|
||||||
|
6,Classe 6 — Comptes de charges,,Charge,
|
||||||
|
60,ACHATS,,Charge,
|
||||||
|
601,Achats stockés - Matières premières et fournitures,,Charge,
|
||||||
|
602,Achats stockés - Autres approvisionnements,,Charge,
|
||||||
|
604,Achat d'études et prestations de services,,Charge,Favori
|
||||||
|
606,Achats non stockés de matières et fournitures,,Charge,
|
||||||
|
6061,"Fournitures non stockables (eau, énergie...)","Facture d'eau, d'opérateur électrique, etc.",Charge,Favori
|
||||||
|
6063,Fournitures d'entretien et de petit équipement,,Charge,Favori
|
||||||
|
6064,Fournitures administratives,"Cartouches d'encre, papier, matériel bureautique, etc.",Charge,Favori
|
||||||
|
6068,Autres matières et fournitures,,Charge,Favori
|
||||||
|
607,Achats de marchandises,Marchandises destinées à être revendues en l'état.,Charge,Favori
|
||||||
|
61,SERVICES EXTÉRIEURS,,Charge,
|
||||||
|
611,Sous-traitance générale,,Charge,
|
||||||
|
612,Redevances de crédit-bail,,Charge,
|
||||||
|
613,Locations,Locations versées pour un local ou du matériel.,Charge,Favori
|
||||||
|
614,Charges locatives et de co-propriété,,Charge,
|
||||||
|
615,Entretiens et réparations,,Charge,
|
||||||
|
616,Primes d'assurance,,Charge,Favori
|
||||||
|
618,Divers,,Charge,
|
||||||
|
62,AUTRES SERVICES EXTÉRIEURS,,Charge,
|
||||||
|
621,Personnel extérieur à l'association,,Charge,
|
||||||
|
62141,Mises à disposition de personnel salarié,,Charge,Favori
|
||||||
|
622,Rémunérations d'intermédiaires et honoraires,,Charge,
|
||||||
|
6226,Honoraires,,Charge,
|
||||||
|
6227,Frais d'actes et de contentieux,"Insertion au Journal Officiel, frais de justice, etc.",Charge,Favori
|
||||||
|
6228,Divers,,Charge,
|
||||||
|
623,"Publicité, publications, relations publiques","Bulletins, affiches, communication, etc.",Charge,Favori
|
||||||
|
624,Transports de biens et transports collectifs du personnel,,Charge,
|
||||||
|
625,"Déplacements, missions et réceptions","Billet SNCF, remboursement de frais kilométrique, etc.",Charge,Favori
|
||||||
|
626,Frais postaux et de télécommunications,"Facture d'accès à Internet, timbres, etc.",Charge,Favori
|
||||||
|
627,Services bancaires et assimilés,Frais bancaires,Charge,Favori
|
||||||
|
628,Divers,,Charge,Favori
|
||||||
|
63,"IMPÔTS, TAXES ET VERSEMENTS ASSIMILÉS",,Charge,
|
||||||
|
631,"Impôts, taxes et versements assimilés sur rémunérations (Administration des impôts)",,Charge,
|
||||||
|
6311,Taxes sur les salaires,,Charge,
|
||||||
|
6313,Participations des employeurs à la formation professionnelle continue,,Charge,
|
||||||
|
635,"Autres impôts, taxes et versements assimilés (Administration des impôts)",,Charge,
|
||||||
|
6351,Impôts directs (sauf impôts sur les bénéfices),,Charge,
|
||||||
|
6353,Impôts indirects,,Charge,
|
||||||
|
637,"Autres impôts, taxes et versements assimilés (Autres organismes)",,Charge,
|
||||||
|
64,CHARGES DE PERSONNEL,,Charge,
|
||||||
|
641,Rémunérations du personnel,,Charge,
|
||||||
|
643,Rémunérations du personnel artistique et assimilés,,Charge,
|
||||||
|
645,Charges de sécurité sociale et de prévoyance,,Charge,
|
||||||
|
647,Autres charges sociales,,Charge,
|
||||||
|
648,Autres charges de personnel,,Charge,
|
||||||
|
65,AUTRES CHARGES DE GESTION COURANTE,,Charge,
|
||||||
|
652,Licences fédérales,Licences payées pour les adhérents (par exemple fédération sportive etc.),Charge,Favori
|
||||||
|
658,Charges diverses de gestion courante,,Charge,Favori
|
||||||
|
66,CHARGES FINANCIÈRES,,Charge,
|
||||||
|
661,Charges d'intérêts,,Charge,
|
||||||
|
67,CHARGES EXCEPTIONNELLES,,Charge,
|
||||||
|
670,Charges exceptionnelles,Autres dépenses exceptionnelles,Charge,Favori
|
||||||
|
671,Charges exceptionnelles sur opérations de gestion,,Charge,
|
||||||
|
6713,"Dons, libéralités",,Charge,
|
||||||
|
678,Autres charges exceptionnelles,,Charge,
|
||||||
|
6788,Charges exceptionnelles diverses,,Charge,
|
||||||
|
68,"DOTATIONS AUX AMORTISSEMENTS, DÉPRÉCIATIONS, PROVISIONS ET ENGAGEMENTS",,Charge,
|
||||||
|
681,"Dotations aux amortissements, dépréciations et provisions - Charges d'exploitation",,Charge,
|
||||||
|
6811,Dotations aux amortissements des immobilisations incorporelles et corporelles,,Charge,
|
||||||
|
68111,Immobilisations incorporelles,,Charge,
|
||||||
|
68112,Immobilisations corporelles,,Charge,
|
||||||
|
686,"Dotations aux amortissements, dépréciations et provisions - Charges financières",,Charge,
|
||||||
|
69,PARTICIPATION DES SALARIÉS - IMPÔTS SUR LES BÉNÉFICES ET ASSIMILÉS,,Charge,
|
||||||
|
695,Impôts sur les sociétés (y compris impôts sur les sociétés des personnes morales non lucratives),,Charge,
|
||||||
|
7,Classe 7 — Comptes de produits,,Produit,
|
||||||
|
70,"VENTES DE PRODUITS FINIS, PRESTATIONS DE SERVICES, MARCHANDISES",,Produit,
|
||||||
|
701,Ventes de produits finis,Vente de produits fabriqués par l'association.,Produit,Favori
|
||||||
|
706,Prestations de services,,Produit,Favori
|
||||||
|
707,Ventes de marchandises,,Produit,Favori
|
||||||
|
708,Produits des activités annexes,,Produit,
|
||||||
|
71,PRODUCTION STOCKÉE (OU DÉSTOCKAGE),,Produit,
|
||||||
|
72,PRODUCTION IMMOBILISÉE,,Produit,
|
||||||
|
74,SUBVENTIONS D'EXPLOITATION,,Produit,
|
||||||
|
740,Subventions reçues,,Produit,Favori
|
||||||
|
75,AUTRES PRODUITS DE GESTION COURANTE,,Produit,
|
||||||
|
754,Collectes,,Produit,Favori
|
||||||
|
756,Cotisations,,Produit,Favori
|
||||||
|
758,Produits divers de gestion courante,,Produit,
|
||||||
|
7587,Ventes de dons en nature,,Produit,
|
||||||
|
7588,Autres produits de la générosité du public,,Produit,
|
||||||
|
76,PRODUITS FINANCIERS,,Produit,
|
||||||
|
760,Produits financiers,,Produit,
|
||||||
|
77,PRODUITS EXCEPTIONNELS,,Produit,
|
||||||
|
771,Produits exceptionnels sur opérations de gestion,,Produit,
|
||||||
|
7713,Libéralités reçues,,Produit,
|
||||||
|
7715,Subventions d'équilibre,,Produit,
|
||||||
|
775,Produits des cessions d'éléments d'actifs,,Produit,
|
||||||
|
778,Autres produits exceptionnels,,Produit,
|
||||||
|
7780,Manifestations diverses,"Revenus provenant de manifestations au profit de l'association : droit d'entrée, location d'emplacement en vide grenier, ventes, etc.",Produit,Favori
|
||||||
|
7788,Produits exceptionnels divers,,Produit,
|
||||||
|
78,REPRISES SUR AMORTISSEMENTS ET PROVISIONS,,Produit,
|
||||||
|
79,TRANSFERT DE CHARGES,,Produit,
|
||||||
|
791,Transferts de charges d'exploitation,,Produit,
|
||||||
|
796,Transferts de charges financières,,Produit,
|
||||||
|
797,Transferts de charges exceptionnels,,Produit,
|
||||||
|
8,Classe 8 — Comptes spéciaux,,,
|
||||||
|
86,RÉPARTITION PAR NATURE DE CHARGES,,Charge,
|
||||||
|
861,Mise à dispositions gratuites de biens,,Charge,
|
||||||
|
862,Prestations,,Charge,Favori
|
||||||
|
864,Personnel bénévole,,Charge,Favori
|
||||||
|
87,RÉPARTITION PAR NATURE DE RESSOURCES,,Produit,
|
||||||
|
870,Bénévolat,,Produit,Favori
|
||||||
|
871,Prestations en nature,,Produit,Favori
|
||||||
|
875,Dons en nature,,Produit,
|
||||||
|
89,BILAN,,,
|
||||||
|
890,Bilan d'ouverture,,Actif ou passif,
|
||||||
|
891,Bilan de clôture,,Actif ou passif,
|
|
553
src/include/data/charts/fr_pca_2018.csv
Normal file
553
src/include/data/charts/fr_pca_2018.csv
Normal file
|
@ -0,0 +1,553 @@
|
||||||
|
code,label,description,position,bookmark
|
||||||
|
1,"Classe 1 — Comptes de capitaux (Fonds propres, emprunts et dettes assimilés)",,Passif,
|
||||||
|
10,Fonds propres et réserves,,Passif,
|
||||||
|
102,Fonds propres sans droit de reprise,,Passif,
|
||||||
|
1021,Première situation nette établie,,Passif,
|
||||||
|
1022,Fonds statutaires,,Passif,
|
||||||
|
1023,Dotations non consomptibles,,Passif,
|
||||||
|
10231,Dotations non consomptibles initiales,,Passif,
|
||||||
|
10232,Dotations non consomptibles complémentaires,,Passif,
|
||||||
|
1024,Autres fonds propres sans droit de reprise,,Passif,
|
||||||
|
103,Fonds propres avec droit de reprise,,Passif,
|
||||||
|
1032,Fonds statutaires,,Passif,
|
||||||
|
1034,Autres fonds propres avec droit de reprise,,Passif,
|
||||||
|
105,Ecarts de réévaluation,,Passif,
|
||||||
|
1051,Ecarts réévaluation sur biens sans dt reprise,,Passif,
|
||||||
|
1052,Ecarts réévaluation sur biens avec dt reprise,,Passif,
|
||||||
|
106,Réserves,,Passif,
|
||||||
|
1062,Réserves indisponibles,,Passif,
|
||||||
|
1063,Réserves statutaires,,Passif,
|
||||||
|
1064,Réserves réglementées,,Passif,
|
||||||
|
1068,Réserves pour projet de l’entité,,Passif,
|
||||||
|
108,Dotations consomptibles,,Passif,
|
||||||
|
1081,Dotations consomptibles,,Passif,
|
||||||
|
1089,Dot. consomptibles inscrites au cpte de résul,,Passif,
|
||||||
|
11,Report à nouveau,,Passif,
|
||||||
|
110,Report à nouveau (Solde créditeur),,Passif,
|
||||||
|
119,Report à nouveau (Solde débiteur),,Passif,
|
||||||
|
12,Résultat net de l’exercice,,Passif,
|
||||||
|
120,Résultat de l'exercice (excédent),,Passif,
|
||||||
|
129,Résultat de l'exercice (déficit),,Passif,
|
||||||
|
13,Subventions d’investissement,,Passif,
|
||||||
|
131,Subventions d'équipement,,Passif,
|
||||||
|
139,Subventions inscrites au compte de résultat,,Passif,
|
||||||
|
14,Provisions réglementées,,Passif,
|
||||||
|
148,Autres provisions réglementées,,Passif,
|
||||||
|
15,Provisions pour risques et charges,,Passif,
|
||||||
|
151,Provisions pour risques,,Passif,
|
||||||
|
152,Provisions pour charges sur legs ou donations,,Passif,
|
||||||
|
153,Provisions pour pensions et obligations simil,,Passif,
|
||||||
|
155,Provisions pour impôts,,Passif,
|
||||||
|
157,Provisions pour charges à répartir,,Passif,
|
||||||
|
158,Autres provisions pour charges,,Passif,
|
||||||
|
16,Emprunts et dettes assimilées,,Passif,
|
||||||
|
163,Autres emprunts obligataires,,Passif,
|
||||||
|
1631,Titres associatifs et assimilés,,Passif,
|
||||||
|
164,Emprunts auprès des établissements de crédit,,Passif,
|
||||||
|
165,Dépôts et cautionnements reçus,,Passif,
|
||||||
|
1651,Dépôts,,Passif,
|
||||||
|
1655,Cautionnements,,Passif,
|
||||||
|
167,Emprunts et dettes sous conditions particulières,,Passif,
|
||||||
|
168,Autres emprunts et dettes assimilées,,Passif,
|
||||||
|
18,Comptes de liaisons,,Passif,
|
||||||
|
181,Apports permanents siège-établissements,,Passif,
|
||||||
|
185,Biens & PS échangés siège-établissements,,Passif,
|
||||||
|
186,Biens & PS entre établissements - Charges,,Passif,
|
||||||
|
187,Biens & PS entre établissements - Produits,,Passif,
|
||||||
|
19,Fonds dédiés ou reportés,,Passif,
|
||||||
|
191,Fonds reportés liés aux legs ou donations,,Passif,
|
||||||
|
1911,Legs ou donations,,Passif,
|
||||||
|
1912,Donations temporaires d’usufruit,,Passif,
|
||||||
|
194,Fonds dédiés sur subventions fonctionnement,,Passif,
|
||||||
|
195,F.d. / contributions financières autres org.,,Passif,
|
||||||
|
196,F.d. / ressources liées à la générosité,,Passif,
|
||||||
|
2,Classe 2 — Comptes d'immobilisations,,Actif,
|
||||||
|
20,Immobilisations incorporelles,,Actif,
|
||||||
|
201,Frais d'établissement,,Actif,
|
||||||
|
203,Frais de recherche et de développement,,Actif,
|
||||||
|
204,Donations temporaires d’usufruit,,Actif,
|
||||||
|
205,"Brevets, licences, marques...",,Actif,
|
||||||
|
206,Droit au bail,,Actif,
|
||||||
|
208,Autres immobilisations incorporelles,,Actif,
|
||||||
|
21,Immobilisations corporelles,,Actif,
|
||||||
|
211,Terrains,,Actif,
|
||||||
|
212,Agencements / aménagements de terrains,,Actif,
|
||||||
|
2131,Bâtiments,,Actif,
|
||||||
|
2135,"Installations, agencements...de constructions",,Actif,
|
||||||
|
214,Constructions sur sol d'autrui,,Actif,
|
||||||
|
215,"Installations techniques, matériel, outillage",,Actif,
|
||||||
|
2154,Matériel industriel,,Actif,
|
||||||
|
2155,Outillage industriel,,Actif,
|
||||||
|
218,Autres immobilisations corporelles,,Actif,
|
||||||
|
2181,"Installations, agencements, aménagem. divers",,Actif,
|
||||||
|
2182,Matériel de transport,,Actif,
|
||||||
|
2183,Matériel bureau et informatique,,Actif,
|
||||||
|
2184,Mobilier,,Actif,
|
||||||
|
23,Immobilisations en cours,,Actif,
|
||||||
|
231,Immobilisations corporelles en cours,,Actif,
|
||||||
|
238,"Avances, acomptes sur immobilis. corporelles",,Actif,
|
||||||
|
24,Biens destinés à être cédés,,Actif,
|
||||||
|
240,Biens reçus par legs ou donations à céder,,Actif,
|
||||||
|
26,Participations et créances rattachées,,Actif,
|
||||||
|
261,Titres de participation,,Actif,
|
||||||
|
266,Autres formes de participation,,Actif,
|
||||||
|
267,Créances rattachées à des participations,,Actif,
|
||||||
|
269,Versements restants sur participations,,Actif,
|
||||||
|
27,Immobilisations financières,,Actif,
|
||||||
|
271,Titres immobilisés (droit de propriété),,Actif,
|
||||||
|
272,Titres immobilisés (droit de créance),,Actif,
|
||||||
|
274,Prêts,,Actif,
|
||||||
|
2742,Prêts aux partenaires,,Actif,
|
||||||
|
275,Dépôts et cautionnements versés,,Actif,
|
||||||
|
276,Autres créances immobilisées,,Actif,
|
||||||
|
28,Amortissements des immobilisations,,Actif,
|
||||||
|
2801,Amt. frais d'établissement,,Actif,
|
||||||
|
2804,Amt. donations temporaires d’usufruit,,Actif,
|
||||||
|
2805,"Amt brevets, licences, marques...",,Actif,
|
||||||
|
2806,Amt. droit au bail,,Actif,
|
||||||
|
2808,Amt. autres immo.incorporelles,,Actif,
|
||||||
|
2812,"Amt.agencements, aménagements de terrains",,Actif,
|
||||||
|
28131,Amortissements bâtiments,,Actif,
|
||||||
|
28135,"Amt. installations, agencements...",,Actif,
|
||||||
|
2814,Amt.constructions sur sol d'autrui,,Actif,
|
||||||
|
2815,"Amt instal. techniques, matériel, outillage",,Actif,
|
||||||
|
28181,"Amt. intallations, agencements, aménagements",,Actif,
|
||||||
|
28182,Amt. matériel de transport,,Actif,
|
||||||
|
28183,"Amortiss.matériel de bureau, informatique",,Actif,
|
||||||
|
28184,Amortissements du mobilier,,Actif,
|
||||||
|
29,Dépréciations des immobilisations,,Actif,
|
||||||
|
2904,Donations temporaires d'usufruit,,Actif,
|
||||||
|
2905,"Brevets, licences, marques...",,Actif,
|
||||||
|
2906,Droit au bail,,Actif,
|
||||||
|
2908,Autres immobilisations incorporelles,,Actif,
|
||||||
|
2911,Terrains,,Actif,
|
||||||
|
2931,Immobilisations corporelles en cours,,Actif,
|
||||||
|
294,Biens reçus par legs ou donations à céder,,Actif,
|
||||||
|
2961,Titres de participations,,Actif,
|
||||||
|
2966,Autres formes de participations,,Actif,
|
||||||
|
2967,Créances rattachées à des participations,,Actif,
|
||||||
|
2971,Titres immobilisés (droit de propriété),,Actif,
|
||||||
|
2972,Titres immobilisés (droit de créance),,Actif,
|
||||||
|
2974,Prêts,,Actif,
|
||||||
|
2975,Dépôts et cautionnements versés,,Actif,
|
||||||
|
2976,Autres créances immobilisées,,Actif,
|
||||||
|
3,Classe 3 — Comptes de stocks,,Actif,
|
||||||
|
31,Matières premières et fournitures,,Actif,
|
||||||
|
318,Matières premières et fournitures,,Actif,
|
||||||
|
32,Autres approvisionnements,,Actif,
|
||||||
|
321,Matières consommables,,Actif,
|
||||||
|
322,Fournitures consommables,,Actif,
|
||||||
|
326,Emballages,,Actif,
|
||||||
|
33,En-cours de production de biens,,Actif,
|
||||||
|
331,Produits en cours,,Actif,
|
||||||
|
335,Travaux en cours,,Actif,
|
||||||
|
34,En-cours de production de services,,Actif,
|
||||||
|
341,Etudes en cours,,Actif,
|
||||||
|
345,Prestations de services en cours,,Actif,
|
||||||
|
35,Stocks de produits,,Actif,
|
||||||
|
351,Produits intermédiaires,,Actif,
|
||||||
|
355,Produits finis,,Actif,
|
||||||
|
358,Produits résiduels,,Actif,
|
||||||
|
37,Stocks de marchandises,,Actif,
|
||||||
|
370,Stocks de marchandises,,Actif,
|
||||||
|
39,Provisions pour dépréciations stocks et en-cours,,Actif,
|
||||||
|
391,Matières premières et fournitures,,Actif,
|
||||||
|
392,Autres approvisionnements,,Actif,
|
||||||
|
393,En-cours de production de biens,,Actif,
|
||||||
|
394,En-cours de production de services,,Actif,
|
||||||
|
395,Stocks de produits,,Actif,
|
||||||
|
397,Stocks de marchandises,,Actif,
|
||||||
|
4,Classe 4 — Comptes de tiers,,Actif ou passif,
|
||||||
|
40,Fournisseurs et comptes rattachés,,Actif ou passif,
|
||||||
|
401,Fournisseurs,,Actif ou passif,
|
||||||
|
4010,Autres fournisseurs,,Actif ou passif,Favori
|
||||||
|
403,Fournisseurs - Effets à payer,,Passif,
|
||||||
|
404,Fournisseurs d'immobilisations,,Actif ou passif,
|
||||||
|
405,Fournisseurs d'immos - Effets à payer,,Passif,
|
||||||
|
408,Fournisseurs - Factures non parvenues,,Passif,
|
||||||
|
4091,Fournisseurs - Avances & acomptes,,Actif,
|
||||||
|
41,Usagers et comptes rattachés,,Actif ou passif,
|
||||||
|
411,Usagers,,Actif ou passif,
|
||||||
|
4110,Autres usagers,Pour les dettes ou créances des membres,Actif ou passif,Favori
|
||||||
|
413,Usagers - Effets à recevoir,,Actif,
|
||||||
|
416,Usagers douteux ou litigieux,,Actif,
|
||||||
|
418,Usagers non encore facturés,,Actif,
|
||||||
|
4191,Usagers créditeurs : Avances et acomptes,,Passif,
|
||||||
|
42,Personnel et comptes rattachés,,Actif ou passif,
|
||||||
|
421,Personnel : Rémunérations dues,,Passif,
|
||||||
|
4210,Autres membres du personnel,Dettes dûes aux salarié⋅e⋅s,Actif ou passif,Favori
|
||||||
|
422,"Comités d'entreprise, d'établissement",,Actif ou passif,
|
||||||
|
425,Personnel : Avances & acomptes,,Actif,
|
||||||
|
427,Personnel - Oppositions,,Passif,
|
||||||
|
4286,Personnel- Charges à payer,,Passif,
|
||||||
|
4287,Personnel- Produits à recevoir,,Actif,
|
||||||
|
43,Sécurité sociale et autres organismes sociaux,,Passif,
|
||||||
|
431,Sécurité sociale,,Passif,
|
||||||
|
4372,Mutuelles,,Passif,
|
||||||
|
4373,Caisses de retraites et de prévoyance,,Passif,
|
||||||
|
4378,Autres organismes sociaux,,Passif,
|
||||||
|
438,Organismes sociaux - Charges à payer et produits à recevoir,,Passif,
|
||||||
|
4382,Charges sociales sur congés à payer,,Passif,
|
||||||
|
4386,Autres charges à payer,,Passif,
|
||||||
|
4387,Produits à recevoir,,Passif,
|
||||||
|
44,État et autres collectivités publiques,,Actif,
|
||||||
|
441,État - Subventions à recevoir,,Actif,
|
||||||
|
4421,Prélèvements à la source - Impôt sur le revenu,,Actif ou passif,
|
||||||
|
444,État - Impôts sur les bénéfices,,Actif ou passif,
|
||||||
|
4452,TVA due intracommunautaire,,Actif ou passif,
|
||||||
|
4455,Taxes sur CA à décaisser,,Actif,
|
||||||
|
44562,TVA déductible sur immobilisations,,Actif,
|
||||||
|
44566,TVA déductible sur autres biens et services,,Actif,
|
||||||
|
44571,TVA normale collectée,,Actif,
|
||||||
|
445711,TVA réduite collectée,,Actif,
|
||||||
|
445712,TVA super-réduite collectée,,Actif,
|
||||||
|
445713,TVA intermédiaire collectée,,Actif,
|
||||||
|
4458,Taxe sur CA à régulariser ou en attente,,Actif,
|
||||||
|
447,"Autres impôts, taxes et versements assimilés",,Actif,
|
||||||
|
4486,État - Charges à payer,,Passif,
|
||||||
|
4487,État - Produits à recevoir,,Actif,
|
||||||
|
45,"Confédération, fédération, unions… affiliées",,Actif ou passif,
|
||||||
|
451,"Confédération, fédération et associations affiliées",,Actif ou passif,
|
||||||
|
455,Partenaires - comptes courants,,Actif ou passif,
|
||||||
|
46,Débiteurs divers et créditeurs divers,,Actif ou passif,
|
||||||
|
461,Créances reçues par legs ou donations,,Actif,
|
||||||
|
466,Dettes des legs ou donations,,Passif,
|
||||||
|
4671,Débiteurs divers,,Actif ou passif,
|
||||||
|
4672,Créditeurs divers,,Actif ou passif,
|
||||||
|
4681,Frais des bénévoles,,Actif ou passif,
|
||||||
|
4686,Divers - Charges à payer,,Passif,
|
||||||
|
4687,Divers - Produits à recevoir,,Actif,
|
||||||
|
47,Comptes d’attente,,Actif ou passif,
|
||||||
|
4715,Compte de transit,,Actif ou passif,
|
||||||
|
4718,Compte d'attente,,Actif ou passif,
|
||||||
|
48,Comptes de régularisation,,Actif ou passif,
|
||||||
|
481,Charges à répartir,,Passif,
|
||||||
|
486,Charges constatées d'avance,,Actif,
|
||||||
|
487,Produits constatés d'avance,,Passif,
|
||||||
|
49,Dépréciations des comptes de tiers,,Actif ou passif,
|
||||||
|
491,Provision pour dépreciation des comptes d'usagers,,Passif,
|
||||||
|
496,Provision pour dépreciation des comptes débiteurs divers,,Passif,
|
||||||
|
5,Classe 5 — Comptes financiers,,Actif,
|
||||||
|
50,Valeurs mobilières de placement,,Actif,
|
||||||
|
503,Actions,,Actif,
|
||||||
|
506,Obligations,,Actif,
|
||||||
|
508,Autres VMP et créances assimilées,,Actif,
|
||||||
|
51,"Banques, établissements financiers",,Actif,
|
||||||
|
5112,Chèques à encaisser,,Actif ou passif,Favori
|
||||||
|
5115,Paiements par carte à encaisser,,Actif ou passif,
|
||||||
|
512,Banques,,Actif ou passif,
|
||||||
|
5186,Intérêts courus à payer,,Passif,
|
||||||
|
5187,Intérêts courus à recevoir,,Actif,
|
||||||
|
53,Caisses,,Actif ou passif,
|
||||||
|
530,Caisse,,Actif ou passif,Favori
|
||||||
|
58,Virements internes,,Actif ou passif,
|
||||||
|
580,Virements internes,,Actif ou passif,
|
||||||
|
59,Dépréciations des comptes financiers,,Actif ou passif,
|
||||||
|
5903,Actions,,Actif ou passif,
|
||||||
|
5906,Obligations,,Actif ou passif,
|
||||||
|
5908,Autres VMP et créances assimilées,,Actif ou passif,
|
||||||
|
6,Classe 6 — Comptes de charges,,Charge,
|
||||||
|
60,Achats (sauf 603),,Charge,
|
||||||
|
601,Achats stockés - Matières premières et fournitures,,Charge,
|
||||||
|
6010,Achats stockés de matières et fournitures,,Charge,
|
||||||
|
6011,Achats stockés - Matières premières,,Charge,
|
||||||
|
6017,Achats stockés - Fournitures,,Charge,
|
||||||
|
602,Achats stockés - Autres approvisionnements,,Charge,
|
||||||
|
6021,Achats stockés - Matières consommables,,Charge,
|
||||||
|
60221,Achats stockés - Combustibles,,Charge,
|
||||||
|
60222,Achats stockés - Produits d'entretien,,Charge,
|
||||||
|
60223,Achats stockés - Fournitures d'atelier,,Charge,
|
||||||
|
60224,Achats stockés - Fournitures de magasin,,Charge,
|
||||||
|
60225,Fournitures de bureau,,Charge,
|
||||||
|
6026,Achats stockés - Emballages,,Charge,
|
||||||
|
603,Variations de stocks,,Charge,
|
||||||
|
6031,Variations de stocks matières & fournitures,,Charge,
|
||||||
|
6032,Variations stocks autres approvisionnements,,Charge,
|
||||||
|
6037,Variations de stocks de marchandises,,Charge,
|
||||||
|
604,Achats d'études et prestations de services,,Charge,
|
||||||
|
605,"Achats matériel, équipements & travaux",,Charge,
|
||||||
|
606,Achats non stockés de matières et fournitures,,Charge,
|
||||||
|
6061,"Fournitures non stockables (eau, énergie...)","Facture d'eau, d’électricité, etc.",Charge,Favori
|
||||||
|
60611,Eau,,Charge,
|
||||||
|
60612,Electricité,,Charge,
|
||||||
|
60613,Chauffage,,Charge,
|
||||||
|
6063,Fournitures d'entretien et petit équipement,"Vis, et matériel de bricolage (sauf outils) par exemple",Charge,Favori
|
||||||
|
6064,Fournitures administratives,"Cartouches d'encre, papier, matériel bureautique, etc.",Charge,Favori
|
||||||
|
6065,Petits logiciels,Par exemple contribution à un logiciel de gestion associative génial :-),Charge,Favori
|
||||||
|
6068,Autres fournitures & matières,,Charge,Favori
|
||||||
|
607,Achats de marchandises,Marchandises destinées à être revendues en l'état.,Charge,Favori
|
||||||
|
608,Frais accessoires d'achats,,Charge,
|
||||||
|
60811,Frais accessoires d'achats sur matières,,Charge,
|
||||||
|
60817,Frais accessoires d'achats sur fournitures,,Charge,
|
||||||
|
609,"Rabais, remises et ristournes sur achats",,Charge,
|
||||||
|
6091,RRR sur achats matières et fournitures,,Charge,
|
||||||
|
6092,RRR sur achats et autres approvisionnements,,Charge,
|
||||||
|
6097,RRR sur achats de marchandises,,Charge,
|
||||||
|
61,Services extérieurs,,Charge,
|
||||||
|
611,Sous-traitance générale,,Charge,
|
||||||
|
6122,Redevance crédit-bail mobilier,,Charge,
|
||||||
|
6125,Redevances crédit-bail immobilier,,Charge,
|
||||||
|
6132,Locations immobilières,Locations versées pour un local ou du matériel.,Charge,Favori
|
||||||
|
6135,Locations mobilières,,Charge,
|
||||||
|
6136,Malis sur emballages,,Charge,
|
||||||
|
614,Charges locatives et de copropriété,,Charge,
|
||||||
|
6152,Entretien sur biens immobiliers,,Charge,
|
||||||
|
6155,Entretien sur biens mobiliers,,Charge,
|
||||||
|
6156,Maintenance,,Charge,
|
||||||
|
616,Primes d'assurance,"Frais d’assurance local, activité, etc.",Charge,Favori
|
||||||
|
6161,Primes d'assurances mutirisques,,Charge,
|
||||||
|
6164,Primes d'assurances / risques d'exploitation,,Charge,
|
||||||
|
6165,Primes d'assurances / insolvabilité usagers,,Charge,
|
||||||
|
6168,Autres assurances,,Charge,
|
||||||
|
617,Études et recherches,,Charge,
|
||||||
|
6181,Documentation générale,,Charge,
|
||||||
|
6183,Documentation technique,,Charge,
|
||||||
|
6185,"Frais de colloques, séminaires, conférences",,Charge,
|
||||||
|
6187,Prestations administratives,,Charge,
|
||||||
|
62,Autres services extérieurs,,Charge,
|
||||||
|
621,Personnel extérieur à l'association,,Charge,
|
||||||
|
6211,Personnel intérimaire,,Charge,
|
||||||
|
6214,Personnel détaché ou prêté à l'association,,Charge,
|
||||||
|
62141,Mises à disposition de personnel salarié,Frais de mise à disposition via un groupement d’employeurs,Charge,Favori
|
||||||
|
622,Rémunérations d'intermédiaires et honoraires,,Charge,
|
||||||
|
6221,Commissions… sur achats,,Charge,
|
||||||
|
6222,Commissions… sur ventes,,Charge,
|
||||||
|
6226,Honoraires,,Charge,
|
||||||
|
62264,Honoraires sur legs ou donations à céder,,Charge,
|
||||||
|
6227,Frais d'actes et de contentieux,,Charge,
|
||||||
|
6228,Rémunérations divers intermédiaires & honoraires,,Charge,
|
||||||
|
623,"Publicité, publications, relations publiques","Bulletins, affiches, communication, etc.",Charge,Favori
|
||||||
|
6231,Annonces et insertions,,Charge,
|
||||||
|
6232,Fêtes et cérémonies,,Charge,
|
||||||
|
6233,Foires et expositions,,Charge,
|
||||||
|
6234,Cadeaux,,Charge,
|
||||||
|
6236,Catalogues et imprimés,,Charge,
|
||||||
|
6237,Publications,,Charge,
|
||||||
|
6238,"Divers : pourboires, dons courants",,Charge,
|
||||||
|
624,Transports de biens,,Charge,
|
||||||
|
6241,Transports sur achats,,Charge,
|
||||||
|
6242,Transports sur ventes,,Charge,
|
||||||
|
6243,Transports entre établissements,,Charge,
|
||||||
|
6244,Transports administratifs,,Charge,
|
||||||
|
6247,Transports collectifs du personnel,,Charge,
|
||||||
|
6248,Transports divers,,Charge,
|
||||||
|
625,"Déplacements, missions et réceptions","Billet de train, remboursement de frais kilométrique, etc.",Charge,Favori
|
||||||
|
6251,Voyages et déplacements,,Charge,
|
||||||
|
6255,Frais de déménagement,,Charge,
|
||||||
|
6256,Frais de missions,,Charge,
|
||||||
|
6257,"Frais de réceptions, représentations",,Charge,
|
||||||
|
626,Frais postaux et de télécommunications,"Facture d'accès à Internet, timbres, etc.",Charge,Favori
|
||||||
|
6261,Liaisons spécialisées,,Charge,
|
||||||
|
6263,"Affranchissements, frais postaux",,Charge,
|
||||||
|
6265,Téléphone,,Charge,
|
||||||
|
627,Services bancaires et assimilés,Frais bancaires,Charge,Favori
|
||||||
|
628,Divers,,Charge,Favori
|
||||||
|
6281,Cotisations (liées à l'activité économique),,Charge,
|
||||||
|
6284,Frais de recrutement du personnel,,Charge,
|
||||||
|
63,"Impôts, taxes et versements assimilés",,Charge,
|
||||||
|
631,Sur rémunérations - administration des impôts,,Charge,
|
||||||
|
6311,Taxe sur les salaires,,Charge,
|
||||||
|
633,Sur rémunérations - autres organismes,,Charge,
|
||||||
|
6331,Versement de transport,,Charge,
|
||||||
|
6332,Allocation logement,,Charge,
|
||||||
|
6333,Formation professionnelle continue,,Charge,
|
||||||
|
6334,Participations employeurs à l'effort de construction,,Charge,
|
||||||
|
635,Autres - Administration des impôts,,Charge,
|
||||||
|
63512,Taxes foncières,,Charge,
|
||||||
|
63513,Autres impôts locaux,,Charge,
|
||||||
|
6354,Droits d'enregistrement et de timbre,,Charge,
|
||||||
|
637,Autres - Autres organismes,,Charge,
|
||||||
|
64,Charges de personnel,,Charge,
|
||||||
|
641,Rémunérations du personnel,,Charge,
|
||||||
|
6411,"Salaires, appointements",,Charge,
|
||||||
|
6412,Congés payés,,Charge,
|
||||||
|
6413,Primes et gratifications,,Charge,
|
||||||
|
6414,Indemnités et avantages divers,,Charge,
|
||||||
|
6415,Supplément familial,,Charge,
|
||||||
|
645,Charges de sécurité sociale et de prévoyance,,Charge,
|
||||||
|
6451,Cotisations à l'URSSAF,,Charge,
|
||||||
|
6452,Cotisations aux mutuelles,,Charge,
|
||||||
|
6453,Cotisations caisses de retraites et de prévoyance,,Charge,
|
||||||
|
6458,Cotisations aux autres organismes sociaux,,Charge,
|
||||||
|
647,Autres charges sociales,,Charge,
|
||||||
|
6472,Versements aux comités d'entreprise et d'établissement,,Charge,
|
||||||
|
6473,Versement aux comités d'hygiène et de sécurité,,Charge,
|
||||||
|
6474,Versements aux autres œuvres sociales,,Charge,
|
||||||
|
6475,"Médecine du travail, pharmacie",,Charge,
|
||||||
|
648,Autres charges de personnel,,Charge,
|
||||||
|
6481,Indemnités du personnel de culte,,Charge,
|
||||||
|
6485,Charges sociales sur indemnités de culte,,Charge,
|
||||||
|
6488,Autres charges de personnel,,Charge,
|
||||||
|
65,Autres charges de gestion courante,,Charge,
|
||||||
|
6511,"Redevances pour concessions, brevets, licences",,Charge,
|
||||||
|
6516,Droits d'auteur et de reproduction,,Charge,
|
||||||
|
6518,Autres droits et valeurs similaires,,Charge,
|
||||||
|
652,Licences fédérales,Licences payées pour les adhérents (par exemple fédération sportive etc.),Charge,Favori
|
||||||
|
653,Charges de la générosité du public,,Charge,
|
||||||
|
6531,Autres charges sur legs ou donations,,Charge,
|
||||||
|
654,Pertes sur créances irrécouvrables,,Charge,
|
||||||
|
655,Quotes-parts sur opérations faites en commun,,Charge,
|
||||||
|
657,Aides financières,,Charge,
|
||||||
|
6571,Aides financières octroyées,,Charge,
|
||||||
|
6572,Quotes-parts de générosité reversée,,Charge,
|
||||||
|
658,Charges diverses de gestion courante,,Charge,Favori
|
||||||
|
6586,Cotisations (vie statutaire),,Charge,
|
||||||
|
6588,Charges diverses de gestion courante,,Charge,
|
||||||
|
66,Charges financières,,Charge,
|
||||||
|
661,Charges d'intérêts,,Charge,
|
||||||
|
665,Escomptes accordés,,Charge,
|
||||||
|
666,Pertes de changes,,Charge,
|
||||||
|
667,Charges nettes sur cessions de VMP,,Charge,
|
||||||
|
668,Autres charges financières,,Charge,
|
||||||
|
67,Charges exceptionnelles,,Charge,
|
||||||
|
670,Charges exceptionnelles,Autres dépenses exceptionnelles,Charge,Favori
|
||||||
|
6712,"Pénalités, amendes fiscales et pénales",,Charge,
|
||||||
|
6713,"Dons, libéralités",,Charge,
|
||||||
|
6714,Créances devenues irrécouvrables,,Charge,
|
||||||
|
6718,Autres charges exceptionnelles de gestion,,Charge,
|
||||||
|
672,Charges sur exercices antérieurs,,Charge,
|
||||||
|
673,Apports ou affectations en numéraire,,Charge,
|
||||||
|
675,Valeurs comptables des éléments d'actifs cédés,,Charge,
|
||||||
|
6750,Valeurs comptables des actifs cédés,,Charge,
|
||||||
|
6754,Immobilisations reçues par legs ou donations,,Charge,
|
||||||
|
678,Autres charges exceptionnelles sur opération en capital,,Charge,
|
||||||
|
68,"Dotations aux amortissements, dépréciations et engagements",,Charge,
|
||||||
|
6811,Dot. aux amortissements des immobilisations,,Charge,
|
||||||
|
6812,Dot. aux amortissements charges à répartir,,Charge,
|
||||||
|
6815,Dot. aux provisions d'exploitation,,Charge,
|
||||||
|
6816,Dot. provisions pour dépréciations des immobilisations,,Charge,
|
||||||
|
68164,Dot. pour dépréciation d’actifs reçus par legs ou donations,,Charge,
|
||||||
|
6817,Dot. aux dépréciations des actifs circulants,,Charge,
|
||||||
|
68173,Dotations dépréciations stocks et en-cours,,Charge,
|
||||||
|
68174,Dotations dépréciations créances,,Charge,
|
||||||
|
686,Dot. aux amortissements & provisions - Charges financières,,Charge,
|
||||||
|
68662,Dot. aux amortissements & provisions des immobilisations financières,,Charge,
|
||||||
|
68665,Dot. aux amortissements & provisions des valeurs mobilières de placement,,Charge,
|
||||||
|
687,Dot. aux amortissements & provisions - Charges exceptionnelles,,Charge,
|
||||||
|
689,Reports en fonds dédiés,,Charge,
|
||||||
|
6891,Reports en fonds reportés,,Charge,
|
||||||
|
6894,Reports en fonds dédiés / subventions d’exploitation,,Charge,
|
||||||
|
6895,Reports en fds dédiés / contributions financières d'autres organismes,,Charge,
|
||||||
|
6896,Reports en fds dédiés / ressources générosité,,Charge,
|
||||||
|
69,Impôts sur les bénéfices,,Charge,
|
||||||
|
695,IS sur personnes non lucratives,,Charge,
|
||||||
|
7,Classe 7 — Comptes de produits,,Produit,
|
||||||
|
70,"Ventes de produits finis, marchandises, prestations",,Produit,
|
||||||
|
701,Ventes de produits finis,Vente de produits fabriqués par l'association.,Produit,Favori
|
||||||
|
702,Ventes de produits intermédiaires,,Produit,
|
||||||
|
703,Ventes de produits résiduels,,Produit,
|
||||||
|
704,Travaux,,Produit,
|
||||||
|
705,Études,,Produit,
|
||||||
|
706,Prestations de services,,Produit,Favori
|
||||||
|
7063,Parrainages,,Produit,
|
||||||
|
707,Ventes de marchandises,Ventes de produits achetés et revendus en l’état,Produit,Favori
|
||||||
|
7073,Ventes de dons en nature,,Produit,
|
||||||
|
708,Produits des activités annexes,,Produit,
|
||||||
|
7081,Produits des prestations fournies au personne,,Produit,
|
||||||
|
7083,Locations diverses,,Produit,
|
||||||
|
7085,Ports et frais accessoires facturés,,Produit,
|
||||||
|
7088,Autres produits d'activités annexes,,Produit,
|
||||||
|
709,RRR accordés,,Produit,
|
||||||
|
7091,RRR sur ventes de produits finis,,Produit,
|
||||||
|
7092,RRR sur ventes de produits intermédiaires,,Produit,
|
||||||
|
7094,RRR sur travaux,,Produit,
|
||||||
|
7095,RRR sur études,,Produit,
|
||||||
|
7096,RRR sur prest.de services,,Produit,
|
||||||
|
7097,RRR sur ventes marchandises,,Produit,
|
||||||
|
71,Production stockée,,Produit,
|
||||||
|
713,"Variation de stocks (en-cours, productions)",,Produit,
|
||||||
|
7133,Variation des en-cours de production de biens,,Produit,
|
||||||
|
7134,Variation des en-cours de production services,,Produit,
|
||||||
|
7135,Variations de stocks de produits,,Produit,
|
||||||
|
72,Production immobilisée corporelle,,Produit,
|
||||||
|
721,Production immobilisée incorporelle,,Produit,
|
||||||
|
722,Production immobilisée corporelle,,Produit,
|
||||||
|
73,Concours publics,,Produit,
|
||||||
|
730,Concours publics,,Produit,
|
||||||
|
74,Subventions d’exploitation,,Produit,
|
||||||
|
740,Subventions reçues,,Produit,Favori
|
||||||
|
748,Subventions d'exploitation diverses,,Produit,
|
||||||
|
75,Autres produits de gestion courante,,Produit,
|
||||||
|
751,"Redevances pour concessions, licences…",,Produit,
|
||||||
|
753,Versements des fondateurs ou consommation dot,,Produit,
|
||||||
|
7531,Versements des fondateurs,,Produit,
|
||||||
|
7532,Quotes-parts de dotation consomptible virée a,,Produit,
|
||||||
|
754,Ressources liées à la générosité du public,Dons reçus,Produit,Favori
|
||||||
|
7541,Dons manuels,,Produit,
|
||||||
|
75411,Dons manuels,,Produit,
|
||||||
|
75412,Abandons de frais par les bénévoles,,Produit,
|
||||||
|
7542,Mécénats,,Produit,
|
||||||
|
7543,"Legs, donations et assurances-vie",,Produit,
|
||||||
|
75431,Assurances-vie,,Produit,
|
||||||
|
75432,Legs ou donations,,Produit,
|
||||||
|
75433,Autres produits sur legs ou donations,,Produit,
|
||||||
|
755,Contributions financières,,Produit,
|
||||||
|
7551,Contributions financières d’autres organismes,,Produit,
|
||||||
|
7552,Quotes-parts de générosité reçues,,Produit,
|
||||||
|
756,Cotisations,Cotisations des adhérent⋅e⋅s,Produit,Favori
|
||||||
|
7561,Cotisations sans contrepartie,,Produit,
|
||||||
|
7562,Cotisations avec contrepartie,,Produit,
|
||||||
|
757,Gains de change / créances et dettes d’exploitation,,Produit,
|
||||||
|
758,Produits divers de gestion courante,,Produit,
|
||||||
|
7588,Autres produits divers de gestion courante,,Produit,
|
||||||
|
76,Produits financiers,,Produit,
|
||||||
|
761,Produits des participations,,Produit,
|
||||||
|
762,Produits des autres immobilisations financières,,Produit,
|
||||||
|
763,Revenus des autres créances,,Produit,
|
||||||
|
764,Revenus des valeurs mobilières de placement,,Produit,
|
||||||
|
765,Escomptes obtenus,,Produit,
|
||||||
|
766,Gains de change,,Produit,
|
||||||
|
767,Produits nets sur cession valeurs mobilières de placement,,Produit,
|
||||||
|
768,Autres produits financiers,,Produit,
|
||||||
|
77,Produits exceptionnels,,Produit,
|
||||||
|
771,Produits exceptionnels sur opération de gestion,,Produit,
|
||||||
|
7713,Libéralités perçues,,Produit,
|
||||||
|
7718,Autres produits exceptionnel sur opération de gestion,,Produit,
|
||||||
|
772,Produits sur exercices antérieurs,,Produit,
|
||||||
|
775,Produits des cessions d'actif,,Produit,
|
||||||
|
7754,Immobilisations reçues en legs ou donations à céder,,Produit,
|
||||||
|
777,Quote-part de subvention d'investissement virée au résultat,,Produit,
|
||||||
|
778,Autres produits exceptionnels,,Produit,
|
||||||
|
7780,Manifestations diverses,"Revenus provenant de manifestations au profit de l'association : droit d'entrée, location d'emplacement en vide grenier, ventes, etc.",Produit,Favori
|
||||||
|
78,"Reprises sur amortissement, dépréciations, engagements",,Produit,
|
||||||
|
781,Reprises / amortissements & provisions d'exploitation,,Produit,
|
||||||
|
7811,Amortissement immobilisations corporelles & incorporelles,,Produit,
|
||||||
|
7815,Reprises sur provisions d'exploitation,,Produit,
|
||||||
|
7816,Dépréciation immobilisations corporelles & incorporelles,,Produit,
|
||||||
|
78164,Reprises de dépréciations d’actifs reçus par legs ou donations destinés à être cédés,,Produit,
|
||||||
|
7817,Dépréciations actifs circulant,,Produit,
|
||||||
|
786,Reprises / amortissements & provisions financiers,,Produit,
|
||||||
|
7865,Risques et charges financiers,,Produit,
|
||||||
|
7866,Dépréciations des éléments financiers,,Produit,
|
||||||
|
787,Reprises sur amt & prov. exceptionnelles,,Produit,
|
||||||
|
7872,Provisions réglementées - Immobilisations,,Produit,
|
||||||
|
7873,Provisions réglementées - stocks,,Produit,
|
||||||
|
7874,Autres provisions réglementées,,Produit,
|
||||||
|
7875,Risques et charges,,Produit,
|
||||||
|
7876,Dépréciations exceptionnelles,,Produit,
|
||||||
|
789,Utilisations fonds reportés et de fonds dédiés,,Produit,
|
||||||
|
7891,Utilisations de fonds reportés,,Produit,
|
||||||
|
7894,Utilisations des fonds dédiés / subventions,,Produit,
|
||||||
|
7895,Utilisations des fonds dédiés / contributions,,Produit,
|
||||||
|
7896,Utilisations des fonds dédiés / générosité,,Produit,
|
||||||
|
79,Transfert de charges,,Produit,
|
||||||
|
791,Transferts de charges d'exploitation,,Produit,
|
||||||
|
796,Transferts de charges financières,,Produit,
|
||||||
|
797,Transferts de charges exceptionnelles,,Produit,
|
||||||
|
8,Classe 8 — Comptes spéciaux,,,
|
||||||
|
86,Emplois des contributions volontaires en nature,,,
|
||||||
|
860,Secours en nature,,Charge,Favori
|
||||||
|
8601,Alimentaires,,Charge,Favori
|
||||||
|
8602,Vestimentaires,,Charge,Favori
|
||||||
|
861,Mise à dispositions gratuites de biens,,Charge,Favori
|
||||||
|
8611,Locaux,,Charge,Favori
|
||||||
|
8612,Matériels,,Charge,Favori
|
||||||
|
862,Prestations,,Charge,Favori
|
||||||
|
864,Personnel bénévole,,Charge,Favori
|
||||||
|
87,Contributions volontaires en nature,,,
|
||||||
|
870,Dons en nature,,Produit,Favori
|
||||||
|
871,Prestations en nature,,Produit,Favori
|
||||||
|
875,Bénévolat,,Produit,Favori
|
||||||
|
89,Comptes de bilan,,,
|
||||||
|
890,Bilan d'ouverture,,Actif ou passif,
|
||||||
|
891,Bilan de clôture,,Actif ou passif,
|
|
111
src/include/data/charts/fr_pcc_2020.csv
Normal file
111
src/include/data/charts/fr_pcc_2020.csv
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
code,label,description,position,bookmark
|
||||||
|
1,"Classe 1 — Provisions, avances, subventions et emprunts",,Passif,
|
||||||
|
10,PROVISIONS ET AVANCES,,Passif,
|
||||||
|
103,Avances,,Passif,
|
||||||
|
106,Provisions pour travaux,Provisions pour travaux au titre de la délégation de pouvoirs accordée au conseil syndical,Passif,
|
||||||
|
11,REPORT À NOUVEAU (SOLDE CRÉDITEUR OU DÉBITEUR),,Passif,
|
||||||
|
110,Report à nouveau (solde créditeur),,Passif,
|
||||||
|
119,Report à nouveau (solde débiteur),,Passif,
|
||||||
|
12,Solde en attente sur travaux et opérations exceptionnelles,,Passif,
|
||||||
|
121,Travaux décidés par l'assemblée générale,,Passif,
|
||||||
|
122,Travaux délégués au conseil syndical ,,Passif,
|
||||||
|
13,SUBVENTIONS,,Passif,
|
||||||
|
131, Subventions accordées en instance de versement,,Passif,
|
||||||
|
138,Autres subventions d’investissement ,,Passif,
|
||||||
|
139,Subventions d’investissement inscrites au compte de résultat,,Passif,
|
||||||
|
4,Classe 4 — COPROPRIÉTAIRES ET TIERS,,Actif ou passif,
|
||||||
|
40,Fournisseurs,,Actif ou passif,
|
||||||
|
42,Personnel,,Actif ou passif,
|
||||||
|
43,SÉCURITÉ SOCIALE & AUTRES ORGANISMES SOCIAUX,,Passif,
|
||||||
|
431,Sécurité sociale,,Passif,
|
||||||
|
432,Autres organismes sociaux,,Passif,
|
||||||
|
44,ÉTAT ET COLLECTIVITÉS TERRITORIALES ,,Actif,
|
||||||
|
441,État et autres organismes - subventions à recevoir,,Actif,Favori
|
||||||
|
442,État - impôts et versements assimilés,,Actif ou passif,Favori
|
||||||
|
443,Collectivités territoriales – aides,,Actif ou passif,
|
||||||
|
45,COLLECTIVITÉ DES COPROPRIÉTAIRES,,Actif ou passif,
|
||||||
|
46,DÉBITEURS ET CRÉDITEUR DIVERS,,Actif ou passif,
|
||||||
|
47,COMPTES D'ATTENTE,,Actif ou passif,
|
||||||
|
471,Compte en attente d’imputation débiteur,,Actif ou passif,
|
||||||
|
472,Compte en attente d’imputation créditeur,,Actif ou passif,
|
||||||
|
48,COMPTES DE RÉGULARISATION,,Actif ou passif,
|
||||||
|
486,Charges payées d'avance,,Actif,Favori
|
||||||
|
487,Produits encaissés d’avance,,Passif,Favori
|
||||||
|
49,DÉPRÉCIATIONS DES COMPTES DE TIERS,,Actif ou passif,
|
||||||
|
491,Copropriétaires,,Passif,Favori
|
||||||
|
496,Personnes autres que les copropriétaires,,Passif,Favori
|
||||||
|
5,Classe 5 — Comptes financiers,,Actif,
|
||||||
|
50,FONDS PLACÉS,,Actif,
|
||||||
|
51,"Banques, ou fonds disponibles en banque pour le syndicat",,Actif,
|
||||||
|
5112,Chèques à encaisser,,Actif ou passif,Favori
|
||||||
|
5115,Paiements par carte à encaisser,,Actif ou passif,
|
||||||
|
512,Banques,,Actif ou passif,
|
||||||
|
53,Caisses,,Actif ou passif,
|
||||||
|
530,Caisse,,Actif ou passif,Favori
|
||||||
|
6,Classe 6 — Comptes de charges,,Charge,
|
||||||
|
60,ACHATS DE MATIÈRES ET FOURNITURES,,Charge,
|
||||||
|
601,Eau,,Charge,Favori
|
||||||
|
602,Électricité,,Charge,Favori
|
||||||
|
603,"Chauffage, énergie et combustibles",,Charge,Favori
|
||||||
|
604,Achats produits d'entretien et petits équipements,,Charge,Favori
|
||||||
|
605,Matériel,,Charge,Favori
|
||||||
|
606,Fournitures,,Charge,Favori
|
||||||
|
61,SERVICES EXTÉRIEURS,,Charge,
|
||||||
|
611,Nettoyage des locaux,,Charge,Favori
|
||||||
|
612,Locations immobilières,,Charge,Favori
|
||||||
|
613,Locations mobilières,,Charge,
|
||||||
|
614,Contrats de maintenance,,Charge,Favori
|
||||||
|
615,Entretien et petites réparations,,Charge,Favori
|
||||||
|
616,Primes d'assurance,,Charge,Favori
|
||||||
|
62,FRAIS D’ADMINISTRATION ET HONORAIRES,,Charge,
|
||||||
|
621,Rémunération du syndic sur gestion copropriété,,Charge,
|
||||||
|
6211,Rémunération du syndic,,Charge,
|
||||||
|
6212,Débours,,Charge,
|
||||||
|
6213,Frais postaux,,Charge,Favori
|
||||||
|
622,Autres honoraires du syndic,,Charge,
|
||||||
|
6221,Honoraires travaux,,Charge,Favori
|
||||||
|
6222,Prestations particulières,,Charge,
|
||||||
|
6223,Autres honoraires,,Charge,
|
||||||
|
623,Rémunérations de tiers intervenants,,Charge,
|
||||||
|
624,Frais du conseil syndical,,Charge,
|
||||||
|
63,"IMPÔTS, TAXES ET VERSEMENTS ASSIMILÉS",,Charge,
|
||||||
|
632,Taxe de balayage,,Charge,Favori
|
||||||
|
633,Taxe foncière,,Charge,Favori
|
||||||
|
634,Autre impôt et taxe,,Charge,Favori
|
||||||
|
64,FRAIS DE PERSONNEL,,Charge,
|
||||||
|
641,Salaires,,Charge,Favori
|
||||||
|
642,Charges sociales et organismes sociaux,,Charge,Favori
|
||||||
|
644,"Autres (médecine du travail, mutuelle, etc.)",,Charge,Favori
|
||||||
|
65,MONTANT SPÉCIFIQUE ALLOUÉ AU CONSEIL SYNDICAL,"Montant spécifique alloué au conseil syndical, au sein du budget prévisionnel, pour l'exercice de sa délégation de pouvoirs",Charge,
|
||||||
|
66,"CHARGES FINANCIÈRES DES EMPRUNTS, AGIOS OU AUTRES",,Charge,
|
||||||
|
661,Remboursements d'annuités d'emprunt,,Charge,Favori
|
||||||
|
662,Autres charges financières et agios,,Charge,
|
||||||
|
67,CHARGES POUR TRAVAUX ET OPÉRATIONS EXCEPTIONNELLES,,Charge,
|
||||||
|
671,Travaux décidés par l’assemblée générale,,Charge,Favori
|
||||||
|
672,Travaux urgents,,Charge,Favori
|
||||||
|
673,"Études techniques, diagnostic, consultation",,Charge,
|
||||||
|
677,Pertes sur créances irrécouvrables,,Charge,
|
||||||
|
678,Charges exceptionnelles,,Charge,
|
||||||
|
68,DOTATIONS AUX DÉPRÉCIATIONS SUR CRÉANCES DOUTEUSES,,Charge,
|
||||||
|
7,Classe 7 — Comptes de produits,,Produit,
|
||||||
|
70,APPELS DE FONDS,,Produit,
|
||||||
|
701,Provisions sur opérations courantes,,Produit,Favori
|
||||||
|
702,Provisions sur travaux de l’article 14-2 et opérations exceptionnelles,,Produit,
|
||||||
|
703,Avances,,Produit,Favori
|
||||||
|
704,Remboursements d’annuités d’emprunts,,Produit,
|
||||||
|
705,Études,,Produit,
|
||||||
|
706,Provisions au titre de la délégation de pouvoirs accordée au conseil syndical,,Produit,Favori
|
||||||
|
7061,Provisions sur opérations courantes,,Produit,Favori
|
||||||
|
7062,Provisions sur travaux et opérations exceptionnelles,,Produit,
|
||||||
|
71,AUTRES PRODUITS,,Produit,
|
||||||
|
711,Subventions,,Produit,Favori
|
||||||
|
712,Emprunts,,Produit,Favori
|
||||||
|
713,Indemnités d’assurance,,Produit,
|
||||||
|
714,Produits divers (dont intérêts légaux dus par les copropriétaires),,Produit,
|
||||||
|
716,Produits financiers,,Produit,Favori
|
||||||
|
718,Produits exceptionnels,,Produit,
|
||||||
|
78,REPRISES DE DÉPRÉCIATIONS SUR CRÉANCES DOUTEUSES,Reprises de dépréciations sur créances douteuses,Produit,
|
||||||
|
8,Classe 8 — Comptes spéciaux,,,
|
||||||
|
89,COMPTES DE BILAN,,,
|
||||||
|
890,Bilan d'ouverture,,Actif ou passif,
|
||||||
|
891,Bilan de clôture,,Actif ou passif,
|
|
367
src/include/data/charts/fr_pcg_2014.csv
Normal file
367
src/include/data/charts/fr_pcg_2014.csv
Normal file
|
@ -0,0 +1,367 @@
|
||||||
|
code,label,description,position,bookmark
|
||||||
|
1,COMPTES DE CAPITAUX,,Passif,
|
||||||
|
10,CAPITAL ET RÉSERVES,,Passif,
|
||||||
|
101,Capital,,Passif,
|
||||||
|
1011,Capital souscrit -non appelé,,Passif,
|
||||||
|
1012,"Capital souscrit -appelé, non versé",,Passif,
|
||||||
|
1013,"Capital souscrit - appelé, versé",,Passif,
|
||||||
|
102,Fonds fiduciaires,,Passif,
|
||||||
|
104,Primes liées au capital social,,Passif,
|
||||||
|
105,Écarts de réévaluation,,Passif,
|
||||||
|
106,Réserves,,Passif,
|
||||||
|
1068,Autres réserves,,Passif,
|
||||||
|
107,Écart d’équivalence,,Passif,
|
||||||
|
108,Compte de l’exploitant,,Passif,
|
||||||
|
109,Actionnaires : capital souscrit – non appelé,,Passif,
|
||||||
|
11,REPORT À NOUVEAU (SOLDE CRÉDITEUR OU DÉBITEUR),,Passif,
|
||||||
|
110,Report à nouveau (solde créditeur),,Passif,
|
||||||
|
119,Report à nouveau (solde débiteur),,Passif,
|
||||||
|
12,RÉSULTAT DE L’EXERCICE (BÉNÉFICE OU PERTE),,Passif,
|
||||||
|
120,Résultat de l’exercice (bénéfice),,Passif,
|
||||||
|
129,Résultat de l’exercice (perte),,Passif,
|
||||||
|
13,SUBVENTIONS D’INVESTISSEMENT,,Passif,
|
||||||
|
131,Subventions d’équipement,,Passif,
|
||||||
|
1311,État,,Passif,
|
||||||
|
1312,Régions,,Passif,
|
||||||
|
1313,Départements,,Passif,
|
||||||
|
1314,Communes,,Passif,
|
||||||
|
1315,Collectivités publiques,,Passif,
|
||||||
|
1316,Entreprises publiques,,Passif,
|
||||||
|
1317,Entreprises et organismes privés,,Passif,
|
||||||
|
1318,Autres,,Passif,
|
||||||
|
138,Autres subventions d’investissement,"Même ventilation que celle du compte 131, à rajouter si nécessaire",Passif,
|
||||||
|
139,Subventions d’investissement inscrites au compte de résultat,,Passif,
|
||||||
|
1391,"Subventions d'équipement","Même ventilation que celle du compte 131, à rajouter si nécessaire",Passif,
|
||||||
|
1398,Autres subventions d’investissement ,"Même ventilation que celle du compte 131, à rajouter si nécessaire",Passif,
|
||||||
|
14,PROVISIONS RÉGLEMENTÉES,,Passif,
|
||||||
|
142,Provisions réglementées relatives aux immobilisations,,Passif,
|
||||||
|
143,Provisions réglementées relatives aux stocks,,Passif,
|
||||||
|
144,Provisions réglementées relatives aux autres éléments de l’actif,,Passif,
|
||||||
|
145,Amortissements dérogatoires,,Passif,
|
||||||
|
146,Provision spéciale de réévaluation,,Passif,
|
||||||
|
147,Plus-values réinvesties,,Passif,
|
||||||
|
148,Autres provisions réglementées,,Passif,
|
||||||
|
15,PROVISIONS POUR RISQUES ET CHARGES,,Passif,
|
||||||
|
151,Provisions pour risques,,Passif,
|
||||||
|
153,Provisions pour pensions et obligations similaires,,Passif,
|
||||||
|
154,Provisions pour restructurations,,Passif,
|
||||||
|
155,Provisions pour impôts,,Passif,
|
||||||
|
156,Provisions pour renouvellement des immobilisations (entreprises concessionnaires),,Passif,
|
||||||
|
157,Provisions pour charges à répartir sur plusieurs exercices,,Passif,
|
||||||
|
158,Autres provisions pour charges,,Passif,
|
||||||
|
16,EMPRUNTS ET DETTES ASSIMILÉES,,Passif,
|
||||||
|
161,Emprunts obligataires convertibles,,Passif,
|
||||||
|
163,Autres emprunts obligataires,,Passif,
|
||||||
|
164,Emprunts auprès des établissements de crédit,,Passif,
|
||||||
|
165,Dépôts et cautionnements reçus,,Passif,
|
||||||
|
166,Participation des salariés aux résultats,,Passif,
|
||||||
|
167,Emprunts et dettes assortis de conditions particulières,,Passif,
|
||||||
|
168,Autres emprunts et dettes assimilées,,Passif,
|
||||||
|
169,Primes de remboursement des obligations,,Passif,
|
||||||
|
17,DETTES RATTACHÉES À DES PARTICIPATIONS,,Passif,
|
||||||
|
171,Dettes rattachées à des participations (groupe),,Passif,
|
||||||
|
174,Dettes rattachées à des participations (hors groupe),,Passif,
|
||||||
|
178,Dettes rattachées à des sociétés en participation,,Passif,
|
||||||
|
18,COMPTES DE LIAISON DES ÉTABLISSEMENTS ET SOCIÉTÉS EN PARTICIPATION,,Passif,
|
||||||
|
181,Comptes de liaison des établissements,,Passif,
|
||||||
|
186,Biens et prestations de services échangés entre établissements (charges),,Passif,
|
||||||
|
187,Biens et prestations de services échangés entre établissements (produits),,Passif,
|
||||||
|
188,Comptes de liaison des sociétés en participation,,Passif,
|
||||||
|
2,COMPTES D’IMMOBILISATIONS,,Actif,
|
||||||
|
20,IMMOBILISATIONS INCORPORELLES,,Actif,
|
||||||
|
201,Frais d’établissement,,Actif,
|
||||||
|
203,Frais de recherche et de développement,,Actif,
|
||||||
|
205,"Concessions et droits similaires, brevets, licences, marques, procédés, logiciels, droits et valeurs similaires",,Actif,
|
||||||
|
206,Droit au bail,,Actif,
|
||||||
|
207,Fonds commercial,,Actif,
|
||||||
|
208,Autres immobilisations incorporelles,,Actif,
|
||||||
|
21,IMMOBILISATIONS CORPORELLES,,Actif,
|
||||||
|
211,Terrains,"Au besoin, créer des sous-comptes 2111 et suivants : Terrains nus, Terrains aménagés, Sous - sols et sursols, Terrains de gisement et Terrains bâtis.",Actif,
|
||||||
|
212,Agencements et aménagements de terrains (même ventilation que celle du compte 211,(même ventilation que celle du compte 211) ,Actif,
|
||||||
|
213,Constructions,,Actif,
|
||||||
|
214,Constructions sur sol d’autrui (même ventilation que celle du compte 213,,Actif,
|
||||||
|
215,"Installations techniques, matériels et outillage industriels",,Actif,
|
||||||
|
218,Autres immobilisations corporelles,,Actif,
|
||||||
|
22,IMMOBILISATIONS MISES EN CONCESSION,,Actif,
|
||||||
|
23,IMMOBILISATIONS EN COURS,,Actif,
|
||||||
|
231,Immobilisations corporelles en cours,,Actif,
|
||||||
|
232,Immobilisations incorporelles en cours,,Actif,
|
||||||
|
237,Avances et acomptes versés sur immobilisations incorporelles,,Actif,
|
||||||
|
238,Avances et acomptes versés sur commandes d’immobilisations corporelles,,Actif,
|
||||||
|
25,PARTS DANS DES ENTREPRISES LIÉES ET CRÉANCES SUR DES ENTREPRISES LIÉES,,Actif,
|
||||||
|
26,PARTICIPATIONS ET CRÉANCES RATTACHÉES À DES PARTICIPATIONS,,Actif,
|
||||||
|
261,Titres de participation,,Actif,
|
||||||
|
266,Autres formes de participation,,Actif,
|
||||||
|
267,Créances rattachées à des participations,,Actif,
|
||||||
|
268,Créances rattachées à des sociétés en participation,,Actif,
|
||||||
|
269,Versements restant à effectuer sur titres de participation non libérés,,Actif,
|
||||||
|
27,AUTRES IMMOBILISATIONS FINANCIÈRES,,Actif,
|
||||||
|
271,Titres immobilisés autres que les titres immobilisés de l’activité de portefeuille (droit de propriété),,Actif,
|
||||||
|
272,Titres immobilisés (droit de créance),,Actif,
|
||||||
|
273,Titres immobilisés de l’activité de portefeuille,,Actif,
|
||||||
|
274,Prêts,,Actif,
|
||||||
|
275,Dépôts et cautionnements versés,,Actif,
|
||||||
|
276,Autres créances immobilisées,,Actif,
|
||||||
|
277,(Actions propres ou parts propres),,Actif,
|
||||||
|
278,Mali de fusion sur actifs financiers,,Actif,
|
||||||
|
279,Versements restant à effectuer sur titres immobilisés non libérés,,Actif,
|
||||||
|
28,AMORTISSEMENTS DES IMMOBILISATIONS,,Actif,
|
||||||
|
280,Amortissements des immobilisations incorporelles,,Actif,
|
||||||
|
281,Amortissements des immobilisations corporelles,,Actif,
|
||||||
|
282,Amortissements des immobilisations mises en concession,,Actif,
|
||||||
|
29,DÉPRÉCIATIONS DES IMMOBILISATIONS,,Actif,
|
||||||
|
290,Dépréciations des immobilisations incorporelles,,Actif,
|
||||||
|
291,Dépréciations des immobilisations corporelles ,Même ventilation que celle du compte 21,Actif,
|
||||||
|
292,Dépréciations des immobilisations mises en concession,,Actif,
|
||||||
|
293,Dépréciations des immobilisations en cours,,Actif,
|
||||||
|
296,Provisions pour dépréciation des participations et créances rattachées à des participations,,Actif,
|
||||||
|
297,Provisions pour dépréciation des autres immobilisations financières,,Actif,
|
||||||
|
3,COMPTES DE STOCKS ET EN-COURS,,Actif,
|
||||||
|
31,MATIÈRES PREMIÈRES (ET FOURNITURES),,Actif,
|
||||||
|
311,Matières (ou groupe) A,,Actif,
|
||||||
|
312,Matières (ou groupe) B,,Actif,
|
||||||
|
317,"Fournitures A, B, C",,Actif,
|
||||||
|
32,AUTRES APPROVISIONNEMENTS,,Actif,
|
||||||
|
321,Matières consommables,,Actif,
|
||||||
|
322,Fournitures consommables,,Actif,
|
||||||
|
326,Emballages,,Actif,
|
||||||
|
33,EN-COURS DE PRODUCTION DE BIENS,,Actif,
|
||||||
|
331,Produits en cours,,Actif,
|
||||||
|
335,Travaux en cours,,Actif,
|
||||||
|
34,EN-COURS DE PRODUCTION DE SERVICES,,Actif,
|
||||||
|
341,Études en cours,,Actif,
|
||||||
|
345,Prestations de services en cours,,Actif,
|
||||||
|
35,STOCKS DE PRODUITS,,Actif,
|
||||||
|
351,Produits intermédiaires,,Actif,
|
||||||
|
355,Produits finis,,Actif,
|
||||||
|
358,Produits résiduels (ou matières de récupération),,Actif,
|
||||||
|
37,STOCKS DE MARCHANDISES,,Actif,
|
||||||
|
371,Marchandises (ou groupe) A,,Actif,
|
||||||
|
372,Marchandises (ou groupe) B,,Actif,
|
||||||
|
39,PROVISIONS POUR DÉPRÉCIATION DES STOCKS ET EN-COURS,,Actif,
|
||||||
|
391,Provisions pour dépréciation des matières premières (et fournitures),,Actif,
|
||||||
|
392,Provisions pour dépréciation des autres approvisionnements,,Actif,
|
||||||
|
393,Provisions pour dépréciation des en-cours de production de biens,,Actif,
|
||||||
|
394,Provisions pour dépréciation des en-cours de production de services,,Actif,
|
||||||
|
395,Provisions pour dépréciation des stocks de produits,,Actif,
|
||||||
|
397,Provisions pour dépréciation des stocks de marchandises,,Actif,
|
||||||
|
4,COMPTES DE TIERS,,Actif ou passif,
|
||||||
|
40,FOURNISSEURS ET COMPTES RATTACHÉS,,Actif ou passif,
|
||||||
|
400,Fournisseurs et Comptes rattachés,,Actif ou passif,
|
||||||
|
401,Fournisseurs,,Actif ou passif,
|
||||||
|
403,Fournisseurs – Effets à payer,,Passif,
|
||||||
|
404,Fournisseurs d’immobilisations,,Actif ou passif,
|
||||||
|
405,Fournisseurs d’immobilisations – Effets à payer,,Passif,
|
||||||
|
408,Fournisseurs – Factures non parvenues,,Passif,
|
||||||
|
409,Fournisseurs débiteurs,,Actif,
|
||||||
|
41,CLIENTS ET COMPTES RATTACHÉS,,Actif ou passif,
|
||||||
|
410,Clients et comptes rattachés,,Actif ou passif,
|
||||||
|
411,Clients,,Actif ou passif,
|
||||||
|
413,Clients – Effets à recevoir,,Actif,
|
||||||
|
416,Clients douteux ou litigieux,,Actif,
|
||||||
|
418,Clients – Produits non encore facturés,,Actif,
|
||||||
|
419,Clients créditeurs,,Passif,
|
||||||
|
42,PERSONNEL ET COMPTES RATTACHÉS,,Actif ou passif,
|
||||||
|
421,Personnel – Rémunérations dues,,Passif,
|
||||||
|
422,"Comités d’entreprises, d’établissement,…",,Actif ou passif,
|
||||||
|
424,Participation des salariés aux résultats,,Actif,
|
||||||
|
425,Personnel – Avances et acomptes,,Actif,
|
||||||
|
426,Personnel – Dépôts,,Passif,
|
||||||
|
427,Personnel – Oppositions,,Passif,
|
||||||
|
428,Personnel – Charges à payer et produits à recevoir,,Passif,
|
||||||
|
43,SÉCURITÉ SOCIALE ET AUTRES ORGANISMES SOCIAUX,,Passif,
|
||||||
|
431,Sécurité sociale,,Passif,
|
||||||
|
437,Autres organismes sociaux,,Passif,
|
||||||
|
438,Organismes sociaux – Charges à payer et produits à recevoir,,Passif,
|
||||||
|
44,ÉTAT ET AUTRES COLLECTIVITÉS PUBLIQUES,,Actif,
|
||||||
|
441,État – Subventions à recevoir,,Actif,
|
||||||
|
442," Contributions, impôts et taxes recouvrés pour le compte de l’État ",,Passif,
|
||||||
|
443,"Opérations particulières avec l’État, les collectivités publiques, les organismes internationaux",,Actif ou passif,
|
||||||
|
444,État – Impôts sur les bénéfices,,Actif ou passif,
|
||||||
|
445,État – Taxes sur le chiffre d’affaires,,Actif,
|
||||||
|
446,Obligations cautionnées,,Actif,
|
||||||
|
447,"Autres impôts, taxes et versements assimilés",,Actif,
|
||||||
|
448,État – Charges à payer et produits à recevoir,,Actif ou passif,
|
||||||
|
449,Quotas d’émission à acquérir,,Passif,
|
||||||
|
45,GROUPE ET ASSOCIÉS,,Actif ou passif,
|
||||||
|
451,Groupe,,Actif ou passif,
|
||||||
|
455,Associés – Comptes courants,,Actif ou passif,
|
||||||
|
456,Associés – Opérations sur le capital,,Actif,
|
||||||
|
457,Associés – Dividendes à payer,,Passif,
|
||||||
|
458,Associés – Opérations faites en commun et en G.I.E.,,Actif ou passif,
|
||||||
|
46,DÉBITEURS DIVERS ET CRÉDITEURS DIVERS,,Actif ou passif,
|
||||||
|
462,Créances sur cessions d’immobilisations,,Actif,
|
||||||
|
464,Dettes sur acquisitions de valeurs mobilières de placement,,Passif,
|
||||||
|
465,Créances sur cessions de valeurs mobilières de placement,,Actif,
|
||||||
|
467,Autres comptes débiteurs ou créditeurs,,Actif ou passif,
|
||||||
|
468,Divers – Charges à payer et produits à recevoir,,Actif ou passif,
|
||||||
|
4686,Charges à payer,,Passif,
|
||||||
|
4687,Produits à recevoir,,Actif,
|
||||||
|
47,COMPTES TRANSITOIRES OU D’ATTENTE,,Actif ou passif,
|
||||||
|
471,à 475 comptes d’attente,,Actif ou passif,
|
||||||
|
476,Différence de conversion – Actif,,Actif,
|
||||||
|
477,Différences de conversion – Passif,,Passif,
|
||||||
|
478,Autres comptes transitoires,,Actif ou passif,
|
||||||
|
48,COMPTES DE RÉGULARISATION,,Actif ou passif,
|
||||||
|
481,Charges à répartir sur plusieurs exercices,,Passif,
|
||||||
|
486,Charges constatées d’avance,,Actif,
|
||||||
|
487,Produits constatés d’avance,,Passif,
|
||||||
|
488,Comptes de répartition périodique des charges et des produits,,Actif ou passif,
|
||||||
|
489,Quotas d’émission alloués par l’État,,Actif,
|
||||||
|
49,PROVISIONS POUR DÉPRÉCIATION DES COMPTES DE TIERS,,Actif ou passif,
|
||||||
|
491,Provisions pour dépréciation des comptes de clients,,Passif,
|
||||||
|
495,Provisions pour dépréciation des comptes du groupe et des associés,,Passif,
|
||||||
|
496,Provisions pour dépréciation des comptes de débiteurs divers,,Passif,
|
||||||
|
5,COMPTES FINANCIERS,,Actif,
|
||||||
|
50,VALEURS MOBILIÈRES DE PLACEMENT,,Actif,
|
||||||
|
501,Parts dans des entreprises liées,,Actif,
|
||||||
|
502,Actions propres,,Actif,
|
||||||
|
503,Actions,,Actif,
|
||||||
|
504,Autres titres conférant un droit de propriété,,Actif,
|
||||||
|
505,Obligations et bons émis par la société et rachetés par elle,,Actif,
|
||||||
|
506,Obligations,,Actif,
|
||||||
|
507,Bons du Trésor et bons de caisse à court terme,,Actif,
|
||||||
|
508,Autres valeurs mobilières de placement et autres créances assimilées,,Actif,
|
||||||
|
509,Versements restant à effectuer sur valeurs mobilières de placement non libérées,,Actif,
|
||||||
|
51,"BANQUES, ÉTABLISSEMENTS FINANCIERS ET ASSIMILÉS",,Actif,
|
||||||
|
511,Valeurs à l’encaissement,,Actif ou passif,Favori
|
||||||
|
512,Banques,,Actif ou passif,
|
||||||
|
512A,Compte courant,,Actif ou passif,Favori
|
||||||
|
514,Chèques postaux,,Actif ou passif,Favori
|
||||||
|
515,« Caisses » du Trésor et des établissements publics,,Actif ou passif,
|
||||||
|
516,Sociétés de bourse,,Actif,
|
||||||
|
517,Autres organismes financiers,,Actif ou passif,
|
||||||
|
518,Intérêts courus,,Actif ou passif,
|
||||||
|
519,Concours bancaires courants,,Actif ou passif,
|
||||||
|
52,INSTRUMENTS DE TRÉSORERIE,,Actif ou passif,
|
||||||
|
53,CAISSE,,Actif ou passif,
|
||||||
|
531,Caisse siège social,,Actif ou passif,Favori
|
||||||
|
532,Caisse succursale (ou usine) A,,Actif ou passif,
|
||||||
|
533,Caisse succursale (ou usine) B,,Actif ou passif,
|
||||||
|
54,RÉGIES D’AVANCE ET ACCRÉDITIFS,,Actif ou passif,
|
||||||
|
58,VIREMENTS INTERNES,,Actif ou passif,
|
||||||
|
59,DÉPRÉCIATION DES COMPTES FINANCIERS,,Actif ou passif,
|
||||||
|
590,Provisions pour dépréciation des valeurs mobilières de placement,,Passif,
|
||||||
|
6,COMPTES DE CHARGES,,Charge,
|
||||||
|
60,ACHATS (SAUF 603),,Charge,
|
||||||
|
601,Achats stockés – Matières premières (et fournitures),,Charge,Favori
|
||||||
|
602,Achats stockés – Autres approvisionnements,,Charge,Favori
|
||||||
|
604,Achats d’études et prestations de services,,Charge,Favori
|
||||||
|
605,"Achats de matériel, équipements et travaux",,Charge,Favori
|
||||||
|
606,Achats non stockés de matière et fournitures,"On peut rajouter des sous-comptes : eau, électricité, etc.",Charge,Favori
|
||||||
|
607,Achats de marchandises,,Charge,Favori
|
||||||
|
608,"(Compte réservé, le cas échéant, à la récapitulation des frais accessoires incorporés aux achats)",,Charge,
|
||||||
|
609,"Rabais, remises et ristournes obtenus sur achats",,Charge,
|
||||||
|
603,Variations des stocks (approvisionnements et marchandises),,Charge,
|
||||||
|
61,SERVICES EXTÉRIEURS,,Charge,
|
||||||
|
611,Sous-traitance générale,,Charge,
|
||||||
|
612,Redevances de crédit-bail,,Charge,
|
||||||
|
613,Locations,,Charge,Favori
|
||||||
|
614,Charges locatives et de copropriété,,Charge,Favori
|
||||||
|
615,Entretien et réparations,,Charge,
|
||||||
|
616,Primes d’assurances,,Charge,Favori
|
||||||
|
617,Études et recherches,,Charge,
|
||||||
|
618,Divers,,Charge,
|
||||||
|
619,"Rabais, remises et ristournes obtenus sur services extérieurs",,Charge,
|
||||||
|
62,AUTRES SERVICES EXTÉRIEURS,,Charge,
|
||||||
|
621,Personnel extérieur à l’entreprise,,Charge,
|
||||||
|
622,Rémunérations d’intermédiaires et honoraires,,Charge,
|
||||||
|
623,"Publicité, publications, relations publiques",,Charge,
|
||||||
|
624,Transports de biens et transports collectifs du personnel,Ne comprend pas les transports de l’exploitant,Charge,
|
||||||
|
625,"Déplacements, missions et réceptions",,Charge,Favori
|
||||||
|
626,Frais postaux et de télécommunications,,Charge,Favori
|
||||||
|
627,Services bancaires et assimilés,,Charge,Favori
|
||||||
|
628,Divers,,Charge,
|
||||||
|
629,"Rabais, remises et ristournes obtenus sur autres services extérieurs",,Charge,
|
||||||
|
63,"IMPÔTS, TAXES ET VERSEMENTS ASSIMILÉS",,Charge,
|
||||||
|
631,"Impôts, taxes et versements assimilés sur rémunérations (administrations des impôts)",,Charge,
|
||||||
|
633,"Impôts, taxes et versements assimilés sur rémunérations (autres organismes)",,Charge,
|
||||||
|
635,"Autres impôts, taxes et versements assimilés (administrations des impôts)",,Charge,
|
||||||
|
637,"Autres impôts, taxes et versements assimilés (autres organismes)",,Charge,
|
||||||
|
64,CHARGES DE PERSONNEL,,Charge,
|
||||||
|
641,Rémunérations du personnel,,Charge,
|
||||||
|
644,Rémunération du travail de l’exploitant,,Charge,Favori
|
||||||
|
645,Charges de sécurité sociale et de prévoyance,,Charge,Favori
|
||||||
|
6451,Cotisations à l’Urssaf,,Charge,Favori
|
||||||
|
646,Cotisations sociales personnelles de l’exploitant,,Charge,Favori
|
||||||
|
647,Autres charges sociales,,Charge,
|
||||||
|
648,Autres charges de personnel,,Charge,
|
||||||
|
65,AUTRES CHARGES DE GESTION COURANTE,,Charge,
|
||||||
|
651,"Redevances pour concessions, brevets, licences, marques, procédés, logiciels, droits et valeurs similaires",,Charge,
|
||||||
|
653,Jetons de présence,,Charge,
|
||||||
|
654,Pertes sur créances irrécouvrables,,Charge,
|
||||||
|
655,Quote-part de résultat sur opérations faites en commun,,Charge,
|
||||||
|
658,Charges diverses de gestion courante,,Charge,
|
||||||
|
66,CHARGES FINANCIÈRES,,Charge,
|
||||||
|
661,Charges d’intérêts,,Charge,
|
||||||
|
664,Pertes sur créances liées à des participations,,Charge,
|
||||||
|
665,Escomptes accordés,,Charge,
|
||||||
|
666,Pertes de change,,Charge,
|
||||||
|
667,Charges nettes sur cessions de valeurs mobilières de placement,,Charge,
|
||||||
|
668,Autres charges financières,,Charge,
|
||||||
|
67,CHARGES EXCEPTIONNELLES,,Charge,
|
||||||
|
671,Charges exceptionnelles sur opérations de gestion,,Charge,
|
||||||
|
672,"(Compte à la disposition des entités pour enregistrer, en cours d’exercice, les charges sur exercices antérieurs)",,Charge,
|
||||||
|
675,Valeurs comptables des éléments d’actif cédés,,Charge,
|
||||||
|
678,Autres charges exceptionnelles,,Charge,
|
||||||
|
68,DOTATIONS AUX AMORTISSEMENTS ET AUX PROVISIONS,,Charge,
|
||||||
|
681,Dotations aux amortissements et aux provisions – Charges d’exploitation,,Charge,
|
||||||
|
686,Dotations aux amortissements et aux provisions – Charges financières,,Charge,
|
||||||
|
687,Dotations aux amortissements et aux provisions – Charges exceptionnelles,,Charge,
|
||||||
|
69,PARTICIPATION DES SALARIÉS – IMPÔTS SUR LES BÉNÉFICES ET ASSIMILÉS,,Charge,
|
||||||
|
691,Participation des salariés aux résultats,,Charge,
|
||||||
|
695,Impôts sur les bénéfices,,Charge,
|
||||||
|
696,Suppléments d’impôt sur les sociétés liés aux distributions,,Charge,
|
||||||
|
697,Imposition forfaitaire annuelle des sociétés,,Charge,
|
||||||
|
698,Intégration fiscale,,Charge,
|
||||||
|
699,Produits – Reports en arrière des déficits,,Charge,
|
||||||
|
7,COMPTES DE PRODUITS,,Produit,
|
||||||
|
70,"VENTES DE PRODUITS FABRIQUÉS, PRESTATIONS DE SERVICES, MARCHANDISES",,Produit,
|
||||||
|
701,Ventes de produits finis,,Produit,Favori
|
||||||
|
702,Ventes de produits intermédiaires,,Produit,Favori
|
||||||
|
703,Ventes de produits résiduels,,Produit,Favori
|
||||||
|
704,Travaux,,Produit,Favori
|
||||||
|
705,Études,,Produit,Favori
|
||||||
|
706,Prestations de services,,Produit,Favori
|
||||||
|
707,Ventes de marchandises,,Produit,Favori
|
||||||
|
708,Produits des activités annexes,,Produit,
|
||||||
|
709,"Rabais, remises et ristournes accordés par l’entreprise",,Produit,
|
||||||
|
71,PRODUCTION STOCKÉE (OU DÉSTOCKAGE),,Produit,
|
||||||
|
713,"Variation des stocks (en-cours de production, produits)",,Produit,
|
||||||
|
72,PRODUCTION IMMOBILISÉE,,Produit,
|
||||||
|
721,Immobilisations incorporelles,,Produit,
|
||||||
|
722,Immobilisations corporelles,,Produit,
|
||||||
|
74,SUBVENTIONS D’EXPLOITATION,,Produit,
|
||||||
|
75,AUTRES PRODUITS DE GESTION COURANTE,,Produit,
|
||||||
|
751,"Redevances pour concessions, brevets, licences, marques, procédés, logiciels, droits et valeurs similaires",,Produit,
|
||||||
|
752,Revenus des immeubles non affectés à des activités professionnelles,,Produit,
|
||||||
|
753,"Jetons de présence et rémunérations d’administrateurs, gérants…",,Produit,
|
||||||
|
754,Ristournes perçues des coopératives (provenant des excédents),,Produit,
|
||||||
|
755,Quotes-parts de résultat sur opérations faites en commun,,Produit,
|
||||||
|
758,Produits divers de gestion courante,,Produit,
|
||||||
|
76,PRODUITS FINANCIERS,,Produit,
|
||||||
|
761,PRODUITS DE PARTICIPATIONS,,Produit,
|
||||||
|
762,Produits des autres immobilisations financières,,Produit,
|
||||||
|
763,Revenus des autres créances,,Produit,
|
||||||
|
764,Revenus des valeurs mobilières de placement,,Produit,
|
||||||
|
765,Escomptes obtenus,,Produit,
|
||||||
|
766,Gains de change,,Produit,
|
||||||
|
767,Produits nets sur cessions de valeurs mobilières de placement,,Produit,
|
||||||
|
768,Autres produits financiers,,Produit,
|
||||||
|
77,Produits exceptionnels,,Produit,
|
||||||
|
771,Produits exceptionnels sur opérations de gestion,,Produit,
|
||||||
|
772,"(Compte à la disposition des entités pour enregistrer, en cours d’exercice, les produits sur exercices antérieurs)",,Produit,
|
||||||
|
775,Produits des cessions d’éléments d’actif,,Produit,
|
||||||
|
777,Quote-part des subventions d’investissement virée au résultat de l’exercice,,Produit,
|
||||||
|
778,Autres produits exceptionnels,,Produit,
|
||||||
|
78,REPRISES SUR AMORTISSEMENTS ET PROVISIONS,,Produit,
|
||||||
|
781,Reprises sur amortissements et provisions (à inscrire dans les produits d’exploitation),,Produit,
|
||||||
|
786,Reprises sur provisions pour risques (à inscrire dans les produits financiers),,Produit,
|
||||||
|
787,Reprises sur provisions (à inscrire dans les produits exceptionnels),,Produit,
|
||||||
|
79,TRANSFERTS DE CHARGES,,Produit,
|
||||||
|
791,Transferts de charges d’exploitation,,Produit,
|
||||||
|
796,Transferts de charges financières,,Produit,
|
||||||
|
797,Transferts de charges exceptionnelles,,Produit,
|
||||||
|
89,COMPTES DE BILAN,,,
|
||||||
|
890,Bilan d'ouverture,,Actif ou passif,
|
||||||
|
891,Bilan de clôture,,Actif ou passif,
|
|
1041
src/include/data/charts/fr_pcs_2018.csv
Normal file
1041
src/include/data/charts/fr_pcs_2018.csv
Normal file
File diff suppressed because it is too large
Load diff
3738
src/include/data/dictionary.fr
Normal file
3738
src/include/data/dictionary.fr
Normal file
File diff suppressed because it is too large
Load diff
1
src/include/data/schema.sql
Symbolic link
1
src/include/data/schema.sql
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../migrations/1.3/schema.sql
|
162
src/include/data/users_fields_presets.ini
Normal file
162
src/include/data/users_fields_presets.ini
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
; Ce fichier contient la configuration par défaut des champs des fiches membres.
|
||||||
|
; La configuration est ensuite enregistrée au format INI dans la table
|
||||||
|
; config de la base de données.
|
||||||
|
;
|
||||||
|
; Syntaxe :
|
||||||
|
;
|
||||||
|
; [nom_du_champ] ; Nom unique du champ, ne peut contenir que des lettres et des tirets bas
|
||||||
|
; type = text
|
||||||
|
; label = "Super champ trop cool"
|
||||||
|
; required = true
|
||||||
|
;
|
||||||
|
; Description des options possibles pour chaque champ :
|
||||||
|
;
|
||||||
|
; type: (défaut: text) OBLIGATOIRE
|
||||||
|
; certains types gérés par <input type> de HTML5 :
|
||||||
|
; text, number, date, datetime, url, email, checkbox, file, password, tel
|
||||||
|
; champs spécifiques :
|
||||||
|
; - country = sélecteur de pays
|
||||||
|
; - textarea = texte multi lignes
|
||||||
|
; - multiple = multiples cases à cocher (jusqu'à 32, binaire)
|
||||||
|
; - select = un choix parmis plusieurs
|
||||||
|
; label: OBLIGATOIRE
|
||||||
|
; Titre du champ
|
||||||
|
; help:
|
||||||
|
; Texte d'aide sur les fiches membres
|
||||||
|
; options[]:
|
||||||
|
; pour définir les options d'un champ de type select ou multiple
|
||||||
|
; required:
|
||||||
|
; true = obligatoire, la fiche membre ne pourra être enregistrée si ce champ est vide
|
||||||
|
; false = facultatif (défaut)
|
||||||
|
; user_access_level:
|
||||||
|
; 2 = modifiable par le membre
|
||||||
|
; 1 = visible par le membre (défaut)
|
||||||
|
; 0 = visible uniquement par un admin
|
||||||
|
; management_access_level:
|
||||||
|
; 9 = visible par les membres ayant accès en administration
|
||||||
|
; 2 = visible uniquement par les personnes ayant accès en écriture aux membres
|
||||||
|
; 1 = visible par les personnes ayant accès en lecture aux membres
|
||||||
|
; list_table: 'true' si doit être listé par défaut dans la liste des membres
|
||||||
|
; sql: SQL code for GENERATED columns
|
||||||
|
; depends[]: list of fields that need to be existing in order to install this field
|
||||||
|
|
||||||
|
[numero]
|
||||||
|
type = number
|
||||||
|
label = "Numéro de membre"
|
||||||
|
required = true
|
||||||
|
list_table = true
|
||||||
|
default = true
|
||||||
|
|
||||||
|
[pronom]
|
||||||
|
type = "select"
|
||||||
|
label = "Pronom"
|
||||||
|
required = false
|
||||||
|
default = false
|
||||||
|
list_table = true
|
||||||
|
options[] = "elle"
|
||||||
|
options[] = "il"
|
||||||
|
options[] = "iel"
|
||||||
|
install_help = "Pour identifier la personne par rapport à son genre"
|
||||||
|
|
||||||
|
[nom]
|
||||||
|
type = text
|
||||||
|
label = "Nom & prénom"
|
||||||
|
required = true
|
||||||
|
list_table = true
|
||||||
|
default = true
|
||||||
|
|
||||||
|
[email]
|
||||||
|
; ce champ est facultatif et de type 'email'
|
||||||
|
type = email
|
||||||
|
label = "Adresse E-Mail"
|
||||||
|
required = false
|
||||||
|
default = true
|
||||||
|
|
||||||
|
[password]
|
||||||
|
; ce champ est obligatoirement présent et de type 'password'
|
||||||
|
; le titre ne peut être modifié
|
||||||
|
label = "Mot de passe"
|
||||||
|
type = password
|
||||||
|
required = false
|
||||||
|
default = true
|
||||||
|
|
||||||
|
[adresse]
|
||||||
|
type = textarea
|
||||||
|
label = "Adresse postale"
|
||||||
|
help = "Indiquer ici le numéro, le type de voie, etc."
|
||||||
|
default = true
|
||||||
|
|
||||||
|
[code_postal]
|
||||||
|
type = text
|
||||||
|
label = "Code postal"
|
||||||
|
default = true
|
||||||
|
|
||||||
|
[ville]
|
||||||
|
type = text
|
||||||
|
label = "Ville"
|
||||||
|
list_table = true
|
||||||
|
default = true
|
||||||
|
|
||||||
|
[pays]
|
||||||
|
type = country
|
||||||
|
label = "Pays"
|
||||||
|
default = false
|
||||||
|
|
||||||
|
[telephone]
|
||||||
|
type = tel
|
||||||
|
label = "Numéro de téléphone"
|
||||||
|
default = true
|
||||||
|
|
||||||
|
[lettre_infos]
|
||||||
|
type = checkbox
|
||||||
|
label = "Inscription à la lettre d'information"
|
||||||
|
install_help = "Case à cocher pour indiquer que le membre souhaite recevoir la lettre d'information de l'association"
|
||||||
|
default = true
|
||||||
|
|
||||||
|
[annee_naissance]
|
||||||
|
type = year
|
||||||
|
label = "Année de naissance"
|
||||||
|
install_help = "Recommandé, plutôt que la date de naissance qui est une information très sensible."
|
||||||
|
default = false
|
||||||
|
|
||||||
|
[age_annee]
|
||||||
|
type = virtual
|
||||||
|
label = "Âge"
|
||||||
|
install_help = "Déterminé en utilisant l'année de naissance"
|
||||||
|
depends[] = annee_naissance
|
||||||
|
default = false
|
||||||
|
sql = "strftime('%Y', date('now')) - annee_naissance"
|
||||||
|
|
||||||
|
[date_naissance]
|
||||||
|
type = date
|
||||||
|
label = "Date de naissance complète"
|
||||||
|
default = false
|
||||||
|
install_help = "Attention, cette information est très sensible, il est déconseillé par le RGPD de la demander aux membres. Il est préférable de demander seulement l'année de naissance."
|
||||||
|
|
||||||
|
[age_date]
|
||||||
|
type = virtual
|
||||||
|
label = "Âge"
|
||||||
|
install_help = "Déterminé en utilisant la date de naissance"
|
||||||
|
depends[] = date_naissance
|
||||||
|
default = false
|
||||||
|
sql = "CAST(strftime('%Y.%m%d', date('now')) - strftime('%Y.%m%d', date_naissance) as int)"
|
||||||
|
|
||||||
|
[photo]
|
||||||
|
type = file
|
||||||
|
label = "Photo"
|
||||||
|
default = false
|
||||||
|
|
||||||
|
[date_inscription]
|
||||||
|
type = date
|
||||||
|
label = "Date d'inscription"
|
||||||
|
help = "Date à laquelle le membre a été inscrit à l'association pour la première fois"
|
||||||
|
default = true
|
||||||
|
default_value = "NOW()"
|
||||||
|
|
||||||
|
[anciennete]
|
||||||
|
type = virtual
|
||||||
|
label = "Ancienneté"
|
||||||
|
install_help = "Nombre d'années depuis la date d'inscription"
|
||||||
|
depends[] = date_inscription
|
||||||
|
default = false
|
||||||
|
sql = "CAST(strftime('%Y.%m%d', date('now')) - strftime('%Y.%m%d', date_inscription) as INT)"
|
423
src/include/init.php
Normal file
423
src/include/init.php
Normal file
|
@ -0,0 +1,423 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Paheko;
|
||||||
|
|
||||||
|
use KD2\ErrorManager;
|
||||||
|
use KD2\Security;
|
||||||
|
use KD2\Form;
|
||||||
|
use KD2\Translate;
|
||||||
|
use KD2\DB\EntityManager;
|
||||||
|
|
||||||
|
const CONFIG_FILE = 'config.local.php';
|
||||||
|
|
||||||
|
require_once __DIR__ . '/lib/KD2/ErrorManager.php';
|
||||||
|
|
||||||
|
ErrorManager::enable(ErrorManager::DEVELOPMENT);
|
||||||
|
ErrorManager::setLogFile(__DIR__ . '/data/error.log');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Version de Paheko
|
||||||
|
*/
|
||||||
|
function paheko_version()
|
||||||
|
{
|
||||||
|
if (defined('Paheko\VERSION'))
|
||||||
|
{
|
||||||
|
return VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = __DIR__ . '/../VERSION';
|
||||||
|
|
||||||
|
if (file_exists($file))
|
||||||
|
{
|
||||||
|
$version = trim(file_get_contents($file));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$version = 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
define('Paheko\VERSION', $version);
|
||||||
|
return $version;
|
||||||
|
}
|
||||||
|
|
||||||
|
function paheko_manifest()
|
||||||
|
{
|
||||||
|
$file = __DIR__ . '/../../manifest.uuid';
|
||||||
|
|
||||||
|
if (@file_exists($file))
|
||||||
|
{
|
||||||
|
return substr(trim(file_get_contents($file)), 0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!defined('\SQLITE3_OPEN_READWRITE')) {
|
||||||
|
echo 'Le module de base de données SQLite3 n\'est pas disponible.' . PHP_EOL;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configuration globale
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Configuration externalisée
|
||||||
|
if (file_exists(__DIR__ . '/../' . CONFIG_FILE)) {
|
||||||
|
require __DIR__ . '/../' . CONFIG_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configuration par défaut, si les constantes ne sont pas définies dans CONFIG_FILE
|
||||||
|
// (fallback)
|
||||||
|
if (!defined('Paheko\ROOT'))
|
||||||
|
{
|
||||||
|
define('Paheko\ROOT', dirname(__DIR__));
|
||||||
|
}
|
||||||
|
|
||||||
|
\spl_autoload_register(function (string $classname): void {
|
||||||
|
$classname = ltrim($classname, '\\');
|
||||||
|
|
||||||
|
// Plugins
|
||||||
|
if (substr($classname, 0, 14) == 'Paheko\\Plugin\\')
|
||||||
|
{
|
||||||
|
$classname = substr($classname, 14);
|
||||||
|
$plugin_name = substr($classname, 0, strpos($classname, '\\'));
|
||||||
|
$filename = str_replace('\\', '/', substr($classname, strpos($classname, '\\')+1));
|
||||||
|
|
||||||
|
$path = Plugins::getPath(strtolower($plugin_name));
|
||||||
|
|
||||||
|
// Plugin does not exist, just abort
|
||||||
|
if (!$path) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = $path . '/lib/' . $filename . '.php';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// PSR-0 autoload
|
||||||
|
$filename = str_replace('\\', '/', $classname);
|
||||||
|
$path = ROOT . '/include/lib/' . $filename . '.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists($path)) {
|
||||||
|
require_once $path;
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
if (!defined('Paheko\DATA_ROOT')) {
|
||||||
|
define('Paheko\DATA_ROOT', ROOT . '/data');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('Paheko\WWW_URI'))
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$uri = \KD2\HTTP::getRootURI(ROOT);
|
||||||
|
}
|
||||||
|
catch (\UnexpectedValueException $e) {
|
||||||
|
$uri = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($uri == '/www/') {
|
||||||
|
$uri = '/';
|
||||||
|
}
|
||||||
|
elseif ($uri !== null) {
|
||||||
|
readfile(ROOT . '/sous-domaine.html');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
define('Paheko\WWW_URI', $uri);
|
||||||
|
unset($uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
$host = null;
|
||||||
|
|
||||||
|
if (!defined('Paheko\WWW_URL')) {
|
||||||
|
$host = \KD2\HTTP::getHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WWW_URI === null || (!empty($host) && $host == 'host.unknown')) {
|
||||||
|
$title = 'Impossible de détecter automatiquement l\'URL du site web.';
|
||||||
|
$info = 'Consulter l\'aide pour configurer manuellement l\'URL avec la directive WWW_URL et WWW_URI.';
|
||||||
|
$url ='https://fossil.kd2.org/paheko/wiki?name=Installation';
|
||||||
|
|
||||||
|
if (PHP_SAPI == 'cli') {
|
||||||
|
printf("\n/!\\ %s\n%s\n-> %s\n\n", $title, $info, $url);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf('<h2 style="color: red">%s</h2><p><a href="%s">%s</a></p>', $title, $url, $info);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('Paheko\WWW_URL') && $host !== null) {
|
||||||
|
define('Paheko\WWW_URL', \KD2\HTTP::getScheme() . '://' . $host . WWW_URI);
|
||||||
|
}
|
||||||
|
|
||||||
|
static $default_config = [
|
||||||
|
'CACHE_ROOT' => DATA_ROOT . '/cache',
|
||||||
|
'SHARED_CACHE_ROOT' => DATA_ROOT . '/cache/shared',
|
||||||
|
'WEB_CACHE_ROOT' => DATA_ROOT . '/cache/web/%host%',
|
||||||
|
'DB_FILE' => DATA_ROOT . '/association.sqlite',
|
||||||
|
'DB_SCHEMA' => ROOT . '/include/data/schema.sql',
|
||||||
|
'PLUGINS_ROOT' => DATA_ROOT . '/plugins',
|
||||||
|
'ALLOW_MODIFIED_IMPORT' => true,
|
||||||
|
'SHOW_ERRORS' => true,
|
||||||
|
'MAIL_ERRORS' => false,
|
||||||
|
'ERRORS_REPORT_URL' => null,
|
||||||
|
'REPORT_USER_EXCEPTIONS' => 0,
|
||||||
|
'ENABLE_TECH_DETAILS' => true,
|
||||||
|
'HTTP_LOG_FILE' => null,
|
||||||
|
'ENABLE_UPGRADES' => true,
|
||||||
|
'USE_CRON' => false,
|
||||||
|
'ENABLE_XSENDFILE' => false,
|
||||||
|
'DISABLE_EMAIL' => false,
|
||||||
|
'SMTP_HOST' => false,
|
||||||
|
'SMTP_USER' => null,
|
||||||
|
'SMTP_PASSWORD' => null,
|
||||||
|
'SMTP_PORT' => 587,
|
||||||
|
'SMTP_SECURITY' => 'STARTTLS',
|
||||||
|
'SMTP_HELO_HOSTNAME' => null,
|
||||||
|
'MAIL_RETURN_PATH' => null,
|
||||||
|
'MAIL_BOUNCE_PASSWORD' => null,
|
||||||
|
'MAIL_SENDER' => null,
|
||||||
|
'ADMIN_URL' => WWW_URL . 'admin/',
|
||||||
|
'NTP_SERVER' => 'fr.pool.ntp.org',
|
||||||
|
'ADMIN_COLOR1' => '#20787a',
|
||||||
|
'ADMIN_COLOR2' => '#85b9ba',
|
||||||
|
'ADMIN_BACKGROUND_IMAGE' => WWW_URL . 'admin/static/bg.png',
|
||||||
|
'FORCE_CUSTOM_COLORS' => false,
|
||||||
|
'DISABLE_INSTALL_FORM' => false,
|
||||||
|
'FILE_STORAGE_BACKEND' => 'SQLite',
|
||||||
|
'FILE_STORAGE_CONFIG' => null,
|
||||||
|
'FILE_STORAGE_QUOTA' => null,
|
||||||
|
'FILE_VERSIONING_POLICY' => null,
|
||||||
|
'FILE_VERSIONING_MAX_SIZE' => null,
|
||||||
|
'API_USER' => null,
|
||||||
|
'API_PASSWORD' => null,
|
||||||
|
'PDF_COMMAND' => 'auto',
|
||||||
|
'PDF_USAGE_LOG' => null,
|
||||||
|
'PDFTOTEXT_COMMAND' => null,
|
||||||
|
'CALC_CONVERT_COMMAND' => null,
|
||||||
|
'DOCUMENT_THUMBNAIL_COMMANDS' => null,
|
||||||
|
'SQL_DEBUG' => null,
|
||||||
|
'SYSTEM_SIGNALS' => [],
|
||||||
|
'LOCAL_LOGIN' => null,
|
||||||
|
'LEGAL_HOSTING_DETAILS' => null,
|
||||||
|
'ALERT_MESSAGE' => null,
|
||||||
|
'DISABLE_INSTALL_PING' => false,
|
||||||
|
'WOPI_DISCOVERY_URL' => null,
|
||||||
|
'SQLITE_JOURNAL_MODE' => 'TRUNCATE',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($default_config as $const => $value)
|
||||||
|
{
|
||||||
|
$const = sprintf('Paheko\\%s', $const);
|
||||||
|
|
||||||
|
if (!defined($const))
|
||||||
|
{
|
||||||
|
define($const, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check SMTP_SECURITY value
|
||||||
|
if (SMTP_SECURITY) {
|
||||||
|
$const = '\KD2\SMTP::' . strtoupper(SMTP_SECURITY);
|
||||||
|
|
||||||
|
if (!defined($const)) {
|
||||||
|
throw new \LogicException('Configuration: SMTP_SECURITY n\'a pas une valeur reconnue. Valeurs acceptées: STARTTLS, TLS, SSL, NONE.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for private files, just in case WWW_URL is not the same domain as ADMIN_URL
|
||||||
|
define('Paheko\BASE_URL', str_replace('/admin/', '/', ADMIN_URL));
|
||||||
|
define('Paheko\ADMIN_URI', preg_replace('!(^https?://[^/]+)!', '', ADMIN_URL));
|
||||||
|
|
||||||
|
const HELP_URL = 'https://paheko.cloud/aide?from=%s';
|
||||||
|
const HELP_PATTERN_URL = 'https://paheko.cloud/%s';
|
||||||
|
const WEBSITE = 'https://fossil.kd2.org/paheko/';
|
||||||
|
const PING_URL = 'https://paheko.cloud/ping/';
|
||||||
|
const PLUGINS_URL = 'https://paheko.cloud/plugins/list.json';
|
||||||
|
|
||||||
|
const USER_TEMPLATES_CACHE_ROOT = CACHE_ROOT . '/utemplates';
|
||||||
|
const STATIC_CACHE_ROOT = CACHE_ROOT . '/static';
|
||||||
|
const SHARED_USER_TEMPLATES_CACHE_ROOT = SHARED_CACHE_ROOT . '/utemplates';
|
||||||
|
const SMARTYER_CACHE_ROOT = SHARED_CACHE_ROOT . '/compiled';
|
||||||
|
|
||||||
|
// Used to get around some providers misconfiguration issues
|
||||||
|
if (isset($_SERVER['HTTP_X_OVHREQUEST_ID'])) {
|
||||||
|
define('Paheko\HOSTING_PROVIDER', 'OVH');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
define('Paheko\HOSTING_PROVIDER', null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PHP devrait être assez intelligent pour chopper la TZ système mais nan
|
||||||
|
// il sait pas faire (sauf sur Debian qui a le bon patch pour ça), donc pour
|
||||||
|
// éviter le message d'erreur à la con on définit une timezone par défaut
|
||||||
|
// Pour utiliser une autre timezone, il suffit de définir date.timezone dans
|
||||||
|
// un .htaccess ou dans CONFIG_FILE
|
||||||
|
if (!ini_get('date.timezone') || ini_get('date.timezone') === 'UTC') {
|
||||||
|
if (($tz = @date_default_timezone_get()) && $tz !== 'UTC') {
|
||||||
|
ini_set('date.timezone', $tz);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ini_set('date.timezone', 'Europe/Paris');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ValidationException extends UserException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class APIException extends \LogicException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// activer le gestionnaire d'erreurs/exceptions
|
||||||
|
ErrorManager::setEnvironment(SHOW_ERRORS ? ErrorManager::DEVELOPMENT : ErrorManager::PRODUCTION | ErrorManager::CLI_DEVELOPMENT);
|
||||||
|
ErrorManager::setLogFile(DATA_ROOT . '/error.log');
|
||||||
|
|
||||||
|
// activer l'envoi de mails si besoin est
|
||||||
|
if (MAIL_ERRORS) {
|
||||||
|
ErrorManager::setEmail(MAIL_ERRORS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ERRORS_REPORT_URL) {
|
||||||
|
ErrorManager::setRemoteReporting(ERRORS_REPORT_URL, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorManager::setContext([
|
||||||
|
'root_directory' => ROOT,
|
||||||
|
'paheko_data_root' => DATA_ROOT,
|
||||||
|
'paheko_version' => paheko_version(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
ErrorManager::setProductionErrorTemplate(defined('Paheko\ERRORS_TEMPLATE') && ERRORS_TEMPLATE ? ERRORS_TEMPLATE : '<!DOCTYPE html><html><head><title>Erreur interne</title>
|
||||||
|
<style type="text/css">
|
||||||
|
body {font-family: sans-serif; background: #fff; }
|
||||||
|
code, p, h1 { max-width: 400px; margin: 1em auto; display: block; }
|
||||||
|
code { text-align: right; color: #666; }
|
||||||
|
a { color: blue; }
|
||||||
|
form { text-align: center; }
|
||||||
|
</style></head><body><h1>Erreur interne</h1><p>Désolé mais le serveur a rencontré une erreur interne
|
||||||
|
et ne peut répondre à votre requête. Merci de ré-essayer plus tard.</p>
|
||||||
|
<p>Si vous suspectez un bug dans Paheko, vous pouvez suivre
|
||||||
|
<a href="https://fossil.kd2.org/paheko/wiki?name=Rapporter+un+bug&p">ces instructions</a>
|
||||||
|
pour le rapporter.</p>
|
||||||
|
<if(sent)><p>Un-e responsable a été notifié-e et cette erreur sera corrigée dès que possible.</p></if>
|
||||||
|
<if(logged)><code>L\'erreur a été enregistrée dans les journaux système (error.log) sous la référence : <b>{$ref}</b></code></if>
|
||||||
|
<p><a href="' . WWW_URL . '">← Retour à la page d\'accueil</a></p>
|
||||||
|
</body></html>');
|
||||||
|
|
||||||
|
ErrorManager::setHtmlHeader('<!DOCTYPE html><html><head><meta charset="utf-8" /><style type="text/css">
|
||||||
|
body { font-family: sans-serif; background: #fff; } * { margin: 0; padding: 0; }
|
||||||
|
u, code b, i, h3 { font-style: normal; font-weight: normal; text-decoration: none; }
|
||||||
|
#icn { color: #fff; font-size: 2em; float: right; margin: 1em; padding: 1em; background: #900; border-radius: 50%; }
|
||||||
|
section header { background: #fdd; padding: 1em; }
|
||||||
|
section article { margin: 1em; }
|
||||||
|
section article h3, section article h4 { font-size: 1em; font-family: mono; }
|
||||||
|
code { border: 1px dotted #ccc; display: block; }
|
||||||
|
code b { margin-right: 1em; color: #999; }
|
||||||
|
code u { background: #fcc; display: inline-block; width: 100%; }
|
||||||
|
table { border-collapse: collapse; margin: 1em; } td, th { border: 1px solid #ccc; padding: .2em .5em; text-align: left;
|
||||||
|
vertical-align: top; }
|
||||||
|
input { padding: .3em; margin: .5em; font-size: 1.2em; cursor: pointer; }
|
||||||
|
</style></head><body>
|
||||||
|
<pre id="icn"> \__/<br /> (xx)<br />//||\\\\</pre>
|
||||||
|
<section>
|
||||||
|
<article>
|
||||||
|
<h1>Une erreur s\'est produite</h1>
|
||||||
|
<if(report)><form method="post" action="{$report_url}"><p><input type="hidden" name="report" value="{$report_json}" /><input type="submit" value="Rapporter l\'erreur aux développeur⋅euses de Paheko →" /></p></form></if>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
');
|
||||||
|
|
||||||
|
function user_error(UserException $e)
|
||||||
|
{
|
||||||
|
if (REPORT_USER_EXCEPTIONS > 0) {
|
||||||
|
\Paheko\Form::reportUserException($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PHP_SAPI == 'cli')
|
||||||
|
{
|
||||||
|
echo $e->getMessage();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Flush any previous output, such as module HTML code etc.
|
||||||
|
@ob_end_clean();
|
||||||
|
|
||||||
|
if ($e->getCode() >= 400) {
|
||||||
|
http_response_code($e->getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't use Template class as there might be an error there due do the context (eg. install/upgrade)
|
||||||
|
$tpl = new \KD2\Smartyer(ROOT . '/templates/error.tpl');
|
||||||
|
$tpl->setCompiledDir(SMARTYER_CACHE_ROOT);
|
||||||
|
|
||||||
|
$tpl->assign('error', $e->getMessage());
|
||||||
|
$tpl->assign('html_error', $e->getHTMLMessage());
|
||||||
|
$tpl->assign('admin_url', ADMIN_URL);
|
||||||
|
$tpl->display();
|
||||||
|
}
|
||||||
|
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (REPORT_USER_EXCEPTIONS < 2) {
|
||||||
|
// Message d'erreur simple pour les erreurs de l'utilisateur
|
||||||
|
ErrorManager::setCustomExceptionHandler('\Paheko\UserException', '\Paheko\user_error');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clé secrète utilisée pour chiffrer les tokens CSRF etc.
|
||||||
|
if (!defined('Paheko\SECRET_KEY'))
|
||||||
|
{
|
||||||
|
$key = base64_encode(random_bytes(64));
|
||||||
|
Install::setLocalConfig('SECRET_KEY', $key);
|
||||||
|
define('Paheko\SECRET_KEY', $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intégration du secret pour les tokens CSRF
|
||||||
|
Form::tokenSetSecret(SECRET_KEY);
|
||||||
|
|
||||||
|
EntityManager::setGlobalDB(DB::getInstance());
|
||||||
|
|
||||||
|
Translate::setLocale('fr_FR');
|
||||||
|
|
||||||
|
// This is specific to OVH and other hosting providers who don't set up their servers properly
|
||||||
|
// see https://www.prestashop.com/forums/topic/393496-prestashop-16-webservice-authentification-on-ovh/
|
||||||
|
if (!isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||||
|
@list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vérifications pour enclencher le processus d'installation ou de mise à jour
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('Paheko\INSTALL_PROCESS'))
|
||||||
|
{
|
||||||
|
$exists = file_exists(DB_FILE);
|
||||||
|
|
||||||
|
if (!$exists) {
|
||||||
|
if (in_array('install.php', get_included_files())) {
|
||||||
|
die('Erreur de redirection en boucle : problème de configuration ?');
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::redirect(ADMIN_URL . 'install.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
$v = DB::getInstance()->version();
|
||||||
|
|
||||||
|
if (version_compare($v, paheko_version(), '<')) {
|
||||||
|
if (!empty($_POST)) {
|
||||||
|
http_response_code(500);
|
||||||
|
readfile(ROOT . '/templates/static/upgrade_post.html');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::redirect(ADMIN_URL . 'upgrade.php');
|
||||||
|
}
|
||||||
|
}
|
1029
src/include/lib/KD2/Brindille.php
Normal file
1029
src/include/lib/KD2/Brindille.php
Normal file
File diff suppressed because it is too large
Load diff
338
src/include/lib/KD2/CacheCookie.php
Normal file
338
src/include/lib/KD2/CacheCookie.php
Normal file
|
@ -0,0 +1,338 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
This file is part of KD2FW -- <http://dev.kd2.org/>
|
||||||
|
|
||||||
|
Copyright (c) 2001-2019 BohwaZ <http://bohwaz.net/>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
KD2FW 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.
|
||||||
|
|
||||||
|
Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace KD2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache Cookie
|
||||||
|
* (C) 2011-2014 BohwaZ
|
||||||
|
* Inspired by Frank Denis (C) 2011 Public domain
|
||||||
|
* https://00f.net/2011/01/19/thoughts-on-php-sessions/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CacheCookie
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Name of the cookie
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $name = 'cache';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Secret key/random hash
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $secret_key = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Digest method for hash_hmac
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $digest_method = 'sha256';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delay before expiration when we should renew the cookie
|
||||||
|
* before it expires (in minutes)
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $auto_renew = 30;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default cookie path
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $path = '/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default cookie domain
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $domain = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default cookie duration, in minutes
|
||||||
|
* Will also determine data validity
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $duration = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if the cookie should only be sent over a SSL/TLS connection
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
protected $secure = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start timestamp used to store a shorter timestamp in the cookie
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $start_timestamp = 1391209200; //2014-02-01 00:00:00
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cookie content
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $content = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cookie HTTP only parameter
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
protected $httponly = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new CacheCookie instance and setup default parameters
|
||||||
|
* @param string $name Cookie name
|
||||||
|
* @param string $secret Secret random hash (should stay the same for at least the cookie duration)
|
||||||
|
* @param int $duration Cookie duration, in minutes, set to 0 (zero) to make the cookie lasts for the
|
||||||
|
* whole user agent session (cookie will be deleted when the browser is closed).
|
||||||
|
* @param string $path Cookie path
|
||||||
|
* @param string $domain Cookie domain, if left null the current HTTP_HOST or SERVER_NAME will be used
|
||||||
|
* @param string $secure Set to TRUE if the cookie should only be sent on a secure connection
|
||||||
|
*/
|
||||||
|
public function __construct($name = null, $secret = null, $duration = null, $path = null, $domain = null, $secure = false, $httponly = false)
|
||||||
|
{
|
||||||
|
if (!is_null($name))
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($secret))
|
||||||
|
{
|
||||||
|
$this->secret = $secret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Default secret key
|
||||||
|
$this->secret = \hash('sha256', (isset($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($duration))
|
||||||
|
{
|
||||||
|
$this->duration = (int) $duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($path))
|
||||||
|
{
|
||||||
|
$this->path = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_null($domain))
|
||||||
|
{
|
||||||
|
$this->domain = $domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->secure = (bool)$secure;
|
||||||
|
$this->httponly = (bool)$httponly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAutoRenew($renew)
|
||||||
|
{
|
||||||
|
$this->auto_renew = (int) $renew;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cookie content
|
||||||
|
* @return array Data contained in the cookie
|
||||||
|
*/
|
||||||
|
protected function _getCookie()
|
||||||
|
{
|
||||||
|
if (!is_null($this->content))
|
||||||
|
{
|
||||||
|
return $this->content;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cookie = null;
|
||||||
|
$this->content = new \stdClass;
|
||||||
|
|
||||||
|
if (!empty($_COOKIE[$this->name]))
|
||||||
|
{
|
||||||
|
$cookie = $_COOKIE[$this->name];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($cookie) && (substr_count($cookie, '|') >= 2))
|
||||||
|
{
|
||||||
|
list($digest, $expire, $data) = explode('|', $cookie, 3);
|
||||||
|
|
||||||
|
// Check data expiration and integrity
|
||||||
|
if (!empty($digest) && !empty($data) && !empty($expire)
|
||||||
|
&& ($expire > round((time() - $this->start_timestamp) / 60))
|
||||||
|
&& hash_equals($digest, hash_hmac($this->digest_method, $expire . '|' . $data, $this->secret)))
|
||||||
|
{
|
||||||
|
if (substr($data, 0, 1) == '{')
|
||||||
|
{
|
||||||
|
$this->content = (object) json_decode($data, true);
|
||||||
|
}
|
||||||
|
elseif (function_exists('msgpack_unpack'))
|
||||||
|
{
|
||||||
|
$this->content = (object) msgpack_unpack($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the cookie will expire soon we try to renew it first
|
||||||
|
if ($this->auto_renew && ($expire - round((time() - $this->start_timestamp)/60) <= $this->auto_renew))
|
||||||
|
{
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Invalid cookie: just remove it
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the cookie content to the user-agent
|
||||||
|
* @return boolean TRUE for success,
|
||||||
|
* or RuntimeException if the HTTP headers have already been sent
|
||||||
|
*/
|
||||||
|
public function save()
|
||||||
|
{
|
||||||
|
if (headers_sent())
|
||||||
|
{
|
||||||
|
throw new \RuntimeException('Cache cookie can not be saved as headers have '
|
||||||
|
. 'already been sent to the user agent.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = headers_list(); // List all headers
|
||||||
|
header_remove(); // remove all headers
|
||||||
|
$regexp = '/^Set-Cookie\\s*:\\s*' . preg_quote($this->name) . '=/';
|
||||||
|
|
||||||
|
foreach ($headers as $header)
|
||||||
|
{
|
||||||
|
// Re-add every header except the one for this cookie
|
||||||
|
if (!preg_match($regexp, $header))
|
||||||
|
{
|
||||||
|
header($header, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($this->content) && count($this->content) > 0)
|
||||||
|
{
|
||||||
|
if (function_exists('msgpack_pack'))
|
||||||
|
{
|
||||||
|
$data = msgpack_pack($this->content);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$data = json_encode($this->content);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store expiration time in minutes
|
||||||
|
$data = round((time() - $this->start_timestamp + $this->duration*60)/60) . '|' . $data;
|
||||||
|
|
||||||
|
$cookie = hash_hmac($this->digest_method, $data, $this->secret) . '|' . $data;
|
||||||
|
|
||||||
|
$duration = $this->duration ? time() + $this->duration * 60 : 0;
|
||||||
|
|
||||||
|
if (strlen($cookie . $this->path . $duration . $this->domain . $this->name) > 4080)
|
||||||
|
{
|
||||||
|
throw new \OverflowException('Cache cookie can not be saved as its size exceeds 4KB.');
|
||||||
|
}
|
||||||
|
|
||||||
|
setcookie($this->name, $cookie, $duration, $this->path, $this->domain, $this->secure, true);
|
||||||
|
$_COOKIE[$this->name] = $cookie;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setcookie($this->name, '', 1, $this->path, $this->domain, $this->secure, true);
|
||||||
|
unset($_COOKIE[$this->name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a key/value pair in the cache cookie
|
||||||
|
* @param mixed $key Key (integer or string)
|
||||||
|
* @param mixed $value Value (integer, string, boolean, array, float...)
|
||||||
|
*/
|
||||||
|
public function set($key, $value)
|
||||||
|
{
|
||||||
|
$this->_getCookie();
|
||||||
|
|
||||||
|
if (is_null($value))
|
||||||
|
{
|
||||||
|
unset($this->content->$key);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->content->$key = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get data from the cache cookie, if $key is NULL then all the keys will be returned
|
||||||
|
* @param mixed $key Data key
|
||||||
|
* @return mixed NULL if the key is not found, or content of the requested key
|
||||||
|
*/
|
||||||
|
public function get($key = null)
|
||||||
|
{
|
||||||
|
$content = $this->_getCookie();
|
||||||
|
|
||||||
|
if (is_null($key))
|
||||||
|
{
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($content->$key))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $content->$key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the cookie and all its data
|
||||||
|
* @return boolean TRUE
|
||||||
|
*/
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
$content = $this->get();
|
||||||
|
|
||||||
|
foreach ($content as $key=>$value)
|
||||||
|
{
|
||||||
|
$this->set($key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns raw cookie data
|
||||||
|
* @return string cookie content
|
||||||
|
*/
|
||||||
|
public function getRawData()
|
||||||
|
{
|
||||||
|
if (isset($_COOKIE[$this->name]))
|
||||||
|
return $_COOKIE[$this->name];
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
562
src/include/lib/KD2/DB/AbstractEntity.php
Normal file
562
src/include/lib/KD2/DB/AbstractEntity.php
Normal file
|
@ -0,0 +1,562 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of KD2FW -- <http://dev.kd2.org/>
|
||||||
|
|
||||||
|
Copyright (c) 2001-2019 BohwaZ <http://bohwaz.net/>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
KD2FW 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.
|
||||||
|
|
||||||
|
Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace KD2\DB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AbstractEntity: a generic entity that can be extended to build your entities
|
||||||
|
* Use the EntityManager to persist entities in a database
|
||||||
|
*
|
||||||
|
* @author bohwaz
|
||||||
|
* @license AGPLv3
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class AbstractEntity
|
||||||
|
{
|
||||||
|
protected $_exists = false;
|
||||||
|
|
||||||
|
protected $_modified = [];
|
||||||
|
protected $_types = [];
|
||||||
|
|
||||||
|
static protected $_types_cache = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
// Generate types cache
|
||||||
|
if (empty(self::$_types_cache[static::class]) && empty($this->_types)) {
|
||||||
|
$r = new \ReflectionClass(static::class);
|
||||||
|
|
||||||
|
foreach ($r->getProperties(\ReflectionProperty::IS_PROTECTED) as $p) {
|
||||||
|
if ($p->name[0] == '_') {
|
||||||
|
// Skip internal stuff
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists($p->name, $this->_types)) {
|
||||||
|
$type = $this->_types[$p->name];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$t = $p->getType();
|
||||||
|
|
||||||
|
if (null === $t) {
|
||||||
|
throw new \LogicException(sprintf('Property "%s" of entity "%s" has no type', $p->name, static::class));
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = $t->getName();
|
||||||
|
$type = ($t->allowsNull() ? '?' : '') . $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_types[$p->name] = $type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self::_loadEntityTypesCache($this->_types);
|
||||||
|
}
|
||||||
|
|
||||||
|
static protected function _loadEntityTypesCache(array $types)
|
||||||
|
{
|
||||||
|
if (!empty(self::$_types_cache[static::class])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($types as $name => $type) {
|
||||||
|
$nullable = false;
|
||||||
|
|
||||||
|
if ($type[0] === '?') {
|
||||||
|
$type = substr($type, 1);
|
||||||
|
$nullable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$prop = (object) compact('name', 'nullable', 'type');
|
||||||
|
$prop->boolean = $type === 'bool' || $type === 'boolean';
|
||||||
|
$prop->integer = $type === 'int' || $type === 'integer';
|
||||||
|
$prop->float = $type === 'float' || $type === 'double';
|
||||||
|
$prop->string = $type === 'string';
|
||||||
|
$prop->array = $type === 'array';
|
||||||
|
$prop->object = !$prop->boolean && !$prop->integer && !$prop->float && !$prop->string && !$prop->array;
|
||||||
|
$prop->class = $prop->object ? $type : null;
|
||||||
|
$prop->stdclass = $prop->class === 'stdClass';
|
||||||
|
$prop->datetime = $prop->class === 'DateTime' || $prop->class === 'DateTimeInterface';
|
||||||
|
$prop->date = $prop->class === Date::class || $prop->class === 'date';
|
||||||
|
|
||||||
|
self::$_types_cache[static::class][$name] = $prop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __wakeup(): void
|
||||||
|
{
|
||||||
|
if (empty(self::$_types_cache[static::class])) {
|
||||||
|
self::_loadEntityTypesCache($this->_types);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads data from an array into the entity properties
|
||||||
|
* Used for example to load data from a database. This will convert string values to typed properties.
|
||||||
|
* @param array $data
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function load(array $data): self
|
||||||
|
{
|
||||||
|
$properties = self::$_types_cache[static::class];
|
||||||
|
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
if (!array_key_exists($key, $properties)) {
|
||||||
|
throw new \RuntimeException(sprintf('"%s" is not a property of the entity "%s"', $key, static::class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($properties as $name => $prop) {
|
||||||
|
if (!array_key_exists($name, $data)) {
|
||||||
|
throw new \RuntimeException('Missing key in array: ' . $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $data[$name];
|
||||||
|
|
||||||
|
if (is_int($value) && $prop->boolean) {
|
||||||
|
$value = (bool) $value;
|
||||||
|
}
|
||||||
|
elseif (is_string($value) && !$prop->string) {
|
||||||
|
$value = $this->transformValue($name, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->$name = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import data from an array of user-supplied values, only keys corresponding to entity properties
|
||||||
|
* will be used, others will be ignored.
|
||||||
|
* @param array|null $source Source data array, if none is supplied $_POST will be used
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function import(array $source = null): self
|
||||||
|
{
|
||||||
|
if (null === $source) {
|
||||||
|
$source = $_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($source['id']);
|
||||||
|
|
||||||
|
$data = array_intersect_key($source, self::$_types_cache[static::class]);
|
||||||
|
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
$prop = self::$_types_cache[static::class][$key];
|
||||||
|
|
||||||
|
if ($prop->nullable && is_string($value) && trim($value) === '') {
|
||||||
|
$value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $this->filterUserValue($prop->type, $value, $key);
|
||||||
|
$this->setFromAnyValue($key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function filterUserValue(string $type, $value, string $key)
|
||||||
|
{
|
||||||
|
if (is_null($value)) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($type)
|
||||||
|
{
|
||||||
|
case 'date':
|
||||||
|
case Date::class:
|
||||||
|
$d = new Date($value);
|
||||||
|
$d->setTime(0, 0, 0);
|
||||||
|
return $d;
|
||||||
|
case 'DateTime':
|
||||||
|
return new \DateTime($value);
|
||||||
|
case 'int':
|
||||||
|
return (int) $value;
|
||||||
|
case 'float':
|
||||||
|
return (float) $value;
|
||||||
|
case 'bool':
|
||||||
|
return (bool) $value;
|
||||||
|
case 'string':
|
||||||
|
return trim((string) $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function assert($test, string $message = null): void
|
||||||
|
{
|
||||||
|
if ($test) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $message) {
|
||||||
|
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
|
||||||
|
$caller_class = array_pop($backtrace);
|
||||||
|
$caller = array_pop($backtrace);
|
||||||
|
$message = sprintf('Entity assertion fail from class %s on line %d', $caller_class['class'], $caller['line']);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \UnexpectedValueException($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function selfCheck(): void
|
||||||
|
{
|
||||||
|
$this->assert(!isset($this->id) || (is_numeric($this->id) && $this->id > 0));
|
||||||
|
|
||||||
|
foreach (self::$_types_cache[static::class] as $prop_name => $prop) {
|
||||||
|
// Skip ID
|
||||||
|
if ($prop_name == 'id') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->$prop_name) && !$prop->nullable) {
|
||||||
|
throw new \UnexpectedValueException(sprintf('Entity property "%s" cannot be left NULL', $prop_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asArray(bool $for_database = false): array
|
||||||
|
{
|
||||||
|
$vars = get_object_vars($this);
|
||||||
|
|
||||||
|
// Remove internal stuff
|
||||||
|
foreach ($vars as $key => &$value) {
|
||||||
|
if ($key[0] == '_') {
|
||||||
|
unset($vars[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$for_database) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $this->getAsString($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAsString(string $key, $value = null)
|
||||||
|
{
|
||||||
|
if (!isset($this->$key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value ??= $this->$key;
|
||||||
|
|
||||||
|
switch (gettype($value)) {
|
||||||
|
case 'object':
|
||||||
|
if ($value instanceof \stdClass) {
|
||||||
|
return json_encode($value);
|
||||||
|
}
|
||||||
|
elseif ($value instanceof Date) {
|
||||||
|
return $value->format('Y-m-d');
|
||||||
|
}
|
||||||
|
elseif ($value instanceof \DateTimeInterface) {
|
||||||
|
return $value->format('Y-m-d H:i:s');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string) $value;
|
||||||
|
case 'bool':
|
||||||
|
case 'boolean':
|
||||||
|
return (int) $value;
|
||||||
|
case 'array':
|
||||||
|
return json_encode($value);
|
||||||
|
case 'int':
|
||||||
|
case 'integer':
|
||||||
|
case 'double':
|
||||||
|
case 'float':
|
||||||
|
return $value;
|
||||||
|
default:
|
||||||
|
return (string) $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array containing *OLD* values of modified properties
|
||||||
|
* (*NEW* value is stored in object)
|
||||||
|
*
|
||||||
|
* Note that modified properties are cleared after save()
|
||||||
|
*/
|
||||||
|
public function getModifiedProperties(): array
|
||||||
|
{
|
||||||
|
return $this->_modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
public function modifiedProperties(bool $for_database = false): array
|
||||||
|
{
|
||||||
|
return array_intersect_key($this->asArray($for_database), $this->_modified);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the *OLD* value of a modified property
|
||||||
|
*/
|
||||||
|
public function getModifiedProperty(string $key)
|
||||||
|
{
|
||||||
|
return $this->_modified[$key] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clearModifiedProperties(?array $properties = null): void
|
||||||
|
{
|
||||||
|
if (null === $properties) {
|
||||||
|
$this->_modified = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($properties as $key) {
|
||||||
|
unset($this->_modified[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isModified(?string $property = null): bool
|
||||||
|
{
|
||||||
|
if ($property !== null) {
|
||||||
|
return array_key_exists($property, $this->_modified);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return count($this->_modified) > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function id(int $id = null): int
|
||||||
|
{
|
||||||
|
if (null !== $id) {
|
||||||
|
$this->id = $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->id)) {
|
||||||
|
throw new \LogicException('This entity does not have an ID yet');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exists(bool $exists = null): bool
|
||||||
|
{
|
||||||
|
if (null !== $exists) {
|
||||||
|
$this->_exists = $exists;
|
||||||
|
|
||||||
|
if ($exists === false) {
|
||||||
|
unset($this->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFromAnyValue(string $key, $value)
|
||||||
|
{
|
||||||
|
$this->set($key, $this->transformValue($key, $value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms the value from loosely typed to be suitable to expected type of a property
|
||||||
|
* eg. (string)'42' => (int)42
|
||||||
|
*/
|
||||||
|
public function transformValue(string $key, $value)
|
||||||
|
{
|
||||||
|
$prop = self::$_types_cache[static::class][$key] ?? null;
|
||||||
|
|
||||||
|
if (null === $prop) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Unknown "%s" property: "%s"', static::class, $key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string($value) && trim($value) === '' && $prop->nullable) {
|
||||||
|
$value = null;
|
||||||
|
}
|
||||||
|
elseif (($prop->float || $prop->integer) && is_string($value) && is_numeric($value)) {
|
||||||
|
$value = (int)$value;
|
||||||
|
}
|
||||||
|
elseif ($prop->datetime && is_string($value) && strlen($value) === 19 && ($d = \DateTime::createFromFormat('!Y-m-d H:i:s', $value))) {
|
||||||
|
$value = $d;
|
||||||
|
}
|
||||||
|
elseif ($prop->datetime && is_string($value) && strlen($value) === 16 && ($d = \DateTime::createFromFormat('!Y-m-d H:i', $value))) {
|
||||||
|
$value = $d;
|
||||||
|
}
|
||||||
|
elseif ($prop->date && is_string($value) && strlen($value) === 10 && ($d = Date::createFromFormat('!Y-m-d', $value))) {
|
||||||
|
$value = $d;
|
||||||
|
}
|
||||||
|
elseif ($prop->date && is_object($value) && $value instanceof \DateTime && !($value instanceof Date)) {
|
||||||
|
$value = Date::createFromInterface($value);
|
||||||
|
}
|
||||||
|
elseif ($prop->boolean && is_numeric($value) && ($value == 0 || $value == 1)) {
|
||||||
|
$value = (bool) $value;
|
||||||
|
}
|
||||||
|
elseif ($prop->array && is_string($value)) {
|
||||||
|
$value = json_decode($value, true);
|
||||||
|
|
||||||
|
if (null === $value) {
|
||||||
|
throw new \RuntimeException(sprintf('Cannot decode JSON string for key "%s"', $key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ($prop->stdclass && is_string($value)) {
|
||||||
|
$value = json_decode($value);
|
||||||
|
|
||||||
|
if (null === $value) {
|
||||||
|
throw new \RuntimeException(sprintf('Cannot decode JSON string for key "%s"', $key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, $value)
|
||||||
|
{
|
||||||
|
$prop = self::$_types_cache[static::class][$key] ?? null;
|
||||||
|
|
||||||
|
if (null === $prop) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Unknown "%s" property: "%s"', static::class, $key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->$key) && is_object($this->$key)) {
|
||||||
|
$original_value = clone $this->$key;
|
||||||
|
}
|
||||||
|
elseif (isset($this->$key)) {
|
||||||
|
$original_value = $this->$key;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$original_value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $value && !$prop->nullable) {
|
||||||
|
throw new \UnexpectedValueException(sprintf('Unexpected NULL value for "%s"', $key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prop->date && is_object($value) && !($value instanceof Date)) {
|
||||||
|
$value = Date::createFromInterface($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $value && !$this->_checkValueType($value, $prop)) {
|
||||||
|
$found_type = $this->_getValueType($value);
|
||||||
|
|
||||||
|
if ('object' == $found_type) {
|
||||||
|
$found_type = get_class($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \UnexpectedValueException(sprintf('Value of type \'%s\' for property \'%s\' is invalid (expected \'%s\')', $found_type, $key, $prop->type));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize line breaks to \n
|
||||||
|
if (is_string($value) && (!isset($this->$key) || $this->$key !== $value)) {
|
||||||
|
$value = str_replace("\r\n", "\n", $value);
|
||||||
|
$value = str_replace("\r", "\n", $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->$key = $value;
|
||||||
|
|
||||||
|
// For storing a modified object, compare its string value, not the object, as DateTime !== DateTime
|
||||||
|
if (is_object($value) && is_object($original_value)) {
|
||||||
|
$compare_value = $this->getAsString($key, $original_value);
|
||||||
|
$value = $this->getAsString($key, $value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$compare_value = $original_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only modify entity if value has changed
|
||||||
|
if ($value !== $compare_value) {
|
||||||
|
$this->_modified[$key] = $original_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $key)
|
||||||
|
{
|
||||||
|
return $this->$key ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __set(string $key, $value)
|
||||||
|
{
|
||||||
|
$this->set($key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get(string $key)
|
||||||
|
{
|
||||||
|
return $this->get($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __isset($key)
|
||||||
|
{
|
||||||
|
return property_exists($this, $key) && isset($this->$key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure the cloned object doesn't have the same ID, it's a brand new entity!
|
||||||
|
*/
|
||||||
|
public function __clone()
|
||||||
|
{
|
||||||
|
unset($this->id);
|
||||||
|
$this->_exists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _checkValueType($value, \stdClass $prop): bool
|
||||||
|
{
|
||||||
|
$type = $this->_getValueType($value);
|
||||||
|
|
||||||
|
if ($type !== 'object' && isset($prop->$type) && $prop->$type === true) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
elseif ($prop->date && $value instanceof Date) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
elseif ($prop->datetime && $value instanceof \DateTimeInterface) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
elseif ($prop->stdclass && $value instanceof \stdClass) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
elseif ($prop->class && $value instanceof $prop->class) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _getValueType($value)
|
||||||
|
{
|
||||||
|
$type = gettype($value);
|
||||||
|
|
||||||
|
// Type names are not consistent in PHP...
|
||||||
|
// see https://mlocati.github.io/articles/php-type-hinting.html
|
||||||
|
$type = $type === 'double' ? 'float': $type;
|
||||||
|
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpful helpers
|
||||||
|
public function save(bool $selfcheck = true): bool
|
||||||
|
{
|
||||||
|
return EntityManager::getInstance(static::class)->save($this, $selfcheck);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(): bool
|
||||||
|
{
|
||||||
|
return EntityManager::getInstance(static::class)->delete($this);
|
||||||
|
}
|
||||||
|
}
|
407
src/include/lib/KD2/DB/AbstractEntity.php.UTC
Normal file
407
src/include/lib/KD2/DB/AbstractEntity.php.UTC
Normal file
|
@ -0,0 +1,407 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of KD2FW -- <http://dev.kd2.org/>
|
||||||
|
|
||||||
|
Copyright (c) 2001-2019 BohwaZ <http://bohwaz.net/>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
KD2FW 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.
|
||||||
|
|
||||||
|
Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace KD2\DB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AbstractEntity: a generic entity that can be extended to build your entities
|
||||||
|
* Use the EntityManager to persist entities in a database
|
||||||
|
*
|
||||||
|
* @author bohwaz
|
||||||
|
* @license AGPLv3
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class AbstractEntity
|
||||||
|
{
|
||||||
|
protected $id;
|
||||||
|
|
||||||
|
protected $_exists = false;
|
||||||
|
|
||||||
|
protected $_modified = [];
|
||||||
|
protected $_types = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
// Generate _types array
|
||||||
|
if (version_compare(PHP_VERSION, '7.4', '>=') && empty($this->_types)) {
|
||||||
|
$r = new \ReflectionClass(static::class);
|
||||||
|
foreach ($r->getProperties(\ReflectionProperty::IS_PROTECTED) as $p) {
|
||||||
|
if ($p->name[0] == '_') {
|
||||||
|
// Skip internal stuff
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($p->name == 'id') {
|
||||||
|
$type = 'int';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$t = $p->getType();
|
||||||
|
|
||||||
|
if (null === $t) {
|
||||||
|
throw new \LogicException(sprintf('Property "%s" of entity "%s" has no type', $p->name, static::class));
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = $t->getName();
|
||||||
|
$type = ($t->allowsNull() ? '?' : '') . $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_types[$p->name] = $type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads data from an array into the entity properties
|
||||||
|
* Used for example to load data from a database. This will convert string values to typed properties.
|
||||||
|
* @param array $data
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function load(array $data): void
|
||||||
|
{
|
||||||
|
$properties = array_keys($this->_types);
|
||||||
|
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
if (!in_array($key, $properties)) {
|
||||||
|
throw new \RuntimeException(sprintf('"%s" is not a property of the entity "%s"', $key, static::class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($properties as $key) {
|
||||||
|
if (!array_key_exists($key, $data)) {
|
||||||
|
throw new \RuntimeException('Missing key in array: ' . $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $data[$key];
|
||||||
|
$this->set($key, $value, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import data from an array of user-supplied values, only keys corresponding to entity properties
|
||||||
|
* will be used, others will be ignored.
|
||||||
|
* @param array|null $source Source data array, if none is supplied $_POST will be used
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function import(array $source = null): self
|
||||||
|
{
|
||||||
|
if (null === $source) {
|
||||||
|
$source = $_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = array_intersect_key($source, $this->_types);
|
||||||
|
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
$type = $this->_types[$key];
|
||||||
|
|
||||||
|
if (substr($type, 0, 1) == '?') {
|
||||||
|
$type = substr($type, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $this->filterUserValue($type, $value, $key);
|
||||||
|
$this->set($key, $value, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function filterUserValue(string $type, $value, string $key)
|
||||||
|
{
|
||||||
|
if (is_null($value)) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($type)
|
||||||
|
{
|
||||||
|
case 'date':
|
||||||
|
return \DateTime::createFromFormat('!Y-m-d', $value);
|
||||||
|
case 'DateTime':
|
||||||
|
return new \DateTime($value);
|
||||||
|
case 'int':
|
||||||
|
return (int) $value;
|
||||||
|
case 'bool':
|
||||||
|
return (bool) $value;
|
||||||
|
case 'string':
|
||||||
|
return trim($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function assert(?bool $test, string $message = null): void
|
||||||
|
{
|
||||||
|
if ($test) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $message) {
|
||||||
|
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
|
||||||
|
$caller_class = array_pop($backtrace);
|
||||||
|
$caller = array_pop($backtrace);
|
||||||
|
$message = sprintf('Entity assertion fail from class %s on line %d', $caller_class['class'], $caller['line']);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \UnexpectedValueException($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function selfCheck(): void
|
||||||
|
{
|
||||||
|
$this->assert(is_null($this->id) || (is_numeric($this->id) && $this->id > 0));
|
||||||
|
|
||||||
|
foreach ($this->_types as $key => $type) {
|
||||||
|
// Skip ID
|
||||||
|
if ($key == 'id') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($this->$key) && substr($type, 0, 1) != '?') {
|
||||||
|
throw new \UnexpectedValueException(sprintf('Entity property "%s" cannot be left null', $key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asArray($for_database = false): array
|
||||||
|
{
|
||||||
|
$vars = get_object_vars($this);
|
||||||
|
|
||||||
|
// Remove internal stuff
|
||||||
|
foreach ($vars as $key => &$value) {
|
||||||
|
if ($key[0] == '_') {
|
||||||
|
unset($vars[$key]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$for_database) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $this->getAsString($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAsString(string $key)
|
||||||
|
{
|
||||||
|
if (null === $this->$key) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = $this->_types[$key];
|
||||||
|
|
||||||
|
if (substr($type, 0, 1) == '?') {
|
||||||
|
$type = substr($type, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
// Export dates
|
||||||
|
case 'date':
|
||||||
|
$v = clone $this->$key;
|
||||||
|
$v->setTimezone(new \DateTimeZone('UTC'));
|
||||||
|
return $v->format('Y-m-d');
|
||||||
|
case 'DateTime':
|
||||||
|
$v = clone $this->$key;
|
||||||
|
$v->setTimezone(new \DateTimeZone('UTC'));
|
||||||
|
return $v->format('Y-m-d H:i:s');
|
||||||
|
case 'bool':
|
||||||
|
return (int) $this->$key;
|
||||||
|
default:
|
||||||
|
return $this->$key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function modifiedProperties($for_database = false): array
|
||||||
|
{
|
||||||
|
return array_intersect_key($this->asArray($for_database), $this->_modified);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isModified(): bool
|
||||||
|
{
|
||||||
|
return count($this->_modified) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function id(int $id = null): int
|
||||||
|
{
|
||||||
|
if (null !== $id) {
|
||||||
|
$this->id = $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $this->id) {
|
||||||
|
throw new \LogicException('This entity does not have an ID yet');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exists(bool $exists = null): bool
|
||||||
|
{
|
||||||
|
if (null !== $exists) {
|
||||||
|
$this->_exists = $exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(string $key, $value, bool $loose = false, bool $check_for_changes = true) {
|
||||||
|
if (!property_exists($this, $key)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Unknown "%s" property: "%s"', static::class, $key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->$key)) {
|
||||||
|
$original_value = $this->getAsString($key);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$original_value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = $this->_types[$key];
|
||||||
|
$nullable = false;
|
||||||
|
|
||||||
|
if ($type[0] == '?') {
|
||||||
|
$nullable = true;
|
||||||
|
$type = substr($type, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($loose) {
|
||||||
|
if (is_string($value) && trim($value) === '' && $nullable) {
|
||||||
|
$value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value !== null) {
|
||||||
|
if ($type == 'int' && is_string($value) && ctype_digit($value)) {
|
||||||
|
$value = (int)$value;
|
||||||
|
}
|
||||||
|
elseif ($type == 'DateTime' && is_string($value) && strlen($value) === 19 && ($d = \DateTime::createFromFormat('Y-m-d H:i:s-e', $value . '-UTC'))) {
|
||||||
|
$value = $d;
|
||||||
|
}
|
||||||
|
elseif ($type == 'date' && is_string($value) && strlen($value) === 10 && ($d = \DateTime::createFromFormat('!Y-m-d-e', $value . '-UTC'))) {
|
||||||
|
$value = $d;
|
||||||
|
}
|
||||||
|
elseif ($type == 'bool' && is_numeric($value) && ($value == 0 || $value == 1)) {
|
||||||
|
$value = (bool) $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$nullable && null === $value) {
|
||||||
|
throw new \RuntimeException(sprintf('Unexpected NULL value for "%s"', $key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $value && !$this->_checkType($key, $value, $type)) {
|
||||||
|
$found_type = $this->_getType($value);
|
||||||
|
|
||||||
|
if ('object' == $found_type) {
|
||||||
|
$found_type = get_class($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \UnexpectedValueException(sprintf('Value of type \'%s\' for property \'%s\' is invalid (expected \'%s\')', $found_type, $key, $type));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->$key = $value;
|
||||||
|
|
||||||
|
if ($check_for_changes && $original_value !== $this->getAsString($key)) {
|
||||||
|
$this->_modified[$key] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $key)
|
||||||
|
{
|
||||||
|
return $this->$key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __set(string $key, $value)
|
||||||
|
{
|
||||||
|
$this->set($key, $value, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get(string $key)
|
||||||
|
{
|
||||||
|
return $this->$key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __isset($key)
|
||||||
|
{
|
||||||
|
return isset($this->$key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure the cloned object doesn't have the same ID, it's a brand new entity!
|
||||||
|
*/
|
||||||
|
public function __clone()
|
||||||
|
{
|
||||||
|
$this->id = null;
|
||||||
|
$this->_exists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _checkType(string $key, $value, string $type): bool
|
||||||
|
{
|
||||||
|
if (false !== strpos($type, '|')) {
|
||||||
|
$types = explode('|', $type);
|
||||||
|
|
||||||
|
foreach ($types as $type) {
|
||||||
|
if ($this->_checkType($key, $value, $type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case 'date':
|
||||||
|
return is_object($value) && $value instanceof \DateTimeInterface;
|
||||||
|
case 'DateTime':
|
||||||
|
return is_object($value) && $value instanceof \DateTimeInterface;
|
||||||
|
default:
|
||||||
|
return $this->_getType($value) == $type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _getType($value)
|
||||||
|
{
|
||||||
|
$type = gettype($value);
|
||||||
|
|
||||||
|
// Type names are not consistent in PHP...
|
||||||
|
// see https://mlocati.github.io/articles/php-type-hinting.html
|
||||||
|
$type = strtr($type, ['boolean' => 'bool', 'integer' => 'int', 'double' => 'float']);
|
||||||
|
|
||||||
|
if ($type === 'object') {
|
||||||
|
$type = get_class($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpful helpers
|
||||||
|
public function save(): bool
|
||||||
|
{
|
||||||
|
return EntityManager::getInstance(static::class)->save($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(): bool
|
||||||
|
{
|
||||||
|
return EntityManager::getInstance(static::class)->delete($this);
|
||||||
|
}
|
||||||
|
}
|
1039
src/include/lib/KD2/DB/DB.php
Normal file
1039
src/include/lib/KD2/DB/DB.php
Normal file
File diff suppressed because it is too large
Load diff
33
src/include/lib/KD2/DB/Date.php
Normal file
33
src/include/lib/KD2/DB/Date.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace KD2\DB;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use DateTimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just a helper that tells us that the date should be stored as Y-m-d that's all
|
||||||
|
*/
|
||||||
|
class Date extends DateTime {
|
||||||
|
// For PHP 7.4
|
||||||
|
static public function createFromInterface(DateTimeInterface $object): DateTime
|
||||||
|
{
|
||||||
|
$n = new self;
|
||||||
|
$n->setTimestamp($object->getTimestamp());
|
||||||
|
$n->setTimezone($object->getTimeZone());
|
||||||
|
return $n;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
static public function createFromFormat($format, $datetime, DateTimeZone $object = null)
|
||||||
|
{
|
||||||
|
$v = parent::createFromFormat($format, $datetime, $object);
|
||||||
|
|
||||||
|
if (!$v) {
|
||||||
|
return $v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::createFromInterface($v);
|
||||||
|
}
|
||||||
|
}
|
255
src/include/lib/KD2/DB/EntityManager.php
Normal file
255
src/include/lib/KD2/DB/EntityManager.php
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace KD2\DB;
|
||||||
|
|
||||||
|
use KD2\DB\DB;
|
||||||
|
use KD2\DB\SQLite3;
|
||||||
|
use KD2\DB\AbstractEntity;
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
class EntityManager
|
||||||
|
{
|
||||||
|
protected $class;
|
||||||
|
protected $db;
|
||||||
|
|
||||||
|
static protected $_instances = [];
|
||||||
|
static protected $_global_db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an EntityManager instance linked to a specific Entity class
|
||||||
|
* @param string $class Entity class name
|
||||||
|
* @return EntityManager
|
||||||
|
*/
|
||||||
|
static public function getInstance(string $class): self
|
||||||
|
{
|
||||||
|
// Create a new entity manager for this entity if it does not exist
|
||||||
|
if (!array_key_exists($class, self::$_instances)) {
|
||||||
|
// Check that the class is a child of AbstractEntity
|
||||||
|
if (!is_a($class, AbstractEntity::class, true)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Class "%s" does not extend "%s"', $class, AbstractEntity::class));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The entity manager works with SQL tables, so the entity needs to specify a table
|
||||||
|
if (!defined($class . '::TABLE')) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Class "%s" does not define a TABLE constant', $class));
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$_instances[$class] = new EntityManager($class);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$_instances[$class];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the database manager used for all entity managers, unless they have a specific one
|
||||||
|
* @param DB $db
|
||||||
|
*/
|
||||||
|
static public function setGlobalDB(DB $db): void
|
||||||
|
{
|
||||||
|
self::$_global_db = $db;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set local database object used for this entity manager
|
||||||
|
* @param DB|null $db Set to NULL to use the global manager
|
||||||
|
*/
|
||||||
|
public function setDB(?DB $db = null): void
|
||||||
|
{
|
||||||
|
$this->db = $db;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the correct database object for this entity manager
|
||||||
|
*/
|
||||||
|
public function DB(): DB
|
||||||
|
{
|
||||||
|
if (null !== $this->db) {
|
||||||
|
$db = $this->db;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$db = self::$_global_db;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $db) {
|
||||||
|
throw new \LogicException('No DB object has been set');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $db;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function __construct(string $class)
|
||||||
|
{
|
||||||
|
$this->class = $class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an Entity according to a query
|
||||||
|
* @param string $class Entity class name
|
||||||
|
* @param string $query SQL query
|
||||||
|
* @param mixed ...$params Optional parameters to be used in the query
|
||||||
|
* @return null|AbstractEntity
|
||||||
|
*/
|
||||||
|
static public function findOne(string $class, string $query, ...$params)
|
||||||
|
{
|
||||||
|
return self::getInstance($class)->one($query, ...$params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an Entity from its ID
|
||||||
|
* @param string $class Entity class name
|
||||||
|
* @param int $id Entity ID
|
||||||
|
* @return null|AbstractEntity
|
||||||
|
*/
|
||||||
|
static public function findOneById(string $class, int $id, ?string $table = null)
|
||||||
|
{
|
||||||
|
$query = sprintf('SELECT * FROM %s WHERE id = ?;', $table ?? $class::TABLE);
|
||||||
|
return self::findOne($class, $query, $id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a SQL query by replacing the table name with the entity table name
|
||||||
|
* @param string $query SQL query
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function formatQuery(string $query): string
|
||||||
|
{
|
||||||
|
$class = $this->class;
|
||||||
|
$query = str_replace('@TABLE', $class::TABLE, $query);
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function all(string $query, ...$params): array
|
||||||
|
{
|
||||||
|
$res = $this->iterate($query, ...$params);
|
||||||
|
$out = [];
|
||||||
|
|
||||||
|
foreach ($res as $row) {
|
||||||
|
$out[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function allAssoc(string $query, string $key, ...$params): array
|
||||||
|
{
|
||||||
|
$res = $this->iterate($query, ...$params);
|
||||||
|
$out = [];
|
||||||
|
|
||||||
|
foreach ($res as $row) {
|
||||||
|
$out[$row->$key] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function iterate(string $query, ...$params): iterable
|
||||||
|
{
|
||||||
|
$db = $this->DB();
|
||||||
|
$query = $this->formatQuery($query);
|
||||||
|
$res = $db->preparedQuery($query, $params);
|
||||||
|
|
||||||
|
if ($db instanceof SQLite3) {
|
||||||
|
while ($row = $res->fetchArray(\SQLITE3_ASSOC)) {
|
||||||
|
// If you are getting a row containing only NULL values
|
||||||
|
// it probably means you are deleting rows before the iteration
|
||||||
|
// has a chance to fetch it!
|
||||||
|
$obj = new $this->class;
|
||||||
|
$obj->exists(true);
|
||||||
|
$obj->load($row);
|
||||||
|
yield $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
$res->finalize();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$obj = new $this->class;
|
||||||
|
$obj->exists(true);
|
||||||
|
$obj->load($row);
|
||||||
|
yield $obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function one(string $query, ...$params)
|
||||||
|
{
|
||||||
|
$db = $this->DB();
|
||||||
|
|
||||||
|
$query = $this->formatQuery($query);
|
||||||
|
$res = $db->preparedQuery($query, $params);
|
||||||
|
|
||||||
|
if ($db instanceof SQLite3) {
|
||||||
|
$row = $res->fetchArray(\SQLITE3_ASSOC);
|
||||||
|
$res->finalize();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$row = $res->fetch(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $row) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$obj = new $this->class;
|
||||||
|
$obj->exists(true);
|
||||||
|
$obj->load($row);
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function col(string $query, ...$params)
|
||||||
|
{
|
||||||
|
$query = $this->formatQuery($query);
|
||||||
|
$db = $this->DB();
|
||||||
|
return $db->firstColumn($query, ...$params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save(AbstractEntity $entity, bool $selfcheck = true): bool
|
||||||
|
{
|
||||||
|
if ($selfcheck) {
|
||||||
|
$entity->selfCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = $this->DB();
|
||||||
|
|
||||||
|
if ($entity->exists()) {
|
||||||
|
if ($entity->isModified()) {
|
||||||
|
$data = array_intersect_key($entity->asArray(true), $entity->getModifiedProperties());
|
||||||
|
$return = $db->update($entity::TABLE, $data, $db->where('id', $entity->id()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$return = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$data = $entity->asArray(true);
|
||||||
|
$data = array_filter($data, static function($v) { return $v !== null; });
|
||||||
|
$return = $db->insert($entity::TABLE, $data);
|
||||||
|
|
||||||
|
if ($return) {
|
||||||
|
$id = (int) $db->lastInsertId();
|
||||||
|
|
||||||
|
if ($id < 1) {
|
||||||
|
throw new \LogicException('Error inserting entity in DB: invalid ID = ' . $id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$entity->exists(true);
|
||||||
|
$entity->id($id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$entity->clearModifiedProperties();
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(AbstractEntity $entity): bool
|
||||||
|
{
|
||||||
|
$db = $this->DB();
|
||||||
|
$return = $db->delete($entity::TABLE, $db->where('id', $entity->id()));
|
||||||
|
|
||||||
|
if ($return) {
|
||||||
|
$entity->exists(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
}
|
1168
src/include/lib/KD2/DB/SQLite3.php
Normal file
1168
src/include/lib/KD2/DB/SQLite3.php
Normal file
File diff suppressed because it is too large
Load diff
105
src/include/lib/KD2/DB/SQLite3_Undo.php
Normal file
105
src/include/lib/KD2/DB/SQLite3_Undo.php
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
This file is part of KD2FW -- <http://dev.kd2.org/>
|
||||||
|
|
||||||
|
Copyright (c) 2001-2020 BohwaZ <http://bohwaz.net/>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
KD2FW 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.
|
||||||
|
|
||||||
|
Foobar 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 KD2FW. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DB_SQLite3_Undo: adds the ability to undo/redo any SQL statement to a SQLite3 database
|
||||||
|
*
|
||||||
|
* @author bohwaz http://bohwaz.net/
|
||||||
|
* @license AGPLv3
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace KD2\DB;
|
||||||
|
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
class SQLite3_Undo
|
||||||
|
{
|
||||||
|
protected $db;
|
||||||
|
|
||||||
|
public function __construct(DB $db)
|
||||||
|
{
|
||||||
|
$this->db = $db;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disable(array $tables)
|
||||||
|
{
|
||||||
|
$db = $this->db;
|
||||||
|
|
||||||
|
foreach ($tables as $name) {
|
||||||
|
$sql = 'SELECT name, name FROM sqlite_master WHERE type = \'trigger\' AND name LIKE \'!_%s_log!__t\' ESCAPE \'!\';';
|
||||||
|
$sql = sprintf($sql, $name);
|
||||||
|
$triggers = $db->getAssoc($sql);
|
||||||
|
|
||||||
|
foreach ($triggers as $trigger)
|
||||||
|
{
|
||||||
|
$db->exec(sprintf('DROP TRIGGER %s;', $db->quoteIdentifier($trigger)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enable(array $tables)
|
||||||
|
{
|
||||||
|
$db = $this->db;
|
||||||
|
|
||||||
|
$db->exec('CREATE TABLE IF NOT EXISTS undolog (
|
||||||
|
seq INTEGER PRIMARY KEY,
|
||||||
|
table TEXT NOT NULL,
|
||||||
|
action TEXT NOT NULL
|
||||||
|
sql TEXT NOT NULL,
|
||||||
|
date TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
);');
|
||||||
|
|
||||||
|
$query = 'CREATE TRIGGER _%table_log_it AFTER INSERT ON %table BEGIN
|
||||||
|
DELETE FROM undolog WHERE rowid IN (SELECT rowid FROM undolog LIMIT 500,1000);
|
||||||
|
INSERT INTO undolog (table, action, sql) VALUES (\'%table\', \'I\', \'DELETE FROM %table WHERE rowid=\'||new.rowid);
|
||||||
|
END;
|
||||||
|
CREATE TRIGGER _%table_log_ut AFTER UPDATE ON %table BEGIN
|
||||||
|
DELETE FROM undolog WHERE rowid IN (SELECT rowid FROM undolog LIMIT 500,1000);
|
||||||
|
INSERT INTO undolog (table, action, sql) VALUES (\'%table\', \'U\', \'UPDATE %table SET %columns_update WHERE rowid = \'||old.rowid);
|
||||||
|
END;
|
||||||
|
CREATE TRIGGER _%table_log_dt BEFORE DELETE ON %table BEGIN
|
||||||
|
DELETE FROM undolog WHERE rowid IN (SELECT rowid FROM undolog LIMIT 500,1000);
|
||||||
|
INSERT INTO undolog (table, action, sql) VALUES (\'%table\', \'D\', \'INSERT INTO %table (rowid, %columns_list) VALUES(\'||old.rowid||\', %columns_insert)\');
|
||||||
|
END;';
|
||||||
|
|
||||||
|
foreach ($tables as $table)
|
||||||
|
{
|
||||||
|
$columns = $db->getAssoc(sprintf('PRAGMA table_info(%s);', $this->quoteIdentifier($table)));
|
||||||
|
$columns_insert = [];
|
||||||
|
$columns_update = [];
|
||||||
|
|
||||||
|
foreach ($columns as &$name)
|
||||||
|
{
|
||||||
|
$columns_update[] = sprintf('%s = \'||quote(old.%1$s)||\'', $name);
|
||||||
|
$columns_insert[] = sprintf('\'||quote(old.%s)||\'', $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = strtr($query, [
|
||||||
|
'%table' => $table,
|
||||||
|
'%columns_list' => implode(', ', $columns),
|
||||||
|
'%columns_update' => implode(', ', $columns_update),
|
||||||
|
'%columns_insert' => implode(', ', $columns_insert),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$db->exec($sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
205
src/include/lib/KD2/DNS.php
Normal file
205
src/include/lib/KD2/DNS.php
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace KD2;
|
||||||
|
|
||||||
|
class DNS
|
||||||
|
{
|
||||||
|
static public function getRecordsFromDomainNS(string $type, string $record): array
|
||||||
|
{
|
||||||
|
$ns = dns_get_record($record, \DNS_NS);
|
||||||
|
|
||||||
|
if (empty($ns) || empty($ns[0]['target'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ns = $ns[0]['target'];
|
||||||
|
|
||||||
|
return self::getRecordsFrom($ns, $type, $record);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a DNS a request to a custom nameserver, this is similar to dns_get_record, but allows you to query any nameserver
|
||||||
|
* Usage: dns_get_record_from('ns.server.tld', 'A', 'mydomain.tld');
|
||||||
|
* => ['42.42.42.42']
|
||||||
|
* @author bohwaz
|
||||||
|
* @see https://github.com/DaveRandom/LibDNS
|
||||||
|
* @see https://cabulous.medium.com/dns-message-how-to-read-query-and-response-message-cfebcb4fe817
|
||||||
|
*/
|
||||||
|
static public function getRecordsFrom(string $server, string $type, string $record, string $protocol = 'udp'): array
|
||||||
|
{
|
||||||
|
// Source: https://github.com/metaregistrar/php-dns-client/blob/master/DNS/dnsData/dnsTypes.php
|
||||||
|
static $types = [
|
||||||
|
1 => 'A',
|
||||||
|
2 => 'NS',
|
||||||
|
5 => 'CNAME',
|
||||||
|
6 => 'SOA',
|
||||||
|
12 => 'PTR',
|
||||||
|
15 => 'MX',
|
||||||
|
16 => 'TXT',
|
||||||
|
28 => 'AAAA',
|
||||||
|
255 => 'ANY',
|
||||||
|
];
|
||||||
|
|
||||||
|
$typeid = array_search($type, $types, true);
|
||||||
|
|
||||||
|
if (!$typeid) {
|
||||||
|
throw new \InvalidArgumentException('Invalid type');
|
||||||
|
}
|
||||||
|
|
||||||
|
$host = $protocol . '://' . $server;
|
||||||
|
|
||||||
|
if (!$socket = @fsockopen($host, 53, $errno, $errstr, 10)) {
|
||||||
|
throw new \RuntimeException('Failed to open socket to ' . $host);
|
||||||
|
}
|
||||||
|
|
||||||
|
//stream_set_chunk_size($socket, 0xffff);
|
||||||
|
//stream_set_blocking($socket, false);
|
||||||
|
|
||||||
|
$labels = explode('.', $record);
|
||||||
|
$question_binary = '';
|
||||||
|
|
||||||
|
foreach ($labels as $label) {
|
||||||
|
$question_binary .= pack("C", strlen($label)); // size byte first
|
||||||
|
$question_binary .= $label; // then the label
|
||||||
|
}
|
||||||
|
|
||||||
|
$question_binary .= pack("C", 0); // end it off
|
||||||
|
|
||||||
|
$id = rand(1,255)|(rand(0,255)<<8); // generate the ID
|
||||||
|
|
||||||
|
// Set standard codes and flags
|
||||||
|
$flags = (0x0100 & 0x0300) | 0x0020; // recursion & queryspecmask | authenticated data
|
||||||
|
|
||||||
|
$opcode = 0x0000; // opcode
|
||||||
|
|
||||||
|
// Build the header
|
||||||
|
$header = "";
|
||||||
|
$header .= pack("n", $id);
|
||||||
|
$header .= pack("n", $opcode | $flags);
|
||||||
|
$header .= pack("nnnn", 1, 0, 0, 0);
|
||||||
|
$header .= $question_binary;
|
||||||
|
$header .= pack("n", $typeid);
|
||||||
|
$header .= pack("n", 0x0001); // internet class
|
||||||
|
$headersize = strlen($header);
|
||||||
|
$headersizebin = pack("n", $headersize);
|
||||||
|
$header = $headersizebin . $header;
|
||||||
|
|
||||||
|
$request_size = fwrite($socket, $header, $headersize);
|
||||||
|
$rawbuffer = fread($socket, 1);
|
||||||
|
fclose($socket);
|
||||||
|
|
||||||
|
if (strlen($rawbuffer) < 12) {
|
||||||
|
throw new \UnderflowException("DNS query return buffer too small");
|
||||||
|
}
|
||||||
|
|
||||||
|
$pos = 0;
|
||||||
|
|
||||||
|
$read = function ($len) use (&$pos, $rawbuffer) {
|
||||||
|
$out = substr($rawbuffer, $pos, $len);
|
||||||
|
$pos += $len;
|
||||||
|
return $out;
|
||||||
|
};
|
||||||
|
|
||||||
|
$read_name_pos = function ($offset) use ($rawbuffer) {
|
||||||
|
$out = [];
|
||||||
|
|
||||||
|
while (($len = ord(substr($rawbuffer, $offset, 1))) && $len > 0) {
|
||||||
|
$out[] = substr($rawbuffer, $offset + 1, $len);
|
||||||
|
$offset += $len + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
};
|
||||||
|
|
||||||
|
$read_name = function() use (&$read, $read_name_pos) {
|
||||||
|
$out = [];
|
||||||
|
|
||||||
|
while (($len = ord($read(1))) && $len > 0) {
|
||||||
|
if ($len >= 64) {
|
||||||
|
$offset = (($len & 0x3f) << 8) + ord($read(1));
|
||||||
|
$out = array_merge($out, $read_name_pos($offset));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$out[] = $read($len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode('.', $out);
|
||||||
|
};
|
||||||
|
|
||||||
|
$header = unpack("nid/nfields/nqdcount/nancount/nnscount/narcount", $read(12));
|
||||||
|
$fields = $header['fields'];
|
||||||
|
|
||||||
|
$flags = new \stdClass;
|
||||||
|
$flags->rcode = $fields & 0xf;
|
||||||
|
$flags->ra = (($fields >> 7) & 1) === 1;
|
||||||
|
$flags->rd = (($fields >> 8) & 1) === 1;
|
||||||
|
$flags->tc = (($fields >> 9) & 1) === 1;
|
||||||
|
$flags->aa = (($fields >> 10) & 1) === 1;
|
||||||
|
$flags->opcode = ($fields >> 11) & 0xf;
|
||||||
|
$flags->qr = (($fields >> 15) & 1) === 1;
|
||||||
|
|
||||||
|
|
||||||
|
if ($flags->tc) {
|
||||||
|
throw new \OverflowException('The DNS server returned a truncated result for a UDP query');
|
||||||
|
}
|
||||||
|
|
||||||
|
// No answers
|
||||||
|
if (!$header['ancount']) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$is_authorative = $flags->aa;
|
||||||
|
|
||||||
|
// Question section
|
||||||
|
if ($header['qdcount']) {
|
||||||
|
// Skip name
|
||||||
|
$read_name();
|
||||||
|
|
||||||
|
// skip question part
|
||||||
|
$pos += 4; // 4 => QTYPE + QCLASS
|
||||||
|
}
|
||||||
|
|
||||||
|
$responses = [];
|
||||||
|
|
||||||
|
for ($a = 0; $a < $header['ancount']; $a++) {
|
||||||
|
$read_name(); // Skip name
|
||||||
|
$ans_header = unpack("ntype/nclass/Nttl/nlength", $read(10));
|
||||||
|
|
||||||
|
$t = $types[$ans_header['type']] ?? null;
|
||||||
|
|
||||||
|
if ($type != 'ANY' && $t != $type) {
|
||||||
|
// Skip type that was not requested
|
||||||
|
$t = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($t) {
|
||||||
|
case 'A':
|
||||||
|
$responses[] = implode(".", unpack("Ca/Cb/Cc/Cd", $read(4)));
|
||||||
|
break;
|
||||||
|
case 'AAAA':
|
||||||
|
$responses[] = implode(':', unpack("H4a/H4b/H4c/H4d/H4e/H4f/H4g/H4h", $read(16)));
|
||||||
|
break;
|
||||||
|
case 'MX':
|
||||||
|
$prio = unpack('nprio', $read(2)); // priority
|
||||||
|
$responses[$prio['prio']] = $read_name();
|
||||||
|
break;
|
||||||
|
case 'NS':
|
||||||
|
case 'CNAME':
|
||||||
|
case 'PTR':
|
||||||
|
$responses[] = $read_name();
|
||||||
|
break;
|
||||||
|
case 'TXT':
|
||||||
|
$responses[] = $read($ans_header['length']);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Skip
|
||||||
|
$read($ans_header['length']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $responses;
|
||||||
|
}
|
||||||
|
}
|
693
src/include/lib/KD2/Delta.php
Normal file
693
src/include/lib/KD2/Delta.php
Normal file
|
@ -0,0 +1,693 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
This file is part of KD2FW -- <http://dev.kd2.org/>
|
||||||
|
|
||||||
|
Copyright (c) 2001-2019 BohwaZ <http://bohwaz.net/>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
KD2FW 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.
|
||||||
|
|
||||||
|
Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace KD2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delta algorithm
|
||||||
|
* ported from the C code of Fossil SCM
|
||||||
|
* http://www.fossil-scm.org/xfer/doc/trunk/www/delta_format.wiki
|
||||||
|
* http://www.fossil-scm.org/xfer/doc/trunk/www/delta_encoder_algorithm.wiki
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2006 D. Richard Hipp
|
||||||
|
** Copyright (c) 2013 BohwaZ (PHP port)
|
||||||
|
**
|
||||||
|
** Authors contact information:
|
||||||
|
** drh@hwaci.com
|
||||||
|
** http://www.hwaci.com/drh/
|
||||||
|
**
|
||||||
|
** http://bohwaz.net/
|
||||||
|
**
|
||||||
|
*******************************************************************************
|
||||||
|
**/
|
||||||
|
|
||||||
|
class Delta_Hash
|
||||||
|
{
|
||||||
|
public $a; /* Hash values */
|
||||||
|
public $b;
|
||||||
|
public $i; /* Start of the hash window */
|
||||||
|
public $z; /* The values that have been hashed */
|
||||||
|
|
||||||
|
public function __set($key, $value)
|
||||||
|
{
|
||||||
|
if (($key == 'a' || $key == 'b' || $key == 'i') && (!is_int($value) || $value > 2^16)) {
|
||||||
|
throw new \OutOfBoundsException($key . ' value must be a 16 bits integer');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($key != 'z')
|
||||||
|
{
|
||||||
|
$this->{$key} = $value & 0xffff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->{$key} = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Delta
|
||||||
|
{
|
||||||
|
const NHASH = 16;
|
||||||
|
public $debug_enabled = false;
|
||||||
|
|
||||||
|
protected function debug($msg)
|
||||||
|
{
|
||||||
|
echo str_replace("\n", '.', $msg) . "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emulates C-like 32-bits integer
|
||||||
|
* @param mixed $number
|
||||||
|
* @return integer Unsigned integer
|
||||||
|
*/
|
||||||
|
protected function u32($number)
|
||||||
|
{
|
||||||
|
return $number & 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emulates C-like 16-bit integer
|
||||||
|
* @param mixed $number
|
||||||
|
* @return mixed Unsigned integer
|
||||||
|
*/
|
||||||
|
protected function u16($number)
|
||||||
|
{
|
||||||
|
return $number & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Initialize the rolling hash using the first NHASH characters of z[]
|
||||||
|
*/
|
||||||
|
protected function hash_init(Delta_Hash &$pHash, $z)
|
||||||
|
{
|
||||||
|
$a = $b = 0;
|
||||||
|
|
||||||
|
for ($i=0; $i < self::NHASH; $i++) {
|
||||||
|
$a += ord($z[$i]);
|
||||||
|
$b += (self::NHASH - $i) * ord($z[$i]);
|
||||||
|
$pHash->z[$i] = ord($z[$i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pHash->a = $a & 0xffff;
|
||||||
|
$pHash->b = $b & 0xffff;
|
||||||
|
$pHash->i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Advance the rolling hash by a single character "c"
|
||||||
|
*/
|
||||||
|
protected function hash_next(Delta_Hash &$pHash, $c)
|
||||||
|
{
|
||||||
|
$old = $this->u16($pHash->z[$pHash->i]);
|
||||||
|
$pHash->z[$pHash->i] = $c;
|
||||||
|
$pHash->i = ($pHash->i+1) & (self::NHASH - 1);
|
||||||
|
$pHash->a = $pHash->a - $old + $c;
|
||||||
|
$pHash->b = $pHash->b - self::NHASH * $old + $pHash->a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return a 32-bit hash value
|
||||||
|
*/
|
||||||
|
protected function hash_32bit(Delta_Hash $pHash)
|
||||||
|
{
|
||||||
|
return ($pHash->a & 0xffff) | sprintf('%u', $this->u32(($pHash->b & 0xffff)<<16));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Write an base-64 integer into the given buffer.
|
||||||
|
*/
|
||||||
|
protected function putInt($v)
|
||||||
|
{
|
||||||
|
static $zDigits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~';
|
||||||
|
/* 123456789 123456789 123456789 123456789 123456789 123456789 123 */
|
||||||
|
|
||||||
|
$zBuf = (string)'';
|
||||||
|
$pz = '';
|
||||||
|
|
||||||
|
if ( $v == 0 ) {
|
||||||
|
return $pz . '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i=0; $v>0; $i++, $v>>=6) {
|
||||||
|
$zBuf[$i] = $zDigits[$v&0x3f];
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($j = $i-1; $j>=0; $j--) {
|
||||||
|
$pz .= $zBuf[$j];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $pz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Read bytes from *pz and convert them into a positive integer. When
|
||||||
|
** finished, leave *pz pointing to the first character past the end of
|
||||||
|
** the integer. The *pLen parameter holds the length of the string
|
||||||
|
** in *pz and is decremented once for each character in the integer.
|
||||||
|
*/
|
||||||
|
protected function getInt(&$pz, &$pLen)
|
||||||
|
{
|
||||||
|
$zValue = array(
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||||
|
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||||
|
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36,
|
||||||
|
-1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
|
||||||
|
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1,
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($zValue as &$row)
|
||||||
|
{
|
||||||
|
$row = $this->u32($row);
|
||||||
|
}
|
||||||
|
|
||||||
|
$v = 0;
|
||||||
|
$z = 0;
|
||||||
|
|
||||||
|
while ( ($c = $zValue[0x7f&ord($pz[$z++])]) != $this->u32(-1) ) {
|
||||||
|
$v = ($v<<6) + $c;
|
||||||
|
}
|
||||||
|
|
||||||
|
$z--;
|
||||||
|
$pz = substr($pz, $z);
|
||||||
|
$pLen = strlen($pz);
|
||||||
|
return $v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return the number digits in the base-64 representation of a positive integer
|
||||||
|
*/
|
||||||
|
protected function digit_count($v)
|
||||||
|
{
|
||||||
|
for($i=1, $x=64; $v >= $x; $i++, $x <<= 6){}
|
||||||
|
return $i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Compute a 32-bit checksum on the N-byte buffer. Return the result.
|
||||||
|
*/
|
||||||
|
protected function checksum($z, $N)
|
||||||
|
{
|
||||||
|
$sum0 = $sum1 = $sum2 = $sum3 = (float)0.0;
|
||||||
|
|
||||||
|
while ($N >= 16)
|
||||||
|
{
|
||||||
|
$sum0 += (ord($z[0]) + ord($z[4]) + ord($z[8]) + ord($z[12]));
|
||||||
|
$sum1 += (ord($z[1]) + ord($z[5]) + ord($z[9]) + ord($z[13]));
|
||||||
|
$sum2 += (ord($z[2]) + ord($z[6]) + ord($z[10]) + ord($z[14]));
|
||||||
|
$sum3 += (ord($z[3]) + ord($z[7]) + ord($z[11]) + ord($z[15]));
|
||||||
|
$z = substr($z, 16);
|
||||||
|
$N -= 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($N >= 4) {
|
||||||
|
$sum0 += ord($z[0]);
|
||||||
|
$sum1 += ord($z[1]);
|
||||||
|
$sum2 += ord($z[2]);
|
||||||
|
$sum3 += ord($z[3]);
|
||||||
|
$z = substr($z, 4);
|
||||||
|
$N -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sum3 += $this->u32($sum2 << 8) + $this->u32($sum1 << 16) + $this->u32($sum0 << 24);
|
||||||
|
|
||||||
|
switch ($N) {
|
||||||
|
case 3: $sum3 += $this->u32(ord($z[2]) << 8);
|
||||||
|
case 2: $sum3 += $this->u32(ord($z[1]) << 16);
|
||||||
|
case 1: $sum3 += $this->u32(ord($z[0]) << 24);
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sum3 = $this->u32($sum3);
|
||||||
|
return sprintf('%u', $sum3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Create a new delta.
|
||||||
|
**
|
||||||
|
** The delta is written into a preallocated buffer, zDelta, which
|
||||||
|
** should be at least 60 bytes longer than the target file, zOut.
|
||||||
|
** The delta string will be NUL-terminated, but it might also contain
|
||||||
|
** embedded NUL characters if either the zSrc or zOut files are
|
||||||
|
** binary. This function returns the length of the delta string
|
||||||
|
** in bytes, excluding the final NUL terminator character.
|
||||||
|
**
|
||||||
|
** Output Format:
|
||||||
|
**
|
||||||
|
** The delta begins with a base64 number followed by a newline. This
|
||||||
|
** number is the number of bytes in the TARGET file. Thus, given a
|
||||||
|
** delta file z, a program can compute the size of the output file
|
||||||
|
** simply by reading the first line and decoding the base-64 number
|
||||||
|
** found there. The delta_output_size() routine does exactly this.
|
||||||
|
**
|
||||||
|
** After the initial size number, the delta consists of a series of
|
||||||
|
** literal text segments and commands to copy from the SOURCE file.
|
||||||
|
** A copy command looks like this:
|
||||||
|
**
|
||||||
|
** NNN@MMM,
|
||||||
|
**
|
||||||
|
** where NNN is the number of bytes to be copied and MMM is the offset
|
||||||
|
** into the source file of the first byte (both base-64). If NNN is 0
|
||||||
|
** it means copy the rest of the input file. Literal text is like this:
|
||||||
|
**
|
||||||
|
** NNN:TTTTT
|
||||||
|
**
|
||||||
|
** where NNN is the number of bytes of text (base-64) and TTTTT is the text.
|
||||||
|
**
|
||||||
|
** The last term is of the form
|
||||||
|
**
|
||||||
|
** NNN;
|
||||||
|
**
|
||||||
|
** In this case, NNN is a 32-bit bigendian checksum of the output file
|
||||||
|
** that can be used to verify that the delta applied correctly. All
|
||||||
|
** numbers are in base-64.
|
||||||
|
**
|
||||||
|
** Pure text files generate a pure text delta. Binary files generate a
|
||||||
|
** delta that may contain some binary data.
|
||||||
|
**
|
||||||
|
** Algorithm:
|
||||||
|
**
|
||||||
|
** The encoder first builds a hash table to help it find matching
|
||||||
|
** patterns in the source file. 16-byte chunks of the source file
|
||||||
|
** sampled at evenly spaced intervals are used to populate the hash
|
||||||
|
** table.
|
||||||
|
**
|
||||||
|
** Next we begin scanning the target file using a sliding 16-byte
|
||||||
|
** window. The hash of the 16-byte window in the target is used to
|
||||||
|
** search for a matching section in the source file. When a match
|
||||||
|
** is found, a copy command is added to the delta. An effort is
|
||||||
|
** made to extend the matching section to regions that come before
|
||||||
|
** and after the 16-byte hash window. A copy command is only issued
|
||||||
|
** if the result would use less space that just quoting the text
|
||||||
|
** literally. Literal text is added to the delta for sections that
|
||||||
|
** do not match or which can not be encoded efficiently using copy
|
||||||
|
** commands.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the difference between $zSrc and $zOut and returns the delta
|
||||||
|
* @param string $zSrc Binary content of source file
|
||||||
|
* @param string $zOut Binary content of target file
|
||||||
|
* @return string Delta
|
||||||
|
*/
|
||||||
|
public function create($zSrc, $zOut)
|
||||||
|
{
|
||||||
|
$lenSrc = strlen($zSrc);
|
||||||
|
$lenOut = strlen($zOut);
|
||||||
|
|
||||||
|
$zDelta = '';
|
||||||
|
|
||||||
|
$h = new Delta_Hash;
|
||||||
|
$nHash = 0; /* Number of hash table entries */
|
||||||
|
$landmark = 0; /* Primary hash table */
|
||||||
|
$collide = 0; /* Collision chain */
|
||||||
|
$lastRead = 0xffffffff; /* Last byte of zSrc read by a COPY command */
|
||||||
|
|
||||||
|
/* Add the target file size to the beginning of the delta
|
||||||
|
*/
|
||||||
|
$zDelta .= $this->putInt($lenOut);
|
||||||
|
$zDelta .= "\n";
|
||||||
|
|
||||||
|
/* If the source file is very small, it means that we have no
|
||||||
|
** chance of ever doing a copy command. Just output a single
|
||||||
|
** literal segment for the entire target and exit.
|
||||||
|
*/
|
||||||
|
if ($lenSrc <= self::NHASH)
|
||||||
|
{
|
||||||
|
$zDelta .= $this->putInt($lenOut);
|
||||||
|
$zDelta .= ':';
|
||||||
|
$zDelta .= substr($zOut, 0, $lenOut);
|
||||||
|
$zDelta .= $this->putInt($this->checksum($zOut, $lenOut));
|
||||||
|
$zDelta .= ';';
|
||||||
|
return $zDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute the hash table used to locate matching sections in the
|
||||||
|
** source file.
|
||||||
|
*/
|
||||||
|
$nHash = (int) ($lenSrc / self::NHASH);
|
||||||
|
$collide = array_fill(0, $nHash * 2 * PHP_INT_SIZE, $this->u32(-1));
|
||||||
|
$landmark = array_slice($collide, $nHash);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $lenSrc - self::NHASH; $i += self::NHASH)
|
||||||
|
{
|
||||||
|
$this->hash_init($h, substr($zSrc, $i, self::NHASH));
|
||||||
|
$hv = $this->hash_32bit($h) % $nHash;
|
||||||
|
$collide[$i / self::NHASH] = $landmark[$hv];
|
||||||
|
$landmark[$hv] = $i / self::NHASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Begin scanning the target file and generating copy commands and
|
||||||
|
** literal sections of the delta.
|
||||||
|
*/
|
||||||
|
$base = 0; /* We have already generated everything before zOut[base] */
|
||||||
|
while ($base + self::NHASH < $lenOut)
|
||||||
|
{
|
||||||
|
$bestOfst = 0;
|
||||||
|
$bestLitsz = 0;
|
||||||
|
|
||||||
|
$this->hash_init($h, substr($zOut, $base, self::NHASH));
|
||||||
|
|
||||||
|
$i = 0; /* Trying to match a landmark against zOut[base+i] */
|
||||||
|
$bestCnt = 0;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
$limit = 250;
|
||||||
|
|
||||||
|
$hv = $this->hash_32bit($h) % $nHash;
|
||||||
|
|
||||||
|
if ($this->debug_enabled) {
|
||||||
|
$this->debug(sprintf("LOOKING: %4d [%s]", $base+$i, substr($zOut, $base + $i, 16)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$iBlock = $landmark[$hv];
|
||||||
|
|
||||||
|
while ($iBlock != $this->u32(-1) && $iBlock >= 0 && ($limit--) > 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** The hash window has identified a potential match against
|
||||||
|
** landmark block iBlock. But we need to investigate further.
|
||||||
|
**
|
||||||
|
** Look for a region in zOut that matches zSrc. Anchor the search
|
||||||
|
** at zSrc[iSrc] and zOut[base+i]. Do not include anything prior to
|
||||||
|
** zOut[base] or after zOut[outLen] nor anything after zSrc[srcLen].
|
||||||
|
**
|
||||||
|
** Set cnt equal to the length of the match and set ofst so that
|
||||||
|
** zSrc[ofst] is the first element of the match. litsz is the number
|
||||||
|
** of characters between zOut[base] and the beginning of the match.
|
||||||
|
** sz will be the overhead (in bytes) needed to encode the copy
|
||||||
|
** command. Only generate copy command if the overhead of the
|
||||||
|
** copy command is less than the amount of literal text to be copied.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Beginning at iSrc, match forwards as far as we can. j counts
|
||||||
|
** the number of characters that match */
|
||||||
|
$iSrc = $iBlock * self::NHASH;
|
||||||
|
|
||||||
|
for($j = 0, $x = $iSrc, $y = $base + $i; $x < $lenSrc && $y < $lenOut; $j++, $x++, $y++)
|
||||||
|
{
|
||||||
|
if ($zSrc[$x] != $zOut[$y])
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$j--;
|
||||||
|
|
||||||
|
/* Beginning at iSrc-1, match backwards as far as we can. k counts
|
||||||
|
** the number of characters that match */
|
||||||
|
for ($k = 1; $k < $iSrc && $k <= $i; $k++)
|
||||||
|
{
|
||||||
|
if ($zSrc[$iSrc - $k] != $zOut[$base + $i - $k])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$k--;
|
||||||
|
|
||||||
|
/* Compute the offset and size of the matching region */
|
||||||
|
$ofst = $iSrc - $k;
|
||||||
|
$cnt = $j + $k + 1;
|
||||||
|
$litsz = $i - $k; /* Number of bytes of literal text before the copy */
|
||||||
|
|
||||||
|
if ($this->debug_enabled) {
|
||||||
|
$this->debug(sprintf("MATCH %d bytes at %d: [%s] litsz=%d", $cnt, $ofst, substr($zSrc, $ofst, 16), $litsz));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sz will hold the number of bytes needed to encode the "insert"
|
||||||
|
** command and the copy command, not counting the "insert" text */
|
||||||
|
$sz = $this->digit_count($i - $k) + $this->digit_count($cnt) + $this->digit_count($ofst) + 3;
|
||||||
|
|
||||||
|
if ($cnt >= $sz && $cnt > $bestCnt )
|
||||||
|
{
|
||||||
|
/* Remember this match only if it is the best so far and it
|
||||||
|
** does not increase the file size */
|
||||||
|
$bestCnt = $cnt;
|
||||||
|
$bestOfst = $iSrc - $k;
|
||||||
|
$bestLitsz = $litsz;
|
||||||
|
|
||||||
|
if ($this->debug_enabled) {
|
||||||
|
$this->debug(sprintf("... BEST SO FAR"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the next matching block */
|
||||||
|
$iBlock = $collide[$iBlock];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have a copy command that does not cause the delta to be larger
|
||||||
|
** than a literal insert. So add the copy command to the delta.
|
||||||
|
*/
|
||||||
|
if ($bestCnt > 0)
|
||||||
|
{
|
||||||
|
if ($bestLitsz > 0)
|
||||||
|
{
|
||||||
|
/* Add an insert command before the copy */
|
||||||
|
$zDelta .= $this->putInt($bestLitsz);
|
||||||
|
$zDelta .= ':';
|
||||||
|
$zDelta .= substr($zOut, $base, $bestLitsz);
|
||||||
|
$base += $bestLitsz;
|
||||||
|
|
||||||
|
if ($this->debug_enabled) {
|
||||||
|
$this->debug(sprintf("insert %d", $bestLitsz));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$base += $bestCnt;
|
||||||
|
$zDelta .= $this->putInt($bestCnt);
|
||||||
|
$zDelta .= '@';
|
||||||
|
$zDelta .= $this->putInt($bestOfst);
|
||||||
|
|
||||||
|
if ($this->debug_enabled) {
|
||||||
|
$this->debug(sprintf("copy %d bytes from %d", $bestCnt, $bestOfst));
|
||||||
|
}
|
||||||
|
|
||||||
|
$zDelta .= ',';
|
||||||
|
|
||||||
|
if ($bestOfst + $bestCnt - 1 > $lastRead)
|
||||||
|
{
|
||||||
|
$lastRead = $bestOfst + $bestCnt - 1;
|
||||||
|
|
||||||
|
if ($this->debug_enabled) {
|
||||||
|
$this->debug(sprintf("lastRead becomes %d", $lastRead));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$bestCnt = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we reach this point, it means no match is found so far */
|
||||||
|
if ($base + $i + self::NHASH >= $lenOut)
|
||||||
|
{
|
||||||
|
/* We have reached the end of the file and have not found any
|
||||||
|
** matches. Do an "insert" for everything that does not match */
|
||||||
|
$zDelta .= $this->putInt($lenOut - $base);
|
||||||
|
$zDelta .= ':';
|
||||||
|
$zDelta .= substr($zOut, $base, $lenOut - $base);
|
||||||
|
$base = $lenOut;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance the hash by one character. Keep looking for a match */
|
||||||
|
$this->hash_next($h, ord($zOut[$base + $i + self::NHASH]));
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output a final "insert" record to get all the text at the end of
|
||||||
|
** the file that does not match anything in the source file.
|
||||||
|
*/
|
||||||
|
if ($base < $lenOut)
|
||||||
|
{
|
||||||
|
$zDelta .= $this->putInt($lenOut - $base);
|
||||||
|
$zDelta .= ':';
|
||||||
|
$zDelta .= substr($zOut, $base, $lenOut - $base);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output the final checksum record. */
|
||||||
|
$zDelta .= $this->putInt($this->checksum($zOut, $lenOut));
|
||||||
|
$zDelta .= ';';
|
||||||
|
unset($collide);
|
||||||
|
|
||||||
|
return $zDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return the size (in bytes) of the output from applying
|
||||||
|
** a delta.
|
||||||
|
**
|
||||||
|
** This routine is provided so that an procedure that is able
|
||||||
|
** to call delta_apply() can learn how much space is required
|
||||||
|
** for the output and hence allocate nor more space that is really
|
||||||
|
** needed.
|
||||||
|
*/
|
||||||
|
public function outputSize($zDelta)
|
||||||
|
{
|
||||||
|
$lenDelta = strlen($zDelta);
|
||||||
|
$size = $this->getInt($zDelta, $lenDelta);
|
||||||
|
|
||||||
|
if (substr($zDelta, 0, 1) != "\n")
|
||||||
|
{
|
||||||
|
/* ERROR: size integer not terminated by "\n" */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Apply a delta.
|
||||||
|
**
|
||||||
|
** The output buffer should be big enough to hold the whole output
|
||||||
|
** file and a NUL terminator at the end. The delta_output_size()
|
||||||
|
** routine will determine this size for you.
|
||||||
|
**
|
||||||
|
** The delta string should be null-terminated. But the delta string
|
||||||
|
** may contain embedded NUL characters (if the input and output are
|
||||||
|
** binary files) so we also have to pass in the length of the delta in
|
||||||
|
** the lenDelta parameter.
|
||||||
|
**
|
||||||
|
** This function returns the size of the output file in bytes (excluding
|
||||||
|
** the final NUL terminator character). Except, if the delta string is
|
||||||
|
** malformed or intended for use with a source file other than zSrc,
|
||||||
|
** then this routine returns -1.
|
||||||
|
**
|
||||||
|
** Refer to the delta_create() documentation above for a description
|
||||||
|
** of the delta file format.
|
||||||
|
*/
|
||||||
|
public function apply($zSrc, $zDelta)
|
||||||
|
{
|
||||||
|
$zOut = '';
|
||||||
|
$lenSrc = strlen($zSrc);
|
||||||
|
$lenDelta = strlen($zDelta);
|
||||||
|
|
||||||
|
$total = 0;
|
||||||
|
$zOut;
|
||||||
|
|
||||||
|
$limit = $this->getInt($zDelta, $lenDelta);
|
||||||
|
|
||||||
|
if (substr($zDelta, 0, 1) != "\n")
|
||||||
|
{
|
||||||
|
throw new \UnexpectedValueException('size integer not terminated by "\n"');
|
||||||
|
}
|
||||||
|
|
||||||
|
$zDelta = substr($zDelta, 1);
|
||||||
|
$lenDelta--;
|
||||||
|
|
||||||
|
while ($zDelta != '' && $lenDelta > 0)
|
||||||
|
{
|
||||||
|
$cnt = $this->getInt($zDelta, $lenDelta);
|
||||||
|
|
||||||
|
switch ($zDelta[0])
|
||||||
|
{
|
||||||
|
case '@':
|
||||||
|
{
|
||||||
|
$zDelta = substr($zDelta, 1);
|
||||||
|
$lenDelta--;
|
||||||
|
|
||||||
|
$ofst = $this->getInt($zDelta, $lenDelta);
|
||||||
|
|
||||||
|
if ($lenDelta > 0 && $zDelta[0] != ',' )
|
||||||
|
{
|
||||||
|
throw new \RuntimeException("copy command not terminated by ','");
|
||||||
|
}
|
||||||
|
|
||||||
|
$zDelta = substr($zDelta, 1);
|
||||||
|
$lenDelta--;
|
||||||
|
|
||||||
|
if ($this->debug_enabled) {
|
||||||
|
$this->debug(sprintf("COPY %d from %d\n", $cnt, $ofst));
|
||||||
|
}
|
||||||
|
|
||||||
|
$total += $cnt;
|
||||||
|
|
||||||
|
if ($total > $limit)
|
||||||
|
{
|
||||||
|
throw new \RuntimeException('copy exceeds output file size');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ofst + $cnt > $lenSrc)
|
||||||
|
{
|
||||||
|
throw new \RuntimeException('copy extends past end of input');
|
||||||
|
}
|
||||||
|
|
||||||
|
$zOut .= substr($zSrc, $ofst, $cnt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ':':
|
||||||
|
{
|
||||||
|
$zDelta = substr($zDelta, 1);
|
||||||
|
$lenDelta--;
|
||||||
|
$total += $cnt;
|
||||||
|
|
||||||
|
if ($total > $limit)
|
||||||
|
{
|
||||||
|
throw new \RuntimeException('insert command gives an output larger than predicted');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->debug_enabled) {
|
||||||
|
$this->debug(sprintf("INSERT %d\n", $cnt));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cnt > $lenDelta)
|
||||||
|
{
|
||||||
|
throw new \RuntimeException('insert count exceeds size of delta');
|
||||||
|
}
|
||||||
|
|
||||||
|
$zOut .= substr($zDelta, 0, $cnt);
|
||||||
|
$zDelta = substr($zDelta, $cnt);
|
||||||
|
$lenDelta -= $cnt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ';':
|
||||||
|
{
|
||||||
|
$zDelta = substr($zDelta, 1);
|
||||||
|
$lenDelta--;
|
||||||
|
|
||||||
|
if ($cnt != ($ck = $this->checksum($zOut, $total)))
|
||||||
|
{
|
||||||
|
throw new \RuntimeException('bad checksum: '.sprintf("%u", $ck));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($total != $limit)
|
||||||
|
{
|
||||||
|
throw new \RuntimeException('generated size does not match predicted size');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $zOut;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new \RuntimeException('unknown delta operator: ' . sprintf("'%s'", $zDelta[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \RuntimeException('unterminated delta');
|
||||||
|
}
|
||||||
|
}
|
1157
src/include/lib/KD2/ErrorManager.php
Normal file
1157
src/include/lib/KD2/ErrorManager.php
Normal file
File diff suppressed because it is too large
Load diff
707
src/include/lib/KD2/FeedParser.php
Normal file
707
src/include/lib/KD2/FeedParser.php
Normal file
|
@ -0,0 +1,707 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
This file is part of KD2FW -- <http://dev.kd2.org/>
|
||||||
|
|
||||||
|
Copyright (c) 2001-2019 BohwaZ <http://bohwaz.net/>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
KD2FW 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.
|
||||||
|
|
||||||
|
Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace KD2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple and loosy feed parser
|
||||||
|
*
|
||||||
|
* This parser is not using any XML or DOM parsing library
|
||||||
|
* as a result of this it can parse any kind of feed, even if it
|
||||||
|
* is invalid or broken.
|
||||||
|
*
|
||||||
|
* It will parse and provide most common properties for every item
|
||||||
|
* and also an array of all the tags found for the item, allowing
|
||||||
|
* easy extension on specific features (like medias for example).
|
||||||
|
*
|
||||||
|
* Copyleft (C) 2012-2013 BohwaZ <http://bohwaz.net/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
class FeedParser
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Possible feed mime types
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected static $mime_types = array(
|
||||||
|
'application/atom+xml',
|
||||||
|
'application/rss+xml',
|
||||||
|
'application/rdf+xml'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feed format (rss/atom)
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $format = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feed vendor (netscape/w3c/userland/rss-dev-wg/imc)
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $vendor = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feed spec version (1.0/0.9x/2.0/0.3)
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $version = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Items contained in the feed
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $items = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Channel data
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $channel = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current item, to iterate over items
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $current_item = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns discovered feeds from web URL
|
||||||
|
* @param string $url HTML page URL
|
||||||
|
* @return array List of discovered feeds
|
||||||
|
*/
|
||||||
|
static public function discoverFeedsFromURL($url)
|
||||||
|
{
|
||||||
|
$feeds = self::discoverFeeds(file_get_contents($url));
|
||||||
|
|
||||||
|
if (empty($feeds))
|
||||||
|
return $feeds;
|
||||||
|
|
||||||
|
foreach ($feeds as &$feed)
|
||||||
|
{
|
||||||
|
$feed['url'] = self::getRealURL($feed['href'], $url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $feeds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a complete URL with scheme and host from an unknown or incomplete URI
|
||||||
|
* @param string $href Incomplete URI
|
||||||
|
* @param string $base_url Base URL used to build a complete URL
|
||||||
|
* @return string Complete URL
|
||||||
|
*/
|
||||||
|
static public function getRealURL($href, $base_url)
|
||||||
|
{
|
||||||
|
$_href = parse_url($href);
|
||||||
|
|
||||||
|
// already an absolute URL
|
||||||
|
if (!empty($_href['scheme']))
|
||||||
|
return $href;
|
||||||
|
|
||||||
|
$_base = parse_url($base_url);
|
||||||
|
|
||||||
|
// protocol-relative URL ie. //bits.wikimedia.org/static/elements/rss.xml
|
||||||
|
if (substr($href, 0, 2) == '//')
|
||||||
|
return $_base['scheme'] . ':' . $href;
|
||||||
|
|
||||||
|
$url = $_base['scheme'] . '://';
|
||||||
|
|
||||||
|
if (!empty($_base['user']))
|
||||||
|
{
|
||||||
|
$url .= $_base['user'];
|
||||||
|
|
||||||
|
if (!empty($_base['pass']))
|
||||||
|
$url .= ':' . $_base['pass'];
|
||||||
|
|
||||||
|
$url .= '@';
|
||||||
|
}
|
||||||
|
|
||||||
|
$url .= $_base['host'];
|
||||||
|
|
||||||
|
// absolute URI
|
||||||
|
if (preg_match('!^/!', $href))
|
||||||
|
return $url . $href;
|
||||||
|
|
||||||
|
$url .= preg_replace('!/[^/]*$!', '/', $_base['path']);
|
||||||
|
|
||||||
|
// query-based URI, eg. ?feed
|
||||||
|
if (!empty($_href['path']))
|
||||||
|
return $url . $href;
|
||||||
|
|
||||||
|
$url .= preg_replace('!^.*/!', '', $_base['path']);
|
||||||
|
|
||||||
|
// relative URI
|
||||||
|
return $url . $href;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discover feeds from an HTML string
|
||||||
|
* @param string $content HTML content
|
||||||
|
* @param boolean $fallback_discover_content If set to TRUE, it will try to find feeds in <a href... links
|
||||||
|
* if no feed is found in <link rel... tags.
|
||||||
|
* @return array List of feeds found
|
||||||
|
*/
|
||||||
|
static public function discoverFeeds($content, $fallback_discover_content = false)
|
||||||
|
{
|
||||||
|
$feeds = array();
|
||||||
|
$possible_rels = array('alternate', 'feed', 'alternate feed');
|
||||||
|
|
||||||
|
// Standard auto discovery
|
||||||
|
if (preg_match_all('/<\s*link\s+(.*?)\/?>/is', $content, $links, PREG_SET_ORDER))
|
||||||
|
{
|
||||||
|
foreach ($links as $link)
|
||||||
|
{
|
||||||
|
$params = self::parseAttributes($link[1]);
|
||||||
|
|
||||||
|
if (empty($params['rel']) || empty($params['type']) || empty($params['href']))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$rel = strtolower($params['rel']);
|
||||||
|
|
||||||
|
if (!in_array($rel, $possible_rels))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$type = strtolower($params['type']);
|
||||||
|
|
||||||
|
if (!in_array($type, self::$mime_types))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$feeds[] = array(
|
||||||
|
'type' => $type,
|
||||||
|
'href' => $params['href'],
|
||||||
|
'title' => isset($params['title']) ? trim(html_entity_decode($params['title'], ENT_COMPAT, '')) : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Discover feed links from page links
|
||||||
|
elseif ($fallback_discover_content && preg_match_all('/<\s*a\s+(.*?)>(.*?)<\/a>/is', $content, $links, PREG_SET_ORDER))
|
||||||
|
{
|
||||||
|
foreach ($links as $link)
|
||||||
|
{
|
||||||
|
$params = self::parseAttributes($link[1]);
|
||||||
|
|
||||||
|
if (empty($params['href']))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!preg_match('/[^\w\d](?:atom|rss|rdf)[^\w\d]/i', $params['href']))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$feeds[] = array(
|
||||||
|
'type' => null,
|
||||||
|
'href' => $params['href'],
|
||||||
|
'title' => html_entity_decode(strip_tags($link[2]), ENT_COMPAT, ''),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $feeds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a valid UNIX timestamp from a RSS/ATOM date, even broken ones
|
||||||
|
* From https://github.com/fguillot/picoFeed/blob/master/lib/PicoFeed/Parser.php
|
||||||
|
* @param string $value Input date, any format
|
||||||
|
* @return int Unix Timestamp
|
||||||
|
*/
|
||||||
|
static public function parseDate($value)
|
||||||
|
{
|
||||||
|
// Format => truncate to this length if not null
|
||||||
|
static $formats = array(
|
||||||
|
DATE_ATOM => null,
|
||||||
|
DATE_RSS => null,
|
||||||
|
DATE_COOKIE => null,
|
||||||
|
DATE_ISO8601 => null,
|
||||||
|
DATE_RFC822 => null,
|
||||||
|
DATE_RFC850 => null,
|
||||||
|
DATE_RFC1036 => null,
|
||||||
|
DATE_RFC1123 => null,
|
||||||
|
DATE_RFC2822 => null,
|
||||||
|
DATE_RFC3339 => null,
|
||||||
|
'D, d M Y H:i:s' => 25,
|
||||||
|
'D, d M Y h:i:s' => 25,
|
||||||
|
'D M d Y H:i:s' => 24,
|
||||||
|
'Y-m-d H:i:s' => 19,
|
||||||
|
'Y-m-d\TH:i:s' => 19,
|
||||||
|
'd/m/Y H:i:s' => 19,
|
||||||
|
'D, d M Y' => 16,
|
||||||
|
'Y-m-d' => 10,
|
||||||
|
'd-m-Y' => 10,
|
||||||
|
'm-d-Y' => 10,
|
||||||
|
'd.m.Y' => 10,
|
||||||
|
'm.d.Y' => 10,
|
||||||
|
'd/m/Y' => 10,
|
||||||
|
'm/d/Y' => 10,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$value) {
|
||||||
|
return time();
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = trim($value);
|
||||||
|
|
||||||
|
foreach ($formats as $format => $length) {
|
||||||
|
$timestamp = self::getValidDate($format, substr($value, 0, $length));
|
||||||
|
if ($timestamp > 0) return $timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return time();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a valid timestamp from a given date format
|
||||||
|
* @param string $format Date format
|
||||||
|
* @param string $value Date string
|
||||||
|
* @return integer Timestamp
|
||||||
|
*/
|
||||||
|
static protected function getValidDate($format, $value)
|
||||||
|
{
|
||||||
|
$date = \DateTime::createFromFormat($format, $value);
|
||||||
|
|
||||||
|
if ($date !== false) {
|
||||||
|
$errors = \DateTime::getLastErrors();
|
||||||
|
if (empty($errors['error_count']) && empty($errors['warning_count'])) return $date->getTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content of an XML tag, without entities
|
||||||
|
* @param string $string Raw XML string
|
||||||
|
* @return string Decoded string
|
||||||
|
*/
|
||||||
|
static protected function getXmlContent($string)
|
||||||
|
{
|
||||||
|
$string = trim($string);
|
||||||
|
$string = preg_replace('/^.*<!\[CDATA\[/is', '', $string);
|
||||||
|
$string = preg_replace('/\]\]>.*$/s', '', $string);
|
||||||
|
$string = str_replace(''', ''', $string);
|
||||||
|
$string = html_entity_decode(self::utf8_encode($string), ENT_QUOTES, 'UTF-8');
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
static protected function utf8_encode($str)
|
||||||
|
{
|
||||||
|
// Check if string is already UTF-8 encoded or not
|
||||||
|
if (!preg_match('//u', $str))
|
||||||
|
{
|
||||||
|
return utf8_encode($str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses attributes from a XML/HTML tag
|
||||||
|
* @param string $str String containing all attributes
|
||||||
|
* @return array List of attributes
|
||||||
|
*/
|
||||||
|
static protected function parseAttributes($str)
|
||||||
|
{
|
||||||
|
$params = array();
|
||||||
|
preg_match_all('/(\w[\w\d]*(?::\w[\w\d]*)*)(?:\s*=\s*(?:([\'"])(.*?)\2|([^>\s\'"]+)))?/i', $str, $_params, PREG_SET_ORDER);
|
||||||
|
|
||||||
|
if (empty($_params))
|
||||||
|
{
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($_params as $_p)
|
||||||
|
{
|
||||||
|
$value = isset($_p[4]) ? trim($_p[4]) : (isset($_p[3]) ? trim($_p[3]) : null);
|
||||||
|
$params[strtolower($_p[1])] = $value ? self::utf8_encode($value) : $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load and parse a feed from an URL
|
||||||
|
* @param string $url Feed URL
|
||||||
|
* @return boolean false if feed parsing or loading failed
|
||||||
|
*/
|
||||||
|
public function load($url)
|
||||||
|
{
|
||||||
|
if (!$this->parse(file_get_contents($url)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!empty($this->items))
|
||||||
|
{
|
||||||
|
foreach ($this->items as &$item)
|
||||||
|
{
|
||||||
|
$item->url = self::getRealURL($item->link, $url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a feed from a string
|
||||||
|
* @param string $content Feed as string
|
||||||
|
* @return boolean false if parsing failed (or string is empty)
|
||||||
|
*/
|
||||||
|
public function parse($content)
|
||||||
|
{
|
||||||
|
$this->format = $this->version = $this->vendor = false;
|
||||||
|
$this->items = array();
|
||||||
|
$this->channel = null;
|
||||||
|
|
||||||
|
if (preg_match('!<feed\s+[^>]*xmlns\s*=\s*["\']?http://www\.w3\.org/2005/Atom["\']?!i', $content))
|
||||||
|
{
|
||||||
|
$this->format = 'atom';
|
||||||
|
$this->version = '1.0';
|
||||||
|
$this->vendor = 'w3c';
|
||||||
|
}
|
||||||
|
elseif (preg_match('!<feed\s+[^>]*version\s*=\s*["\']?0\.3["\']?!i', $content))
|
||||||
|
{
|
||||||
|
$this->format = 'atom';
|
||||||
|
$this->version = '0.3';
|
||||||
|
$this->vendor = 'imc';
|
||||||
|
}
|
||||||
|
// Source: http://web.archive.org/web/20100315092011/http://diveintomark.org/archives/2004/02/04/incompatible-rss
|
||||||
|
elseif (preg_match('!<rdf:RDF\s+[^>]*http://my\.netscape\.com/rdf/simple/0\.9/!i', $content))
|
||||||
|
{
|
||||||
|
$this->format = 'rss';
|
||||||
|
$this->version = '0.90';
|
||||||
|
$this->vendor = 'netscape';
|
||||||
|
}
|
||||||
|
elseif (preg_match('!http://my\.netscape\.com/publish/formats/rss-0\.91\.dtd!i', $content))
|
||||||
|
{
|
||||||
|
$this->format = 'rss';
|
||||||
|
$this->version = '0.91';
|
||||||
|
$this->vendor = 'netscape';
|
||||||
|
}
|
||||||
|
elseif (preg_match('!<rss\s+[^>]*version\s*=\s*["\']?(0\.9[1234]|2\.0)["\']?!i', $content))
|
||||||
|
{
|
||||||
|
$this->format = 'rss';
|
||||||
|
$this->version = '0.91';
|
||||||
|
$this->vendor = 'userland';
|
||||||
|
}
|
||||||
|
elseif (preg_match('!<rdf:RDF\s+[^>]*http://purl\.org/rss/1\.0/!i', $content))
|
||||||
|
{
|
||||||
|
$this->format = 'rss';
|
||||||
|
$this->version = '1.0';
|
||||||
|
$this->vendor = 'rss-dev-wg';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separate items from channel
|
||||||
|
$pos = $end = false;
|
||||||
|
|
||||||
|
if (($items = preg_split('/<\/?(item|entry)(\s+.*?)?>/is', $content, -1, PREG_SPLIT_OFFSET_CAPTURE | PREG_SPLIT_NO_EMPTY))
|
||||||
|
&& !empty($items[1]))
|
||||||
|
{
|
||||||
|
$pos = $items[1][1];
|
||||||
|
$end = $items[count($items) - 2][1] + strlen($items[count($items) - 2][0]);
|
||||||
|
|
||||||
|
unset($items[count($items)-1]);
|
||||||
|
unset($items[0]);
|
||||||
|
|
||||||
|
foreach ($items as $item)
|
||||||
|
{
|
||||||
|
if (trim($item[0]) == '')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$this->items[] = $item[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($items);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($pos)
|
||||||
|
{
|
||||||
|
$start = stripos($content, '<channel');
|
||||||
|
$this->channel = substr($content, ($start === false ? 0 : $start), $pos - $start);
|
||||||
|
|
||||||
|
// Get the start of the channel
|
||||||
|
if (($start = strpos($this->channel, '>')) !== false)
|
||||||
|
{
|
||||||
|
$this->channel = substr($this->channel, $start);
|
||||||
|
}
|
||||||
|
|
||||||
|
$channel_end = strpos($this->channel, '</channel');
|
||||||
|
|
||||||
|
// If the channel ends before the items
|
||||||
|
if ($channel_end !== false)
|
||||||
|
{
|
||||||
|
$this->channel = substr($this->channel, 0, $channel_end);
|
||||||
|
}
|
||||||
|
// If there is still somethin from the channel after the items
|
||||||
|
elseif ($end)
|
||||||
|
{
|
||||||
|
$channel_end = strpos($content, '</channel');
|
||||||
|
$last = substr($content, $end, $channel_end - $end);
|
||||||
|
|
||||||
|
if (($start = strpos($last, '>')) !== false)
|
||||||
|
{
|
||||||
|
$last = substr($last, $start);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->channel .= $last;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->parseChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->items)
|
||||||
|
{
|
||||||
|
$this->parseItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obviously something went wrong
|
||||||
|
if (empty($this->items) && empty($this->channel))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse channel tags into something useful
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function parseChannel()
|
||||||
|
{
|
||||||
|
$channel = new \stdClass;
|
||||||
|
$channel->title = null;
|
||||||
|
$channel->description = null;
|
||||||
|
$channel->link = null;
|
||||||
|
$channel->date = null;
|
||||||
|
$channel->raw = $this->channel;
|
||||||
|
$channel->xml = array();
|
||||||
|
|
||||||
|
preg_match_all('!<\s*([\w\d-]+(?::[\w\d-]+)*)\s*(.*?)/?>(?:(.*?)</\1>)?!is', $this->channel, $tags, PREG_SET_ORDER);
|
||||||
|
|
||||||
|
foreach ($tags as $_tag)
|
||||||
|
{
|
||||||
|
$tag = new \stdClass;
|
||||||
|
$tag->name = $_tag[1];
|
||||||
|
$tag->content = isset($_tag[3]) ? self::getXmlContent($_tag[3]) : null;
|
||||||
|
$tag->attributes = !empty($_tag[2]) ? self::parseAttributes($_tag[2]) : array();
|
||||||
|
$channel->xml[] = $tag;
|
||||||
|
|
||||||
|
$_tag = strtolower($tag->name);
|
||||||
|
|
||||||
|
switch ($_tag)
|
||||||
|
{
|
||||||
|
case 'title':
|
||||||
|
case 'description':
|
||||||
|
$channel->{$_tag} = $tag->content;
|
||||||
|
break;
|
||||||
|
case 'dc:date':
|
||||||
|
case 'pubdate':
|
||||||
|
case 'modified':
|
||||||
|
case 'published':
|
||||||
|
case 'updated':
|
||||||
|
$channel->date = $tag->content;
|
||||||
|
break;
|
||||||
|
case 'link':
|
||||||
|
if (!empty($channel->link))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!empty($tag->attributes['href']))
|
||||||
|
{
|
||||||
|
$channel->link = $tag->attributes['href'];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$channel->link = $tag->content;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the date string to a timestamp
|
||||||
|
$channel->date = self::parseDate($channel->date);
|
||||||
|
|
||||||
|
$this->channel = $channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse feed items into an array of objects
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function parseItems()
|
||||||
|
{
|
||||||
|
foreach ($this->items as $key=>$_item)
|
||||||
|
{
|
||||||
|
$item = new \stdClass;
|
||||||
|
$item->title = null;
|
||||||
|
$item->description = null;
|
||||||
|
$item->link = null;
|
||||||
|
$item->date = null;
|
||||||
|
$item->content = null;
|
||||||
|
$item->raw = $_item;
|
||||||
|
$item->xml = array();
|
||||||
|
|
||||||
|
preg_match_all('!<\s*([\w\d-]+(?::[\w\d-]+)*)\s*(.*?)/?>(?:(.*?)</\1>)?!is', $_item, $tags, PREG_SET_ORDER);
|
||||||
|
|
||||||
|
foreach ($tags as $_tag)
|
||||||
|
{
|
||||||
|
$tag = new \stdClass;
|
||||||
|
$tag->name = $_tag[1];
|
||||||
|
$tag->content = isset($_tag[3]) ? self::getXmlContent($_tag[3]) : null;
|
||||||
|
$tag->attributes = !empty($_tag[2]) ? self::parseAttributes($_tag[2]) : array();
|
||||||
|
$item->xml[] = $tag;
|
||||||
|
|
||||||
|
$_tag = strtolower($tag->name);
|
||||||
|
|
||||||
|
switch ($_tag)
|
||||||
|
{
|
||||||
|
case 'title':
|
||||||
|
case 'description':
|
||||||
|
case 'content':
|
||||||
|
$item->{$_tag} = $tag->content;
|
||||||
|
break;
|
||||||
|
case 'dc:date':
|
||||||
|
case 'pubdate':
|
||||||
|
case 'modified':
|
||||||
|
case 'published':
|
||||||
|
case 'updated':
|
||||||
|
case 'issued':
|
||||||
|
if (!empty($tag->content))
|
||||||
|
$item->date = $tag->content;
|
||||||
|
break;
|
||||||
|
case 'link':
|
||||||
|
if (!empty($item->link))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!empty($tag->attributes['href']))
|
||||||
|
{
|
||||||
|
$item->link = $tag->attributes['href'];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$item->link = $tag->content;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'summary':
|
||||||
|
$item->description = $tag->content;
|
||||||
|
case 'content:encoded':
|
||||||
|
$item->content = $tag->content;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the date string to a timestamp
|
||||||
|
$item->date = self::parseDate($item->date);
|
||||||
|
|
||||||
|
if (is_null($item->description) && !is_null($item->content))
|
||||||
|
$item->description = $item->content;
|
||||||
|
elseif (!is_null($item->description) && is_null($item->content))
|
||||||
|
$item->content = $item->description;
|
||||||
|
|
||||||
|
$this->items[$key] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the channel object
|
||||||
|
* @return object stdClass object containg channel informations
|
||||||
|
*/
|
||||||
|
public function getChannel()
|
||||||
|
{
|
||||||
|
if (!$this->channel)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return $this->channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the array of items
|
||||||
|
* @return array An array of stdClass objects
|
||||||
|
*/
|
||||||
|
public function getItems()
|
||||||
|
{
|
||||||
|
return $this->items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the average publication interval between items.
|
||||||
|
* Useful to know when to check the feed for new stuff.
|
||||||
|
* @return integer Average publication time (in seconds)
|
||||||
|
*/
|
||||||
|
public function getAveragePublicationInterval()
|
||||||
|
{
|
||||||
|
$start = null;
|
||||||
|
|
||||||
|
if (count($this->items) < 1)
|
||||||
|
{
|
||||||
|
return 3600 * 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
$start = $this->items[0]->date;
|
||||||
|
$end = $this->items[count($this->items) - 1]->date;
|
||||||
|
|
||||||
|
$diff = abs($end - $start);
|
||||||
|
return (int) round($diff / count($this->items));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a feed item
|
||||||
|
* @param integer $key Item number, if omitted it will return the next item in the list
|
||||||
|
* @return object stdClass object with informations and raw content of the item
|
||||||
|
*/
|
||||||
|
public function getItem($key = false)
|
||||||
|
{
|
||||||
|
if (!$this->items)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($key === false)
|
||||||
|
{
|
||||||
|
$key = $this->current_item++;
|
||||||
|
|
||||||
|
if ($key > count($this->items))
|
||||||
|
{
|
||||||
|
$this->reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!array_key_exists($key, $this->items))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return $this->items[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the iteration counter for getItem()
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function reset()
|
||||||
|
{
|
||||||
|
$this->current_item = 0;
|
||||||
|
}
|
||||||
|
}
|
312
src/include/lib/KD2/FileInfo.php
Normal file
312
src/include/lib/KD2/FileInfo.php
Normal file
|
@ -0,0 +1,312 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
This file is part of KD2FW -- <http://dev.kd2.org/>
|
||||||
|
|
||||||
|
Copyright (c) 2001-2019 BohwaZ <http://bohwaz.net/>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
KD2FW 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.
|
||||||
|
|
||||||
|
Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace KD2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Various tools to get informations on files
|
||||||
|
*/
|
||||||
|
|
||||||
|
class FileInfo
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Magic numbers, taken from fileinfo package
|
||||||
|
* Every key contains the mimetype, and the value is an array
|
||||||
|
* containing magic numbers
|
||||||
|
* 'image/gif' => ['GIF'] // will match only if the string 'GIF' is found at position 0
|
||||||
|
* 'application/epub+zip' => ["PK\003\004", 30 => 'mimetypeapplication/epub+zip']
|
||||||
|
* // will only match if "PK\003\004" is found at position 0 and
|
||||||
|
* // 'mimetypeapplication/epub+zip' is found at position 30
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
static public $magic_numbers = [
|
||||||
|
// Images
|
||||||
|
'image/gif' => [['GIF87a'], ['GIF89a']],
|
||||||
|
'image/png' => ["\x89PNG"],
|
||||||
|
'image/jpeg'=> ["\xff\xd8\xff"],
|
||||||
|
'image/tiff'=> [["\x49\x49\x2A\x00"], ["\x4D\x4D\x00\x2A"]],
|
||||||
|
'image/bmp' => ['BM'],
|
||||||
|
'image/vnd.adobe.photoshop' => ['8BPS'],
|
||||||
|
'image/x-icon' => ["\000\000\001\000"],
|
||||||
|
'image/xcf' => ['gimp xcf'],
|
||||||
|
'image/svg+xml' => '/^\s*<\?xml.*?\?>\s*<svg/is',
|
||||||
|
|
||||||
|
// Office documents
|
||||||
|
'application/msword' => [
|
||||||
|
["\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1", 546 => 'jbjb'],
|
||||||
|
["\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1", 546 => 'bjbj']
|
||||||
|
],
|
||||||
|
'application/x-msoffice' => ["\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1"],
|
||||||
|
'application/vnd.openxmlformats-officedocument' => ["PK\x03\x04\x14\x00\x06\x00"],
|
||||||
|
'application/pdf' => ['%PDF-'],
|
||||||
|
'application/postscript' => [["\004%"], ['%!PS-Adobe-']],
|
||||||
|
'application/epub+zip' => ["PK\003\004", 30 => 'mimetypeapplication/epub+zip'],
|
||||||
|
|
||||||
|
// Open Office 1.x
|
||||||
|
'application/vnd.sun.xml.writer'
|
||||||
|
=> ["PK\003\004", 26 => "\x8\0\0\0mimetypeapplication/", 50 => 'vnd.sun.xml.writer'],
|
||||||
|
'application/vnd.sun.xml.calc'
|
||||||
|
=> ["PK\003\004", 26 => "\x8\0\0\0mimetypeapplication/", 50 => 'vnd.sun.xml.calc'],
|
||||||
|
'application/vnd.sun.xml.draw'
|
||||||
|
=> ["PK\003\004", 26 => "\x8\0\0\0mimetypeapplication/", 50 => 'vnd.sun.xml.draw'],
|
||||||
|
'application/vnd.sun.xml.impress'
|
||||||
|
=> ["PK\003\004", 26 => "\x8\0\0\0mimetypeapplication/", 50 => 'vnd.sun.xml.impress'],
|
||||||
|
'application/vnd.sun.xml.math'
|
||||||
|
=> ["PK\003\004", 26 => "\x8\0\0\0mimetypeapplication/", 50 => 'vnd.sun.xml.math'],
|
||||||
|
'application/vnd.sun.xml.base'
|
||||||
|
=> ["PK\003\004", 26 => "\x8\0\0\0mimetypeapplication/", 50 => 'vnd.sun.xml.base'],
|
||||||
|
|
||||||
|
// Open Office 2.x
|
||||||
|
'application/vnd.oasis.opendocument.text'
|
||||||
|
=> ["PK\003\004", 26 => "\x8\0\0\0mimetypeapplication/", 50 => 'vnd.oasis.opendocument.text'],
|
||||||
|
'application/vnd.oasis.opendocument.graphics'
|
||||||
|
=> ["PK\003\004", 26 => "\x8\0\0\0mimetypeapplication/", 50 => 'vnd.oasis.opendocument.graphics'],
|
||||||
|
'application/vnd.oasis.opendocument.presentation'
|
||||||
|
=> ["PK\003\004", 26 => "\x8\0\0\0mimetypeapplication/", 50 => 'vnd.oasis.opendocument.presentation'],
|
||||||
|
'application/vnd.oasis.opendocument.spreadsheet'
|
||||||
|
=> ["PK\003\004", 26 => "\x8\0\0\0mimetypeapplication/", 50 => 'vnd.oasis.opendocument.spreadsheet'],
|
||||||
|
'application/vnd.oasis.opendocument.chart'
|
||||||
|
=> ["PK\003\004", 26 => "\x8\0\0\0mimetypeapplication/", 50 => 'vnd.oasis.opendocument.chart'],
|
||||||
|
'application/vnd.oasis.opendocument.formula'
|
||||||
|
=> ["PK\003\004", 26 => "\x8\0\0\0mimetypeapplication/", 50 => 'vnd.oasis.opendocument.formula'],
|
||||||
|
'application/vnd.oasis.opendocument.image'
|
||||||
|
=> ["PK\003\004", 26 => "\x8\0\0\0mimetypeapplication/", 50 => 'vnd.oasis.opendocument.image'],
|
||||||
|
|
||||||
|
// Video/audio
|
||||||
|
'audio/x-ms-asf' => ["\x30\x26\xb2\x75"],
|
||||||
|
'audio/x-wav' => ['RIFF', 8 => 'WAVE'],
|
||||||
|
'video/x-msvideo' => [['RIFF', 8 => 'AVI'], ['RIFX']],
|
||||||
|
'video/quicktime' => [['mdat'], ['moov']],
|
||||||
|
'video/mpeg' => [["\x1B\x3"], ["\x1B\xA"], ["\x1E\x0"]],
|
||||||
|
'audio/mpeg' => [["\xff\xfb"], ['ID3']],
|
||||||
|
'audio/x-pn-realaudio' => ["\x2e\x72\x61\xfd"],
|
||||||
|
'audio/vnd.rn-realaudio'=> ['.RMF'],
|
||||||
|
'audio/x-flac' => ['fLaC'],
|
||||||
|
'application/ogg' => ['OggS'],
|
||||||
|
'audio/midi' => ['MThd'],
|
||||||
|
|
||||||
|
// Text
|
||||||
|
'text/xml' => ['<?xml'],
|
||||||
|
'text/rtf' => ['{\\rtf'],
|
||||||
|
'text/x-php'=> '/<\?php|<\?=/',
|
||||||
|
'text/html' => '/<!DOCTYPE html|<(?:html|head|title|script|style|table|a href=)/i',
|
||||||
|
|
||||||
|
// Others
|
||||||
|
'application/zip' => ["PK\003\004"],
|
||||||
|
'application/x-tar' => [257 => "ustar\0\x06"],
|
||||||
|
'application/x-xz' => ["\xFD7zXZ\x00"],
|
||||||
|
'application/x-7z-compressed' => ["7z\xBC\xAF\x27\x1C"],
|
||||||
|
|
||||||
|
'application/x-gzip' => ["\x1f\x8b"],
|
||||||
|
'application/x-bzip' => ['BZ0'],
|
||||||
|
'application/x-bzip2' => ['BZh'],
|
||||||
|
'application/x-rar' => ['Rar!'],
|
||||||
|
|
||||||
|
'application/x-shockwave-flash' => [['FWS'], ['CWS']],
|
||||||
|
|
||||||
|
'application/x-sqlite3' => ['SQLite format 3'],
|
||||||
|
'text/x-shellscript' => ['#!/'],
|
||||||
|
'application/octet-stream'=>["\177ELF"],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of extensions for recognized MIME-types
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
static public $mime_extensions = [
|
||||||
|
// Images
|
||||||
|
'image/gif' => 'gif',
|
||||||
|
'image/png' => 'png',
|
||||||
|
'image/jpeg'=> 'jpg',
|
||||||
|
'image/tiff'=> 'tif',
|
||||||
|
'image/bmp' => 'bmp',
|
||||||
|
'image/vnd.adobe.photoshop' => 'psd',
|
||||||
|
'image/x-icon' => 'ico',
|
||||||
|
'image/xcf' => 'xcf',
|
||||||
|
'image/svg+xml' => 'svg',
|
||||||
|
|
||||||
|
// Office documents
|
||||||
|
'application/msword' => 'doc',
|
||||||
|
'application/vnd.openxmlformats-officedocument' => 'docx',
|
||||||
|
'application/pdf' => 'pdf',
|
||||||
|
'application/postscript' => 'ps',
|
||||||
|
'application/epub+zip' => 'epub',
|
||||||
|
|
||||||
|
// Open Office 1.x
|
||||||
|
'application/vnd.sun.xml.writer' => 'sxw',
|
||||||
|
'application/vnd.sun.xml.calc' => 'sxc',
|
||||||
|
'application/vnd.sun.xml.draw' => 'sxd',
|
||||||
|
'application/vnd.sun.xml.impress' => 'sxi',
|
||||||
|
'application/vnd.sun.xml.math' => 'sxf',
|
||||||
|
|
||||||
|
// Open Office 2.x
|
||||||
|
'application/vnd.oasis.opendocument.text' => 'odt',
|
||||||
|
'application/vnd.oasis.opendocument.graphics' => 'odg',
|
||||||
|
'application/vnd.oasis.opendocument.presentation'=> 'odp',
|
||||||
|
'application/vnd.oasis.opendocument.spreadsheet'=> 'ods',
|
||||||
|
'application/vnd.oasis.opendocument.chart' => 'odc',
|
||||||
|
'application/vnd.oasis.opendocument.formula' => 'odf',
|
||||||
|
|
||||||
|
// Video/audio
|
||||||
|
'audio/x-ms-asf' => 'asx',
|
||||||
|
'audio/x-wav' => 'wav',
|
||||||
|
'video/x-msvideo' => 'avi',
|
||||||
|
'video/quicktime' => 'mov',
|
||||||
|
'video/mpeg' => 'mpeg',
|
||||||
|
'audio/mpeg' => 'mp3',
|
||||||
|
'audio/x-pn-realaudio' => 'ra',
|
||||||
|
'audio/vnd.rn-realaudio'=> 'ram',
|
||||||
|
'audio/x-flac' => 'flac',
|
||||||
|
'application/ogg' => 'ogg',
|
||||||
|
'audio/midi' => 'mid',
|
||||||
|
|
||||||
|
// Text
|
||||||
|
'text/xml' => 'xml',
|
||||||
|
'text/rtf' => 'rtf',
|
||||||
|
'text/x-php'=> 'php',
|
||||||
|
'text/html' => 'html',
|
||||||
|
|
||||||
|
// Others
|
||||||
|
'application/zip' => 'zip',
|
||||||
|
'application/x-tar' => 'tar',
|
||||||
|
'application/x-xz' => 'xz',
|
||||||
|
'application/x-7z-compressed' => '7z',
|
||||||
|
'application/x-gzip' => 'gz',
|
||||||
|
'application/x-bzip' => 'bz',
|
||||||
|
'application/x-bzip2' => 'bz2',
|
||||||
|
'application/x-rar' => 'rar',
|
||||||
|
|
||||||
|
'application/x-shockwave-flash' => 'swf',
|
||||||
|
|
||||||
|
'application/x-sqlite3' => 'sqlite',
|
||||||
|
'text/x-shellscript' => 'sh',
|
||||||
|
'application/octet-stream' => 'exe',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guesses the MIME type of a file from its content
|
||||||
|
* @param string $bytes First 1024 bytes (or more) of the file
|
||||||
|
* @return mixed Returns a string containing the matched MIME type or FALSE if no MIME type matched
|
||||||
|
*/
|
||||||
|
static public function guessMimeType($bytes)
|
||||||
|
{
|
||||||
|
// try to match for every mimetype
|
||||||
|
foreach (self::$magic_numbers as $type=>$match)
|
||||||
|
{
|
||||||
|
// Regexp match
|
||||||
|
if (is_string($match))
|
||||||
|
{
|
||||||
|
if (self::matchRegexp($match, $bytes))
|
||||||
|
return $type;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple matches possible for one type
|
||||||
|
if (is_array(current($match)))
|
||||||
|
{
|
||||||
|
foreach ($match as $_submatch)
|
||||||
|
{
|
||||||
|
if (self::matchBytes($_submatch, $bytes))
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single match
|
||||||
|
if (self::matchBytes($match, $bytes))
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to match a regular expression against the first bytes of the file
|
||||||
|
* @param string $regexp Regexp to test
|
||||||
|
* @param string $bytes Binary string of first bytes of the file
|
||||||
|
* @return boolean TRUE if regexp matches, or else FALSE
|
||||||
|
*/
|
||||||
|
static protected function matchRegexp($regexp, $bytes)
|
||||||
|
{
|
||||||
|
return preg_match($regexp, $bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to match magic numbers at specified positions
|
||||||
|
* @param array $magic associative array: (byte position) => matching string
|
||||||
|
* @param string $bytes Binary string of first bytes
|
||||||
|
* @return boolean TRUE if magic numbers actually match, or else FALSE
|
||||||
|
*/
|
||||||
|
static protected function matchBytes($magic, $bytes)
|
||||||
|
{
|
||||||
|
$match = 0;
|
||||||
|
$max = strlen($bytes);
|
||||||
|
|
||||||
|
// Try to match every magic number for this mimetype
|
||||||
|
foreach ($magic as $pos=>$v)
|
||||||
|
{
|
||||||
|
// Content is too short to try matching this mimetype
|
||||||
|
if ($pos > $max)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$len = strlen($v);
|
||||||
|
|
||||||
|
// No match: skip to next mimetype
|
||||||
|
if (substr($bytes, $pos, $len) !== $v)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a file extension from its MIME-type
|
||||||
|
* @param string $type MIME-type, eg. audio/flac
|
||||||
|
* @return string extension, eg. flac
|
||||||
|
*/
|
||||||
|
static public function getFileExtensionFromMimeType($type)
|
||||||
|
{
|
||||||
|
foreach (self::$mime_extensions as $mime=>$ext)
|
||||||
|
{
|
||||||
|
if ($mime === $type)
|
||||||
|
return $ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function getMimeTypeFromFileExtension($extension)
|
||||||
|
{
|
||||||
|
foreach (self::$mime_extensions as $mime=>$ext)
|
||||||
|
{
|
||||||
|
if ($extension === $ext)
|
||||||
|
return $mime;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
632
src/include/lib/KD2/Form.php
Normal file
632
src/include/lib/KD2/Form.php
Normal file
|
@ -0,0 +1,632 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
This file is part of KD2FW -- <http://dev.kd2.org/>
|
||||||
|
|
||||||
|
Copyright (c) 2001-2019 BohwaZ <http://bohwaz.net/>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
KD2FW 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.
|
||||||
|
|
||||||
|
Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace KD2;
|
||||||
|
|
||||||
|
use KD2\Security;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form management helper
|
||||||
|
* - CSRF protection
|
||||||
|
* - validate form fields
|
||||||
|
* - return form fields
|
||||||
|
*/
|
||||||
|
class Form
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Custom validation rules
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
static protected $custom_validation_rules = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Secret used for tokens
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
static protected $token_secret;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the secret key used to hash and check the CSRF tokens
|
||||||
|
* @param string $secret Whatever secret you may like, must be the same for all the user session
|
||||||
|
* @return boolean true
|
||||||
|
*/
|
||||||
|
static public function tokenSetSecret($secret)
|
||||||
|
{
|
||||||
|
self::$token_secret = $secret;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a single use token and return the value
|
||||||
|
* The token will be HMAC signed and you can use it directly in a HTML form
|
||||||
|
* @param string $action An action description, if NULL then REQUEST_URI will be used
|
||||||
|
* @param integer $expire Number of hours before the hash will expire
|
||||||
|
* @return string HMAC signed token
|
||||||
|
*/
|
||||||
|
static public function tokenGenerate($action = null, $expire = 5)
|
||||||
|
{
|
||||||
|
if (is_null(self::$token_secret)) {
|
||||||
|
throw new \RuntimeException('No CSRF token secret has been set.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_secret = $_COOKIE['__c'] ?? null;
|
||||||
|
|
||||||
|
if (null === $user_secret) {
|
||||||
|
if (headers_sent()) {
|
||||||
|
throw new \RuntimeException('Headers have already been sent, cannot generate a token');
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_secret = bin2hex(random_bytes(10));
|
||||||
|
|
||||||
|
// Store user secret in a cookie
|
||||||
|
setcookie('__c', $user_secret, [
|
||||||
|
'expires' => 0,
|
||||||
|
'path' => '/',
|
||||||
|
'secure' => !empty($_SERVER['HTTPS']) ? true : false,
|
||||||
|
'httponly' => true,
|
||||||
|
'samesite' => 'Strict',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$action = self::tokenAction($action);
|
||||||
|
|
||||||
|
$random = random_int(0, PHP_INT_MAX);
|
||||||
|
$expire = floor(time() / 3600) + $expire;
|
||||||
|
$value = $expire . $random . $action;
|
||||||
|
|
||||||
|
|
||||||
|
$hash = hash_hmac('sha256', $expire . $random . $action, self::$token_secret . sha1($user_secret));
|
||||||
|
|
||||||
|
return $hash . '/' . dechex($expire) . '/' . dechex($random);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks a CSRF token
|
||||||
|
* @param string $action An action description, if NULL then REQUEST_URI will be used
|
||||||
|
* @param string $value User supplied value, if NULL then $_POST[automatic name] will be used
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
static public function tokenCheck($action = null, $value = null)
|
||||||
|
{
|
||||||
|
$user_secret = $_COOKIE['__c'] ?? null;
|
||||||
|
|
||||||
|
if (!$user_secret) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$action = self::tokenAction($action);
|
||||||
|
|
||||||
|
if (is_null($value))
|
||||||
|
{
|
||||||
|
$name = self::tokenFieldName($action);
|
||||||
|
|
||||||
|
if (empty($_POST[$name]))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $_POST[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = explode('/', $value, 3);
|
||||||
|
|
||||||
|
if (count($value) != 3)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_hash = $value[0];
|
||||||
|
$expire = hexdec($value[1]);
|
||||||
|
$random = hexdec($value[2]);
|
||||||
|
|
||||||
|
// Expired token
|
||||||
|
if ($expire < ceil(time() / 3600))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hash = hash_hmac('sha256', $expire . $random . $action, self::$token_secret . sha1($user_secret));
|
||||||
|
|
||||||
|
return hash_equals($hash, $user_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a random field name for the current token action
|
||||||
|
* @param string $action An action description, if NULL then REQUEST_URI will be used
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
static public function tokenFieldName($action = null)
|
||||||
|
{
|
||||||
|
$action = self::tokenAction($action);
|
||||||
|
return 'ct_' . sha1($action . $_SERVER['DOCUMENT_ROOT'] . $_SERVER['SERVER_NAME']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the supplied action name or if it is NULL, then the REQUEST_URI
|
||||||
|
* @param string $action
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
static protected function tokenAction($action = null)
|
||||||
|
{
|
||||||
|
// Default action, will work as long as the check is on the same URI as the generation
|
||||||
|
if (is_null($action) && !empty($_SERVER['REQUEST_URI']))
|
||||||
|
{
|
||||||
|
$url = parse_url($_SERVER['REQUEST_URI']);
|
||||||
|
|
||||||
|
if (!empty($url['path']))
|
||||||
|
{
|
||||||
|
$action = $url['path'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns HTML code to embed a CSRF token in a form
|
||||||
|
* @param string $action An action description, if NULL then REQUEST_URI will be used
|
||||||
|
* @return string HTML <input type="hidden" /> element
|
||||||
|
*/
|
||||||
|
static public function tokenHTML($action = null)
|
||||||
|
{
|
||||||
|
return '<input type="hidden" name="' . self::tokenFieldName($action) . '" value="' . self::tokenGenerate($action) . '" />';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns TRUE if the form has this key and it's not NULL
|
||||||
|
* @param string $key Key to find in the form
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
static public function has($key)
|
||||||
|
{
|
||||||
|
return isset($_POST[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses rules for form validation
|
||||||
|
* @param string $str Rule description
|
||||||
|
* @return array List of rules with parameters
|
||||||
|
*/
|
||||||
|
static protected function parseRules($str)
|
||||||
|
{
|
||||||
|
if (false !== strpos($str, '|')) {
|
||||||
|
$a = '\|';
|
||||||
|
$b = ',';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$a = ',';
|
||||||
|
$b = ':';
|
||||||
|
}
|
||||||
|
|
||||||
|
$str = preg_split('/(?<!\\\\)' . $a . '/', $str);
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
foreach ($str as $rule) {
|
||||||
|
$name = strtok($rule, ':');
|
||||||
|
$rules[$name] = [];
|
||||||
|
|
||||||
|
while (($param = strtok($b)) !== false) {
|
||||||
|
$rules[$name][] = $param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strtok('');
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value for a form field, or NULL
|
||||||
|
*
|
||||||
|
* @param string $key Field name
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
static public function get($field)
|
||||||
|
{
|
||||||
|
if (is_array($field))
|
||||||
|
{
|
||||||
|
$out = new \stdClass;
|
||||||
|
|
||||||
|
foreach ($field as $key => $value)
|
||||||
|
{
|
||||||
|
$name = is_int($key) ? $value : $key;
|
||||||
|
$out->$name = self::get($name);
|
||||||
|
|
||||||
|
if (!is_int($key))
|
||||||
|
{
|
||||||
|
$rules = self::parseRules($value);
|
||||||
|
|
||||||
|
foreach ($rules as $rule => $params)
|
||||||
|
{
|
||||||
|
$out->$name = self::filterField($out->$name, $rule, $params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isset($_POST[$field]) ? $_POST[$field] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
static public function filterField($value, $filter, array $params = [])
|
||||||
|
{
|
||||||
|
switch ($filter)
|
||||||
|
{
|
||||||
|
case 'date':
|
||||||
|
return new \DateTime($value);
|
||||||
|
case 'date_format':
|
||||||
|
return \DateTime::createFromFormat($params[0], $value);
|
||||||
|
case 'int':
|
||||||
|
case 'integer':
|
||||||
|
return (int) $value;
|
||||||
|
case 'bool':
|
||||||
|
case 'boolean':
|
||||||
|
return (bool) $value;
|
||||||
|
case 'string':
|
||||||
|
return trim($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a custom validation rule
|
||||||
|
*
|
||||||
|
* @param string $name Rule name
|
||||||
|
* @param Callable $callback Callback (must return a boolean)
|
||||||
|
* @return void
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
static public function registerValidationRule($name, Callable $callback)
|
||||||
|
{
|
||||||
|
self::$custom_validation_rules[$name] = $callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check a form field against a rule
|
||||||
|
*
|
||||||
|
* @param string $key Field name
|
||||||
|
* @param string $rule_name Rule name
|
||||||
|
* @param Array $params Parameters of the rule
|
||||||
|
* @param Array $source Source of the field data
|
||||||
|
* @param Array $rules Complete list of rules
|
||||||
|
* @return boolean
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
static public function validateRule($key, $rule_name, Array $params = [], Array $source = null, Array $rules = [])
|
||||||
|
{
|
||||||
|
$value = isset($source[$key]) ? $source[$key] : null;
|
||||||
|
|
||||||
|
switch ($rule_name)
|
||||||
|
{
|
||||||
|
case 'required':
|
||||||
|
if (isset($rules['file']))
|
||||||
|
{
|
||||||
|
// Checked in 'file' rule
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
elseif (is_array($value) || $value instanceof \Countable)
|
||||||
|
{
|
||||||
|
return count($value) > 0;
|
||||||
|
}
|
||||||
|
elseif (is_string($value))
|
||||||
|
{
|
||||||
|
return trim($value) !== '';
|
||||||
|
}
|
||||||
|
return !is_null($value);
|
||||||
|
case 'required_with':
|
||||||
|
$required = false;
|
||||||
|
|
||||||
|
foreach ($params as $condition)
|
||||||
|
{
|
||||||
|
if (isset($source[$condition]))
|
||||||
|
{
|
||||||
|
$required = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $required ? self::validateRule($key, 'required', $params, $source) : true;
|
||||||
|
case 'required_with_all':
|
||||||
|
$required = 0;
|
||||||
|
|
||||||
|
foreach ($params as $condition)
|
||||||
|
{
|
||||||
|
if (isset($source[$condition]))
|
||||||
|
{
|
||||||
|
$required++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $required == count($params) ? self::validateRule($key, 'required', $params, $source) : true;
|
||||||
|
case 'required_without':
|
||||||
|
$required = false;
|
||||||
|
|
||||||
|
foreach ($params as $condition)
|
||||||
|
{
|
||||||
|
if (!isset($source[$condition]))
|
||||||
|
{
|
||||||
|
$required = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $required ? self::validateRule($key, 'required', $params, $source) : true;
|
||||||
|
case 'required_without_all':
|
||||||
|
$required = 0;
|
||||||
|
|
||||||
|
foreach ($params as $condition)
|
||||||
|
{
|
||||||
|
if (!isset($source[$condition]))
|
||||||
|
{
|
||||||
|
$required++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $required == count($params) ? self::validateRule($key, 'required', $params, $source) : true;
|
||||||
|
case 'required_if':
|
||||||
|
$required = false;
|
||||||
|
$if_value = isset($source[$params[0]]) ? $source[$params[0]] : null;
|
||||||
|
|
||||||
|
for ($i = 1; $i < count($params); $i++)
|
||||||
|
{
|
||||||
|
if ($params[$i] == $if_value)
|
||||||
|
{
|
||||||
|
$required = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $required ? self::validateRule($key, 'required', $params, $source) : true;
|
||||||
|
case 'required_unless':
|
||||||
|
$required = true;
|
||||||
|
$if_value = isset($source[$params[0]]) ? $source[$params[0]] : null;
|
||||||
|
|
||||||
|
for ($i = 1; $i < count($params); $i++)
|
||||||
|
{
|
||||||
|
if ($params[$i] == $if_value)
|
||||||
|
{
|
||||||
|
$required = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $required ? self::validateRule($key, 'required', $params, $source) : true;
|
||||||
|
case 'absent':
|
||||||
|
return $value === null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore rules for empty fields, except 'required*'
|
||||||
|
if ($rule_name != 'file' && ($value === null || (is_string($value) && trim($value) === '')))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($rule_name)
|
||||||
|
{
|
||||||
|
case 'file':
|
||||||
|
if (!isset($_FILES[$key]) && isset($rules['required']))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
elseif (!isset($_FILES[$key]))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($value = $_FILES[$key]) && !empty($value['size']) && !empty($value['tmp_name']) && empty($value['error']);
|
||||||
|
case 'active_url':
|
||||||
|
$url = parse_url($value);
|
||||||
|
return isset($url['host']) && strlen($url['host']) && (checkdnsrr($url['host'], 'A') || checkdnsrr($url['host'], 'AAAA'));
|
||||||
|
case 'alpha':
|
||||||
|
return preg_match('/^[\pL\pM]+$/u', $value);
|
||||||
|
case 'alpha_dash':
|
||||||
|
return preg_match('/^[\pL\pM\pN_-]+$/u', $value);
|
||||||
|
case 'alpha_num':
|
||||||
|
return preg_match('/^[\pL\pM\pN]+$/u', $value);
|
||||||
|
case 'array':
|
||||||
|
return is_array($value);
|
||||||
|
case 'between':
|
||||||
|
return isset($params[0]) && isset($params[1]) && $value >= $params[0] && $value <= $params[1];
|
||||||
|
case 'boolean':
|
||||||
|
case 'bool':
|
||||||
|
return ($value == 0 || $value == 1);
|
||||||
|
case 'color':
|
||||||
|
return preg_match('/^#?[a-f0-9]{6}$/', $value);
|
||||||
|
case 'confirmed':
|
||||||
|
$key_c = $key . '_confirmed';
|
||||||
|
return isset($source[$key_c]) && $value == $source[$key_c];
|
||||||
|
case 'date':
|
||||||
|
return is_object($value) ? $value instanceof \DateTimeInterface : (bool) strtotime($value);
|
||||||
|
case 'date_format':
|
||||||
|
$date = date_parse_from_format($params[0], $value);
|
||||||
|
return $date['warning_count'] === 0 && $date['error_count'] === 0;
|
||||||
|
case 'different':
|
||||||
|
return isset($params[0]) && isset($source[$params[0]]) && $value != $source[$params[0]];
|
||||||
|
case 'digits':
|
||||||
|
return is_numeric($value) && strlen((string) $value) == $params[0];
|
||||||
|
case 'digits_between':
|
||||||
|
$len = strlen((string) $value);
|
||||||
|
return is_numeric($value) && $len >= $params[0] && $len <= $params[0];
|
||||||
|
case 'email':
|
||||||
|
// Compatibility with IDN domains
|
||||||
|
if (function_exists('idn_to_ascii'))
|
||||||
|
{
|
||||||
|
$host = substr($value, strpos($value, '@') + 1);
|
||||||
|
$host = @idn_to_ascii($host); // Silence errors because of PHP 7.2 http://php.net/manual/en/function.idn-to-ascii.php
|
||||||
|
$value = substr($value, 0, strpos($value, '@')+1) . $host;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
|
||||||
|
case 'gt':
|
||||||
|
return isset($params[0]) && isset($source[$params[0]]) && $value > $source[$params[0]];
|
||||||
|
case 'gte':
|
||||||
|
return isset($params[0]) && isset($source[$params[0]]) && $value >= $source[$params[0]];
|
||||||
|
case 'in':
|
||||||
|
return in_array($value, $params);
|
||||||
|
case 'in_array':
|
||||||
|
$field = isset($params[0]) && isset($source[$params[0]]) ? $source[$params[0]] : null;
|
||||||
|
return $field && is_array($field) && in_array($value, $field);
|
||||||
|
case 'integer':
|
||||||
|
case 'int':
|
||||||
|
return is_int($value);
|
||||||
|
case 'ip':
|
||||||
|
return filter_var($value, FILTER_VALIDATE_IP) !== false;
|
||||||
|
case 'json':
|
||||||
|
return json_decode($value) !== null;
|
||||||
|
case 'lt':
|
||||||
|
return isset($params[0]) && isset($source[$params[0]]) && $value < $source[$params[0]];
|
||||||
|
case 'lte':
|
||||||
|
return isset($params[0]) && isset($source[$params[0]]) && $value <= $source[$params[0]];
|
||||||
|
case 'max':
|
||||||
|
$size = is_array($value) ? count($value) : (isset($rules['string']) ? strlen($value) : $value);
|
||||||
|
return isset($params[0]) && $size <= $params[0];
|
||||||
|
case 'min':
|
||||||
|
$size = is_array($value) ? count($value) : (isset($rules['string']) ? strlen($value) : $value);
|
||||||
|
return isset($params[0]) && $size >= $params[0];
|
||||||
|
case 'money':
|
||||||
|
return preg_match('/^-?(\d+)(?:[.,](\d{1,2}))?$/', $value, $match) && ($match[1]*100 + $match[2]) >= 0;
|
||||||
|
case 'not_in':
|
||||||
|
return !in_array($value, $params);
|
||||||
|
case 'numeric':
|
||||||
|
return is_numeric($value);
|
||||||
|
case 'present':
|
||||||
|
return isset($source[$key]);
|
||||||
|
case 'regex':
|
||||||
|
return isset($params[0]) && preg_match($params[0], $value);
|
||||||
|
case 'same':
|
||||||
|
return isset($params[0]) && isset($source[$params[0]]) && $source[$params[0]] == $value;
|
||||||
|
case 'size':
|
||||||
|
$size = is_array($value) ? count($value) : (is_numeric($value) ? $value : strlen($value));
|
||||||
|
return isset($params[0]) && $size == (int) $params[0];
|
||||||
|
case 'string':
|
||||||
|
return is_string($value);
|
||||||
|
case 'timezone':
|
||||||
|
try {
|
||||||
|
new \DateTimeZone($value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (\Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case 'url':
|
||||||
|
return filter_var($value, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED) !== false;
|
||||||
|
// Dates
|
||||||
|
case 'after':
|
||||||
|
return isset($params[0]) && ($date1 = strtotime($value)) && ($date2 = strtotime($params[0])) && $date1 > $date2;
|
||||||
|
case 'after_or_equal':
|
||||||
|
return isset($params[0]) && ($date1 = strtotime($value)) && ($date2 = strtotime($params[0])) && $date1 >= $date2;
|
||||||
|
case 'before':
|
||||||
|
return isset($params[0]) && ($date1 = strtotime($value)) && ($date2 = strtotime($params[0])) && $date1 < $date2;
|
||||||
|
case 'before_or_equal':
|
||||||
|
return isset($params[0]) && ($date1 = strtotime($value)) && ($date2 = strtotime($params[0])) && $date1 <= $date2;
|
||||||
|
default:
|
||||||
|
if (isset(self::$custom_validation_rules[$rule_name]))
|
||||||
|
{
|
||||||
|
return call_user_func_array(self::$custom_validation_rules[$rule_name], [$key, $params, $value, $source]);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \UnexpectedValueException('Invalid rule name: ' . $rule_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate but add CSRF token check to that
|
||||||
|
*
|
||||||
|
* @param string $token_action CSRF token action name
|
||||||
|
* @param Array $all_rules List of rules, eg. 'login' => 'required|string'
|
||||||
|
* @param Array &$errors List of errors encountered
|
||||||
|
* @return boolean
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
static public function check($token_action, Array $all_rules, Array &$errors = [])
|
||||||
|
{
|
||||||
|
if (!self::tokenCheck($token_action))
|
||||||
|
{
|
||||||
|
$errors[] = ['rule' => 'csrf'];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::validate($all_rules, $errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the current form against a set of rules
|
||||||
|
*
|
||||||
|
* Most rules from Laravel are implemented.
|
||||||
|
*
|
||||||
|
* @link https://laravel.com/docs/5.4/validation#available-validation-rules
|
||||||
|
* @param Array $all_rules List of rules, eg. 'login' => 'required|string'
|
||||||
|
* @param Array &$errors Filled with list of errors encountered
|
||||||
|
* @param Array $source Source of form data, if left empty or NULL,
|
||||||
|
* $_POST will be used
|
||||||
|
* @return boolean
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
static public function validate(Array $all_rules, Array &$errors = null, Array $source = null)
|
||||||
|
{
|
||||||
|
if (is_null($errors))
|
||||||
|
{
|
||||||
|
$errors = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($source))
|
||||||
|
{
|
||||||
|
$source = $_POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($all_rules as $key => $rules)
|
||||||
|
{
|
||||||
|
if ($return = self::validateField($key, $rules, $source)) {
|
||||||
|
$errors[] = $return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count($errors) == 0 ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate a field against a list of rules
|
||||||
|
* @param string $key Name of the field
|
||||||
|
* @param array|string $rules List of rules, either as an associative array of type rule_name => [...parameters] or a string
|
||||||
|
* @param array $source Source array of user data (eg. $_POST)
|
||||||
|
* @return array Array containing the first error encountered for the field (as an array), or NULL if no error was found
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
static public function validateField(string $key, $rules, array $source): ?array
|
||||||
|
{
|
||||||
|
$rules = is_array($rules) ? $rules : self::parseRules($rules);
|
||||||
|
|
||||||
|
foreach ($rules as $name => $params)
|
||||||
|
{
|
||||||
|
if (!self::validateRule($key, $name, $params, $source, $rules))
|
||||||
|
{
|
||||||
|
return ['name' => $key, 'rule' => $name, 'params' => $params];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
137
src/include/lib/KD2/Fossil.php
Normal file
137
src/include/lib/KD2/Fossil.php
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace KD2;
|
||||||
|
|
||||||
|
class Fossil
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Length for SHA1
|
||||||
|
*/
|
||||||
|
const HNAME_MIN = 40;
|
||||||
|
|
||||||
|
protected $db;
|
||||||
|
protected $url;
|
||||||
|
|
||||||
|
public function __construct($repo_file, $url)
|
||||||
|
{
|
||||||
|
$this->db = new DB_SQLite3($repo_file, SQLITE3_OPEN_READONLY);
|
||||||
|
$this->db->createFunction('repo_url', [$this, 'getURL']);
|
||||||
|
$this->url = $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getURL($uri = '')
|
||||||
|
{
|
||||||
|
return $this->url . $uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listUnversioned()
|
||||||
|
{
|
||||||
|
return $this->db->getGrouped('SELECT uvid, name, sz AS size, mtime, hash, repo_url(\'uv/\' || name) AS url
|
||||||
|
FROM unversioned WHERE hash IS NOT NULL ORDER BY mtime DESC;');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTicketsStatus()
|
||||||
|
{
|
||||||
|
return $this->db->get('SELECT DISTINCT status FROM ticket;');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTicketsTypes()
|
||||||
|
{
|
||||||
|
return $this->db->get('SELECT DISTINCT type FROM ticket;');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listTickets(array $filters = [])
|
||||||
|
{
|
||||||
|
$query = 'SELECT *, repo_url(\'tktview?name=\' || substr(tkt_uuid, 1, 10)) AS url FROM ticket WHERE 1';
|
||||||
|
$args = [];
|
||||||
|
|
||||||
|
foreach ($filters as $field => $value)
|
||||||
|
{
|
||||||
|
$query .= ' AND ' . $field . ' = ?';
|
||||||
|
$args[] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query .= ' ORDER BY tkt_mtime DESC;';
|
||||||
|
|
||||||
|
return $this->db->get($query, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bundlePreview($file, $force = false)
|
||||||
|
{
|
||||||
|
if (!is_readable($file))
|
||||||
|
{
|
||||||
|
throw new \RuntimeException('Cannot read file: ' . $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->db->preparedQuery('ATTACH ? AS b1;', [$file]);
|
||||||
|
$a = $this->db->prepare('SELECT bcname, bcvalue FROM b1.bconfig LIMIT 1;');
|
||||||
|
$b = $this->db->prepare('SELECT blobid, uuid, sz, delta, notes, data FROM b1.bblob;');
|
||||||
|
|
||||||
|
if (!$a || !$b)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->db->exec('DETACH b1;');
|
||||||
|
throw new \RuntimeException('Not a valid bundle file: ' . $e->getMessage(), 0, $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only import a bundle that was generated from a repo with the same
|
||||||
|
** project code, unless the --force flag is true */
|
||||||
|
|
||||||
|
if (!$force)
|
||||||
|
{
|
||||||
|
$exists = $this->db->firstColumn('SELECT 1 FROM config, bconfig
|
||||||
|
WHERE config.name = \'project-code\'
|
||||||
|
AND bconfig.bcname = \'project-code\'
|
||||||
|
AND config.value = bconfig.bcvalue;');
|
||||||
|
|
||||||
|
if (!$exists)
|
||||||
|
{
|
||||||
|
$this->db->exec('DETACH b1;');
|
||||||
|
throw new \RuntimeException('project-code in the bundle does not match the repository project code.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the bundle contains deltas with a basis that is external to the
|
||||||
|
** bundle and those external basis files are missing from the local
|
||||||
|
** repo, then the delta encodings cannot be decoded and the bundle cannot
|
||||||
|
** be extracted. */
|
||||||
|
$missing_deltas = $this->db->firstColumn('SELECT group_concat(substr(delta,1,10), \' \') FROM bblob WHERE typeof(delta) = \'text\' AND length(delta) >= ? AND NOT EXISTS(SELECT 1 FROM blob WHERE uuid = bblob.delta)', self::HNAME_MIN);
|
||||||
|
|
||||||
|
if ($missing_deltas)
|
||||||
|
{
|
||||||
|
$this->db->exec('DETACH b1;');
|
||||||
|
throw new \RuntimeException('delta basis artifacts not found in repository: ' . $missing_deltas);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->begin();
|
||||||
|
|
||||||
|
$this->db->exec('CREATE TEMP TABLE bix(
|
||||||
|
blobid INTEGER PRIMARY KEY,
|
||||||
|
delta INTEGER
|
||||||
|
);
|
||||||
|
CREATE INDEX bixdelta ON bix(delta);
|
||||||
|
INSERT INTO bix(blobid,delta)
|
||||||
|
SELECT blobid,
|
||||||
|
CASE WHEN typeof(delta)==\'integer\'
|
||||||
|
THEN delta ELSE 0 END
|
||||||
|
FROM bblob
|
||||||
|
WHERE NOT EXISTS(SELECT 1 FROM blob WHERE uuid=bblob.uuid AND size>=0);
|
||||||
|
CREATE TEMP TABLE got(rid INTEGER PRIMARY KEY ON CONFLICT IGNORE);');
|
||||||
|
|
||||||
|
/*
|
||||||
|
manifest_crosslink_begin();
|
||||||
|
bundle_import_elements(0, 0, isPriv);
|
||||||
|
manifest_crosslink_end(0);
|
||||||
|
describe_artifacts_to_stdout("IN got", "Imported content:");
|
||||||
|
*/
|
||||||
|
|
||||||
|
$this->db->commit();
|
||||||
|
|
||||||
|
// gzuncompress on each delta
|
||||||
|
|
||||||
|
$this->db->exec('DETACH b1;');
|
||||||
|
}
|
||||||
|
}
|
444
src/include/lib/KD2/FossilInstaller.php
Normal file
444
src/include/lib/KD2/FossilInstaller.php
Normal file
|
@ -0,0 +1,444 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace KD2;
|
||||||
|
|
||||||
|
use KD2\HTTP;
|
||||||
|
use KD2\Security;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FossilInstaller
|
||||||
|
*
|
||||||
|
* This is useful to fetch and install .tar.gz (or .zip) updates from a Fossil repository
|
||||||
|
* using the Unversioned files feature.
|
||||||
|
*
|
||||||
|
* This also implements PGP signature verification and can display a summary of changed to the user.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 BohwaZ <https://bohwaz.net/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
class FossilInstaller
|
||||||
|
{
|
||||||
|
const DEFAULT_REGEXP = '/app-(?P<version>.*)\.tar\.gz/';
|
||||||
|
|
||||||
|
protected array $releases;
|
||||||
|
protected string $app_path;
|
||||||
|
protected string $tmp_path;
|
||||||
|
protected string $fossil_url;
|
||||||
|
protected string $release_name_regexp;
|
||||||
|
protected array $ignored_paths = [];
|
||||||
|
protected string $gpg_pubkey_file;
|
||||||
|
|
||||||
|
public function __construct(string $fossil_repo_url, string $app_path, string $tmp_path, ?string $release_name_regexp = null)
|
||||||
|
{
|
||||||
|
$this->fossil_url = $fossil_repo_url;
|
||||||
|
$this->app_path = $app_path;
|
||||||
|
$this->tmp_path = $tmp_path;
|
||||||
|
$this->release_name_regexp = $release_name_regexp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct()
|
||||||
|
{
|
||||||
|
$this->prune();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPublicKeyFile(string $file)
|
||||||
|
{
|
||||||
|
$this->gpg_pubkey_file = $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignore some paths during upgrade
|
||||||
|
* @param string $path Paths are relative to the installation directory
|
||||||
|
*/
|
||||||
|
public function addIgnoredPath(string $path)
|
||||||
|
{
|
||||||
|
$this->ignored_paths[] = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listReleases(): array
|
||||||
|
{
|
||||||
|
if (isset($this->releases)) {
|
||||||
|
return $this->releases;
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = (new HTTP)->GET($this->fossil_url . 'juvlist');
|
||||||
|
|
||||||
|
if (!$list) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$list = json_decode($list);
|
||||||
|
|
||||||
|
if (!$list) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->releases = [];
|
||||||
|
|
||||||
|
foreach ($list as $item) {
|
||||||
|
if (!isset($item->name, $item->hash, $item->size, $item->mtime)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preg_match($this->release_name_regexp, $item->name, $match)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list(, $version) = $match;
|
||||||
|
|
||||||
|
$item->signed = false;
|
||||||
|
$item->stable = preg_match('/alpha|dev|rc|beta/', $version) ? false : true;
|
||||||
|
$this->releases[$version] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add signed information
|
||||||
|
foreach ($list as $item) {
|
||||||
|
if (substr($item->name, -4) !== '.asc') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = substr($item->name, 0, -4);
|
||||||
|
|
||||||
|
foreach ($this->releases as &$r) {
|
||||||
|
if ($r->name == $name) {
|
||||||
|
$r->signed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($r);
|
||||||
|
|
||||||
|
return $this->releases;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function latest(bool $stable_only = true): ?string
|
||||||
|
{
|
||||||
|
$releases = $this->listReleases();
|
||||||
|
|
||||||
|
$latest = null;
|
||||||
|
|
||||||
|
foreach ($releases as $version => $r) {
|
||||||
|
if ($stable_only && !$r->stable) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$latest || version_compare($version, $latest, '>')) {
|
||||||
|
$latest = $version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $latest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function download(string $version): string
|
||||||
|
{
|
||||||
|
if (!isset($this->releases[$version])) {
|
||||||
|
throw new \InvalidArgumentException('Unknown release');
|
||||||
|
}
|
||||||
|
|
||||||
|
$release = $this->releases[$version];
|
||||||
|
|
||||||
|
$url = sprintf('%suv/%s', $this->fossil_url, $release->name);
|
||||||
|
$tmpfile = $this->_getTempFilePath($version);
|
||||||
|
$r = (new HTTP)->GET($url);
|
||||||
|
|
||||||
|
if (!$r->fail && $r->body) {
|
||||||
|
file_put_contents($tmpfile, $r->body);
|
||||||
|
touch($tmpfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_exists($tmpfile)) {
|
||||||
|
throw new \RuntimeException('Error while downloading file');
|
||||||
|
}
|
||||||
|
|
||||||
|
$can_check_hash = in_array('sha3-256', hash_algos());
|
||||||
|
|
||||||
|
if ($can_check_hash && !hash_equals(hash_file('sha3-256', $tmpfile), $release->hash)) {
|
||||||
|
@unlink($tmpfile);
|
||||||
|
throw new \RuntimeException('Error while downloading file: invalid hash');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tmpfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _getTempFilePath(string $version): string
|
||||||
|
{
|
||||||
|
return $this->tmp_path . '/tmp-release-' . sha1($version) . '.tar.gz';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verify(string $version): ?bool
|
||||||
|
{
|
||||||
|
if (!isset($this->releases[$version])) {
|
||||||
|
throw new \InvalidArgumentException('Unknown release');
|
||||||
|
}
|
||||||
|
|
||||||
|
$tmpfile = $this->_getTempFilePath($version);
|
||||||
|
|
||||||
|
if (!file_exists($tmpfile)) {
|
||||||
|
throw new \LogicException('This release has not been downloaded yet');
|
||||||
|
}
|
||||||
|
|
||||||
|
$release = $this->releases[$version];
|
||||||
|
|
||||||
|
$can_check_hash = in_array('sha3-256', hash_algos());
|
||||||
|
|
||||||
|
if ($can_check_hash && !hash_equals(hash_file('sha3-256', $tmpfile), $release->hash)) {
|
||||||
|
@unlink($tmpfile);
|
||||||
|
throw new \RuntimeException('Error while downloading file: invalid hash');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$release->signed) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Security::canUseEncryption()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = sprintf('%suv/%s.asc', $this->fossil_url, $release->name);
|
||||||
|
$r = (new HTTP)->GET($url);
|
||||||
|
|
||||||
|
if ($r->fail || !$r->body) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = file_get_contents($this->gpg_pubkey_file);
|
||||||
|
$data = file_get_contents($tmpfile);
|
||||||
|
|
||||||
|
return Security::verifyWithPublicKey($key, $data, $r->body);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove old stale downloaded files
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function prune(int $delay = 3600 * 24): void
|
||||||
|
{
|
||||||
|
$files = self::recursiveList($this->tmp_path, 'tmp-release-*');
|
||||||
|
$dirs = [];
|
||||||
|
|
||||||
|
foreach ($files as $file) {
|
||||||
|
if (is_dir($file)) {
|
||||||
|
$dirs[] = $file;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$delay || filemtime($file) < (time() - $delay)) {
|
||||||
|
@unlink($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to remove directories
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
@rmdir($dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clean(string $version): void
|
||||||
|
{
|
||||||
|
$path = $this->_getTempFilePath($version);
|
||||||
|
self::recursiveDelete(dirname($path), basename($path) . '*');
|
||||||
|
}
|
||||||
|
|
||||||
|
static protected function recursiveDelete(string $path, string $pattern = '*') {
|
||||||
|
$files = self::recursiveList($path, $pattern);
|
||||||
|
|
||||||
|
$dirs = [];
|
||||||
|
|
||||||
|
foreach ($files as $file) {
|
||||||
|
if (is_dir($file)) {
|
||||||
|
$dirs[] = $file;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@unlink($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
@rmdir($dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function diff(string $version): \stdClass
|
||||||
|
{
|
||||||
|
$this->listReleases();
|
||||||
|
|
||||||
|
if (!isset($this->releases[$version])) {
|
||||||
|
throw new \InvalidArgumentException('Unknown release');
|
||||||
|
}
|
||||||
|
|
||||||
|
$tmpfile = $this->_getTempFilePath($version);
|
||||||
|
|
||||||
|
if (!file_exists($tmpfile)) {
|
||||||
|
throw new \LogicException('This release has not been downloaded yet');
|
||||||
|
}
|
||||||
|
|
||||||
|
$release = $this->releases[$version];
|
||||||
|
|
||||||
|
$phar = new \PharData($tmpfile,
|
||||||
|
\FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::KEY_AS_PATHNAME
|
||||||
|
| \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS);
|
||||||
|
|
||||||
|
|
||||||
|
// List existing files
|
||||||
|
$existing_files = [];
|
||||||
|
$l = strlen($this->app_path);
|
||||||
|
|
||||||
|
foreach (self::recursiveList($this->app_path) as $path) {
|
||||||
|
if (is_dir($path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = substr($path, $l + 1);
|
||||||
|
|
||||||
|
// Skip ignored paths
|
||||||
|
foreach ($this->ignored_paths as $ignored_path) {
|
||||||
|
if (0 === strpos($file, $ignored_path)) {
|
||||||
|
continue(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$existing_files[$file] = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// List files
|
||||||
|
$release_files = [];
|
||||||
|
$update = [];
|
||||||
|
|
||||||
|
// We are always ignoring the first directory level
|
||||||
|
$parent = $phar->getPathName();
|
||||||
|
$parent_l = strlen($parent);
|
||||||
|
|
||||||
|
foreach (new \RecursiveIteratorIterator($phar) as $path => $file) {
|
||||||
|
if ($file->isDir()) {
|
||||||
|
// Skip directories
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$relative_path = substr($path, $parent_l + 1);
|
||||||
|
$release_files[$relative_path] = $path;
|
||||||
|
|
||||||
|
$is_ignored = false;
|
||||||
|
|
||||||
|
// Skip ignored paths
|
||||||
|
foreach ($this->ignored_paths as $ignored_path) {
|
||||||
|
if (0 === strpos($relative_path, $ignored_path)) {
|
||||||
|
$is_ignored = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$local_path = $this->app_path . DIRECTORY_SEPARATOR . $relative_path;
|
||||||
|
|
||||||
|
// Skip if file doesn't exist, it will be marked as to be created
|
||||||
|
if (!file_exists($local_path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($file->getSize() != filesize($local_path)
|
||||||
|
|| sha1_file($local_path) != sha1_file($path)) {
|
||||||
|
$update[$relative_path] = $path;
|
||||||
|
}
|
||||||
|
elseif ($is_ignored) {
|
||||||
|
unset($release_files[$relative_path]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$create = array_diff_key($release_files, $existing_files);
|
||||||
|
$delete = array_diff_key($existing_files, $release_files);
|
||||||
|
|
||||||
|
ksort($create);
|
||||||
|
ksort($delete);
|
||||||
|
ksort($update);
|
||||||
|
|
||||||
|
return (object) compact('delete', 'create', 'update');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function upgrade(string $version): void
|
||||||
|
{
|
||||||
|
$diff = $this->diff($version);
|
||||||
|
|
||||||
|
foreach ($diff->delete as $file => $path) {
|
||||||
|
@unlink($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Clean up empty directories
|
||||||
|
|
||||||
|
foreach ($diff->create as $file => $source) {
|
||||||
|
$this->_copy($source, $this->app_path . DIRECTORY_SEPARATOR . $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($diff->update as $file => $source) {
|
||||||
|
$this->_copy($source, $this->app_path . DIRECTORY_SEPARATOR . $file);
|
||||||
|
|
||||||
|
if (function_exists('opcache_invalidate')) {
|
||||||
|
@opcache_invalidate($this->app_path . DIRECTORY_SEPARATOR . $file, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->clean($version);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _copy(string $source, string $target): bool
|
||||||
|
{
|
||||||
|
$dir = dirname($target);
|
||||||
|
|
||||||
|
if (!file_exists($dir)) {
|
||||||
|
mkdir($dir, 0777, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy($source, $target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function install(string $version)
|
||||||
|
{
|
||||||
|
if (!isset($this->releases[$version])) {
|
||||||
|
throw new \InvalidArgumentException('Unknown release');
|
||||||
|
}
|
||||||
|
|
||||||
|
$tmpfile = $this->_getTempFilePath($version);
|
||||||
|
$phar = new \PharData($tmpfile, \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::KEY_AS_PATHNAME
|
||||||
|
| \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS);
|
||||||
|
// Ignore first level directory
|
||||||
|
$root_l = strlen($phar->getPathName());
|
||||||
|
|
||||||
|
foreach (new \RecursiveIteratorIterator($phar) as $source => $_file) {
|
||||||
|
$file = substr($source, $root_l + 1);
|
||||||
|
$this->_copy($source, $this->app_path . DIRECTORY_SEPARATOR . $file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function autoinstall(?string $version = null): void
|
||||||
|
{
|
||||||
|
$version ??= $this->latest();
|
||||||
|
|
||||||
|
if (!$version) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->download($version);
|
||||||
|
|
||||||
|
if (isset($this->gpg_pubkey_file)) {
|
||||||
|
$this->verify($version);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->install($version);
|
||||||
|
$this->clean($version);
|
||||||
|
}
|
||||||
|
|
||||||
|
static protected function recursiveList(string $path, string $pattern = '*')
|
||||||
|
{
|
||||||
|
$out = [];
|
||||||
|
$length = strlen($path);
|
||||||
|
|
||||||
|
foreach (glob($path . DIRECTORY_SEPARATOR . $pattern, \GLOB_NOSORT) as $subpath) {
|
||||||
|
$out[] = $subpath;
|
||||||
|
|
||||||
|
if (is_dir($subpath)) {
|
||||||
|
$out = array_merge($out, self::recursiveList($subpath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
}
|
878
src/include/lib/KD2/Garbage2xhtml.php
Normal file
878
src/include/lib/KD2/Garbage2xhtml.php
Normal file
|
@ -0,0 +1,878 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
This file is part of KD2FW -- <http://dev.kd2.org/>
|
||||||
|
|
||||||
|
Copyright (c) 2001-2019 BohwaZ <http://bohwaz.net/>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
KD2FW 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.
|
||||||
|
|
||||||
|
Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace KD2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Garbage2xhtml lib
|
||||||
|
Takes a html text and returns something semantic and maybe valid
|
||||||
|
|
||||||
|
Copyleft (C) 2006-13 BohwaZ - http://bohwaz.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Garbage_Exception extends \Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class Garbage2xhtml
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Secure attributes contents?
|
||||||
|
* Will check for url scheme and url content in href and src
|
||||||
|
* It's advised to disable <script> and <style> tags and style attribute
|
||||||
|
* because they could be used for XSS attacks
|
||||||
|
*/
|
||||||
|
public $secure = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enclose text which is not in any element in <p> tags?
|
||||||
|
*/
|
||||||
|
public $enclose_text = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-add <br /> in text blocks?
|
||||||
|
* Will also break <p> blocks when encountering a double line break.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* <p>One Two
|
||||||
|
*
|
||||||
|
* Three
|
||||||
|
* Four
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Will render as:
|
||||||
|
* <p>One Two</p>
|
||||||
|
* <p>Three<br />
|
||||||
|
* Four</p>
|
||||||
|
*/
|
||||||
|
public $auto_br = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text encoding (used for escaping)
|
||||||
|
*/
|
||||||
|
public $encoding = 'UTF-8';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove forbidden tags from ouput?
|
||||||
|
* If true, "<em>" will disappear if it's not in allowed tags.
|
||||||
|
* If false, "<em>" will become a text node with <em>
|
||||||
|
*/
|
||||||
|
public $remove_forbidden_tags = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove forbidden tags contents?
|
||||||
|
* If true "<b>Hello</b>" will become "" if <b> is not allowed
|
||||||
|
* If false "<b>Hello</b>" will become "Hello"
|
||||||
|
*/
|
||||||
|
public $remove_forbidden_tags_content = false;
|
||||||
|
|
||||||
|
public $indent = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Core attributes allowed on each element
|
||||||
|
*/
|
||||||
|
public $core_attributes = array('lang', 'class', 'id', 'title', 'dir');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allowed block tags
|
||||||
|
*
|
||||||
|
* 'tag' => true, // Allows core attributes
|
||||||
|
* 'tag' => false, // Disallow core attributes
|
||||||
|
* 'tag' => array('allowed attribute 1', 'href', 'src'),
|
||||||
|
* // Allow core attributes and those specific attributes
|
||||||
|
*/
|
||||||
|
public $block_tags = array(
|
||||||
|
'ul' => true,
|
||||||
|
'ol' => true,
|
||||||
|
'li' => true,
|
||||||
|
'dl' => true,
|
||||||
|
|
||||||
|
'p' => true,
|
||||||
|
'div' => true,
|
||||||
|
|
||||||
|
'h1' => true,
|
||||||
|
'h2' => true,
|
||||||
|
'h3' => true,
|
||||||
|
'h4' => true,
|
||||||
|
'h5' => true,
|
||||||
|
'h6' => true,
|
||||||
|
|
||||||
|
'pre' => true,
|
||||||
|
'hr' => true,
|
||||||
|
'address' => true,
|
||||||
|
'blockquote'=> array('cite'),
|
||||||
|
|
||||||
|
'object'=> array('type', 'width', 'height', 'data'),
|
||||||
|
'iframe'=> array('src', 'width', 'height', 'frameborder', 'scrolling'),
|
||||||
|
|
||||||
|
'table' => array('summary'),
|
||||||
|
'tbody' => true,
|
||||||
|
'thead' => true,
|
||||||
|
'tfoot' => true,
|
||||||
|
'caption' => true,
|
||||||
|
'colgroup' => array('span'),
|
||||||
|
'col' => true,
|
||||||
|
'tr' => true,
|
||||||
|
'th' => array('colspan', 'rowspan', 'scope', 'headers'),
|
||||||
|
'td' => array('colspan', 'rowspan', 'headers'),
|
||||||
|
|
||||||
|
// XHTML 5
|
||||||
|
'article' => true,
|
||||||
|
'aside' => true,
|
||||||
|
'audio' => array('src', 'controls', 'loop'),
|
||||||
|
'figure' => true,
|
||||||
|
'footer' => true,
|
||||||
|
'header' => true,
|
||||||
|
'hgroup' => true,
|
||||||
|
'section' => true,
|
||||||
|
'video' => array('src', 'controls', 'width', 'height', 'poster'),
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allowed inline elements
|
||||||
|
*/
|
||||||
|
public $inline_tags = array(
|
||||||
|
// 'tag' => array of allowed attributes
|
||||||
|
'abbr' => array('title'),
|
||||||
|
'dfn' => true,
|
||||||
|
'acronym' => array('title'),
|
||||||
|
|
||||||
|
'cite' => true,
|
||||||
|
'q' => array('cite'),
|
||||||
|
|
||||||
|
'code' => true,
|
||||||
|
'kbd' => true,
|
||||||
|
'samp' => true,
|
||||||
|
|
||||||
|
'strong'=> true,
|
||||||
|
'b' => true,
|
||||||
|
'i' => true,
|
||||||
|
'u' => true,
|
||||||
|
'em' => true,
|
||||||
|
|
||||||
|
'del' => true,
|
||||||
|
'ins' => true,
|
||||||
|
'sup' => true,
|
||||||
|
'sub' => true,
|
||||||
|
|
||||||
|
'dt' => true,
|
||||||
|
'dd' => true,
|
||||||
|
|
||||||
|
'span' => true,
|
||||||
|
'br' => false,
|
||||||
|
|
||||||
|
'a' => array('href', 'hreflang', 'rel'),
|
||||||
|
'img' => array('src', 'alt', 'width', 'height'),
|
||||||
|
|
||||||
|
'param' => array('name', 'value', 'type'),
|
||||||
|
|
||||||
|
// XHTML 5
|
||||||
|
'mark' => true,
|
||||||
|
'var' => true,
|
||||||
|
'time' => array('pubdate', 'datetime'),
|
||||||
|
'figcaption'=> true,
|
||||||
|
);
|
||||||
|
|
||||||
|
public $allowed_url_schemes = array(
|
||||||
|
'http' => '://',
|
||||||
|
'https' => '://',
|
||||||
|
'ftp' => '://',
|
||||||
|
'mailto'=> ':',
|
||||||
|
'xmpp' => ':',
|
||||||
|
'news' => ':',
|
||||||
|
'nntp' => '://',
|
||||||
|
'tel' => ':',
|
||||||
|
'callto'=> ':',
|
||||||
|
'ed2k' => '://',
|
||||||
|
'irc' => '://',
|
||||||
|
'magnet'=> ':',
|
||||||
|
'mms' => '://',
|
||||||
|
'rtsp' => '://',
|
||||||
|
'sip' => ':',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tags who need content to be enclosed
|
||||||
|
*/
|
||||||
|
public $elements_need_enclose = array('blockquote', 'form', 'address', 'noscript');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tags elements who accept <br /> inside
|
||||||
|
*/
|
||||||
|
public $elements_allow_break = array('p', 'dd', 'dt', 'li', 'td', 'th', 'div');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autoclosing tags (eg. <br />)
|
||||||
|
*/
|
||||||
|
public $autoclosing_tags = array('br', 'hr', 'img', 'param');
|
||||||
|
|
||||||
|
///////// PRIVATE PROPERTIES
|
||||||
|
|
||||||
|
private $opened = array();
|
||||||
|
private $matches = array();
|
||||||
|
private $line = 0;
|
||||||
|
private $check_only = false;
|
||||||
|
|
||||||
|
private $allowed_tags = array();
|
||||||
|
|
||||||
|
const SPLIT_REGEXP = '!<(/?)([^><]*)>!';
|
||||||
|
const ATTRIBUTE_REGEXP = '/(?:(?:"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\') | (?>[^"\'=\s]+))+|[=]/x';
|
||||||
|
|
||||||
|
public function parse($string)
|
||||||
|
{
|
||||||
|
$string = preg_replace('#<!--.*-->#Us', '', $string);
|
||||||
|
$string = preg_replace('#<!\[CDATA\[.*\]\]>#Us', '', $string);
|
||||||
|
|
||||||
|
$string = str_replace(array("\r\n", "\r"), "\n", $string);
|
||||||
|
$string = preg_replace('!<br\s*/?>!i', '<br />', $string);
|
||||||
|
$string = trim($string);
|
||||||
|
|
||||||
|
$this->resetInternals();
|
||||||
|
$this->allowed_tags = array_merge($this->inline_tags, $this->block_tags);
|
||||||
|
|
||||||
|
$this->matches = preg_split(self::SPLIT_REGEXP, $string, 0, PREG_SPLIT_DELIM_CAPTURE);
|
||||||
|
unset($string);
|
||||||
|
|
||||||
|
$nodes = $this->buildTree();
|
||||||
|
$this->resetInternals();
|
||||||
|
|
||||||
|
return $nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks a string validity
|
||||||
|
*/
|
||||||
|
public function check($string)
|
||||||
|
{
|
||||||
|
$this->check_only = true;
|
||||||
|
$this->parse($string);
|
||||||
|
$this->check_only = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a string
|
||||||
|
*/
|
||||||
|
public function process($string)
|
||||||
|
{
|
||||||
|
$nodes = $this->parse($string);
|
||||||
|
unset($string);
|
||||||
|
|
||||||
|
if ($this->enclose_text)
|
||||||
|
{
|
||||||
|
$nodes = $this->encloseChildren($nodes, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->auto_br)
|
||||||
|
{
|
||||||
|
$nodes = $this->autoLineBreak($nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->outputNodes($nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs a string from a nodes array
|
||||||
|
*/
|
||||||
|
public function outputNodes($nodes, $level = 0)
|
||||||
|
{
|
||||||
|
$out = '';
|
||||||
|
|
||||||
|
foreach ($nodes as $node)
|
||||||
|
{
|
||||||
|
if (is_array($node))
|
||||||
|
{
|
||||||
|
$close = '';
|
||||||
|
$content = '';
|
||||||
|
$open = '<'.$node['name'];
|
||||||
|
|
||||||
|
foreach ($node['attrs'] as $key=>$value)
|
||||||
|
{
|
||||||
|
$open .= ' '.$key.'="'.$value.'"';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isTagAutoclosing($node['name']))
|
||||||
|
{
|
||||||
|
$open .= ' />';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$open .= '>';
|
||||||
|
$close = '</'.$node['name'].'>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($node['children']))
|
||||||
|
{
|
||||||
|
$content = $this->outputNodes($node['children'], $level + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($close && $this->indent !== false && array_key_exists($node['name'], $this->block_tags) && $node['name'] != 'pre')
|
||||||
|
{
|
||||||
|
$tag = $this->indentTag($open, $content, $close, $level * ($this->indent === true ? 1 : (int) $this->indent));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$tag = $open . $content . $close;
|
||||||
|
|
||||||
|
if ($node['name'] == 'br')
|
||||||
|
$tag.= "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$tag = $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out .= $tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function indentTag($open, $content, $close, $indent)
|
||||||
|
{
|
||||||
|
$out = "\n";
|
||||||
|
$out.= str_repeat(' ', $indent);
|
||||||
|
$out.= $open;
|
||||||
|
$out.= "\n";
|
||||||
|
|
||||||
|
$content = explode("\n", $content);
|
||||||
|
|
||||||
|
foreach ($content as $line)
|
||||||
|
{
|
||||||
|
if (!trim($line))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$out.= str_repeat(' ', $indent + ($this->indent === true ? 2 : (int) $this->indent));
|
||||||
|
$out.= $line . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($content);
|
||||||
|
|
||||||
|
$out.= str_repeat(' ', $indent);
|
||||||
|
$out.= $close;
|
||||||
|
$out.= "\n";
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resetInternals()
|
||||||
|
{
|
||||||
|
$this->opened = array();
|
||||||
|
$this->matches = array();
|
||||||
|
$this->line = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Break line and paragraphs following this rule :
|
||||||
|
* in a paragraph : one line break = <br />,
|
||||||
|
* two line breaks = closing paragraph and opening a new one
|
||||||
|
* in other elements : nl2br
|
||||||
|
*/
|
||||||
|
private function autoLineBreak($nodes, $parent = false)
|
||||||
|
{
|
||||||
|
$n = array();
|
||||||
|
$nb_nodes = count($nodes);
|
||||||
|
$k = 0;
|
||||||
|
|
||||||
|
foreach ($nodes as $node)
|
||||||
|
{
|
||||||
|
// Text node inside an element allowing for line breaks
|
||||||
|
if (is_string($node) && trim($node) != '' && in_array($parent, $this->elements_allow_break))
|
||||||
|
{
|
||||||
|
$matches = preg_split('!(\n+)!', $node, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||||
|
$i = 1;
|
||||||
|
$max = count($matches);
|
||||||
|
|
||||||
|
while (($line = array_shift($matches)) !== null)
|
||||||
|
{
|
||||||
|
// Line break
|
||||||
|
if ($i++ % 2 == 0)
|
||||||
|
{
|
||||||
|
if (!empty($n) && ($k < $nb_nodes - 1 || $i < $max))
|
||||||
|
{
|
||||||
|
$n[] = array('name' => 'br', 'attrs' => array(), 'children' => array());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ($line != "")
|
||||||
|
{
|
||||||
|
$n[] = $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// In paragraphs we'll try to split them each two-line breaks
|
||||||
|
elseif (is_array($node) && $node['name'] == 'p')
|
||||||
|
{
|
||||||
|
$n[] = array('name' => 'p', 'attrs' => $node['attrs'], 'children' => array());
|
||||||
|
$current_node = count($n) - 1;
|
||||||
|
|
||||||
|
// Because we need to work on parent-level we will loop on children here
|
||||||
|
// (so we don't do recursive calls)
|
||||||
|
while (($child = array_shift($node['children'])) !== null)
|
||||||
|
{
|
||||||
|
// Text node ? try to split it
|
||||||
|
if (is_string($child))
|
||||||
|
{
|
||||||
|
$matches = preg_split('!(\n+)!', $child, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||||
|
$i = 0;
|
||||||
|
$max = count($matches);
|
||||||
|
|
||||||
|
while (($line = array_shift($matches)) !== null)
|
||||||
|
{
|
||||||
|
if ($i++ % 2)
|
||||||
|
{
|
||||||
|
// More than 2 line-breaks then we create a new paragraph and we continue
|
||||||
|
if (strlen($line) >= 2)
|
||||||
|
{
|
||||||
|
$n[] = array('name' => 'p', 'attrs' => $node['attrs'], 'children' => array());
|
||||||
|
$current_node = count($n) - 1;
|
||||||
|
|
||||||
|
$nb_nodes++;
|
||||||
|
$k++;
|
||||||
|
}
|
||||||
|
// Simple line break
|
||||||
|
// but no line break just after or before end
|
||||||
|
elseif (!empty($n[$current_node]['children']) && ($i - 1 < $max || $k < $nb_nodes - 1))
|
||||||
|
{
|
||||||
|
$n[$current_node]['children'][] = array('name' => 'br', 'attrs' => array(), 'children' => array());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ($line != "")
|
||||||
|
{
|
||||||
|
$n[$current_node]['children'][] = $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$n[$current_node]['children'][] = $child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!is_string($node) && !empty($node['children']))
|
||||||
|
{
|
||||||
|
$node['children'] = $this->autoLineBreak($node['children'], $node['name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$n[] = $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
$k++;
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($nodes);
|
||||||
|
return $n;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getTagAttributes($value, $tag)
|
||||||
|
{
|
||||||
|
$attributes = array();
|
||||||
|
|
||||||
|
if (array_key_exists($tag, $this->allowed_tags))
|
||||||
|
{
|
||||||
|
$tag =& $this->allowed_tags[$tag];
|
||||||
|
}
|
||||||
|
elseif (($prefix = strtok($tag, ':')) && array_key_exists($prefix, $this->allowed_tags))
|
||||||
|
{
|
||||||
|
$tag =& $this->allowed_tags[$match[0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
strtok('');
|
||||||
|
|
||||||
|
$value = preg_replace('!^.*\s+!U', '', $value);
|
||||||
|
|
||||||
|
if (preg_match_all(self::ATTRIBUTE_REGEXP, $value, $match))
|
||||||
|
{
|
||||||
|
$state = 0;
|
||||||
|
$name = false;
|
||||||
|
|
||||||
|
foreach($match[0] as $value)
|
||||||
|
{
|
||||||
|
if ($state == 0)
|
||||||
|
{
|
||||||
|
$name = strtolower((string) $value);
|
||||||
|
$state = 1;
|
||||||
|
$pass = false;
|
||||||
|
|
||||||
|
// Allowed attribute ?
|
||||||
|
if ($tag && in_array($name, $this->core_attributes))
|
||||||
|
$pass = true;
|
||||||
|
elseif (is_array($tag) && in_array($name, $tag))
|
||||||
|
$pass = true;
|
||||||
|
elseif (preg_match('!^(?:data-|[a-z0-9-]+:)!', $name, $m))
|
||||||
|
{
|
||||||
|
// Allow namespaces and data- (html5) attributes
|
||||||
|
if ($tag && in_array($m[0], $this->core_attributes))
|
||||||
|
$pass = true;
|
||||||
|
elseif (is_array($tag) && in_array($m[0], $tag))
|
||||||
|
$pass = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$pass)
|
||||||
|
{
|
||||||
|
$name = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ($state == 1)
|
||||||
|
{
|
||||||
|
if ($value != '=' && $name && $this->check_only)
|
||||||
|
throw new Garbage_Exception("Expecting '=' after $name on line ".$this->line);
|
||||||
|
|
||||||
|
$state = 2;
|
||||||
|
}
|
||||||
|
elseif ($state == 2)
|
||||||
|
{
|
||||||
|
$state = 0;
|
||||||
|
|
||||||
|
if (!$name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ($value == '=' && $this->check_only)
|
||||||
|
throw new Garbage_Exception("Unexpected '=' after $name on line ".$this->line);
|
||||||
|
|
||||||
|
if ($value[0] == '"' || $value[0] == "'")
|
||||||
|
$value = substr($value, 1, -1);
|
||||||
|
|
||||||
|
$value = $this->protectAttribute($name, $value);
|
||||||
|
|
||||||
|
$attributes[$name] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeObfuscated($value)
|
||||||
|
{
|
||||||
|
// Don't try to trick me
|
||||||
|
$value = rawurldecode($value);
|
||||||
|
$value = html_entity_decode($value, ENT_QUOTES, $this->encoding);
|
||||||
|
|
||||||
|
// Convert unicode entities back to ASCII
|
||||||
|
// unicode entities don't always have a semicolon ending the entity
|
||||||
|
$value = preg_replace_callback('~�*([0-9a-f]+);?~i',
|
||||||
|
function($match) { return chr(hexdec($match[1])); },
|
||||||
|
$value);
|
||||||
|
$value = preg_replace_callback('~�*([0-9]+);?~',
|
||||||
|
function ($match) { return chr($match[1]); },
|
||||||
|
$value);
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function protectAttribute($name, $value)
|
||||||
|
{
|
||||||
|
if (!$this->secure)
|
||||||
|
return $value;
|
||||||
|
|
||||||
|
if ($name == 'src' || $name == 'href')
|
||||||
|
{
|
||||||
|
$value = self::decodeObfuscated($value);
|
||||||
|
|
||||||
|
// parse_url already have some tricks against XSS
|
||||||
|
$url = parse_url($value);
|
||||||
|
$value = '';
|
||||||
|
|
||||||
|
if (!empty($url['scheme']))
|
||||||
|
{
|
||||||
|
$url['scheme'] = strtolower($url['scheme']);
|
||||||
|
|
||||||
|
if (!array_key_exists($url['scheme'], $this->allowed_url_schemes))
|
||||||
|
return '';
|
||||||
|
|
||||||
|
$value .= $url['scheme'] . $this->allowed_url_schemes[$url['scheme']];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($url['host']))
|
||||||
|
{
|
||||||
|
$value .= $url['host'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($url['path']))
|
||||||
|
{
|
||||||
|
$value .= $url['path'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($url['query']))
|
||||||
|
{
|
||||||
|
// We can't use parse_str and build_http_string to sanitize url here
|
||||||
|
// Or else we'll get things like ?param1¶m2 transformed in ?param1=¶m2=
|
||||||
|
$query = explode('&', $url['query']);
|
||||||
|
|
||||||
|
foreach ($query as &$item)
|
||||||
|
{
|
||||||
|
$item = explode('=', $item);
|
||||||
|
|
||||||
|
if (isset($item[1]))
|
||||||
|
$item = rawurlencode(rawurldecode($item[0])) . '=' . rawurlencode(rawurldecode($item[1]));
|
||||||
|
else
|
||||||
|
$item = rawurlencode(rawurldecode($item[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$value .= '?' . $this->escape(implode('&', $query));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($url['fragment']))
|
||||||
|
{
|
||||||
|
$value .= '#' . $url['fragment'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$value = str_replace('&', '&', $value);
|
||||||
|
$value = $this->cleanEntities($value);
|
||||||
|
$value = $this->escape($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getTagName($value)
|
||||||
|
{
|
||||||
|
$value = trim($value);
|
||||||
|
|
||||||
|
if (preg_match('!^([a-zA-Z0-9-]+)(?:[:]([a-zA-Z0-9-]+))?!', $value, $match))
|
||||||
|
{
|
||||||
|
if (!empty($match[2]) && array_key_exists($match[1] . ':', $this->allowed_tags))
|
||||||
|
return $match[0];
|
||||||
|
elseif (array_key_exists($match[0], $this->allowed_tags))
|
||||||
|
return $match[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isTagAutoclosing($tag)
|
||||||
|
{
|
||||||
|
if (in_array($tag, $this->autoclosing_tags))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (preg_match('!^[a-zA-Z0-9-]+:!', $tag, $match) && in_array($match[0], $this->autoclosing_tags))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build HTML tree
|
||||||
|
*/
|
||||||
|
private function buildTree()
|
||||||
|
{
|
||||||
|
$i = 0;
|
||||||
|
$nodes = array();
|
||||||
|
$closing = false;
|
||||||
|
$in_forbidden_tag = false;
|
||||||
|
|
||||||
|
while (($value = array_shift($this->matches)) !== null)
|
||||||
|
{
|
||||||
|
// Line count
|
||||||
|
$this->line += (int) substr_count($value, "\n");
|
||||||
|
|
||||||
|
switch ($i++ % 3)
|
||||||
|
{
|
||||||
|
// Text node
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
if ($value != "" && !$this->check_only
|
||||||
|
&& !($in_forbidden_tag && $this->remove_forbidden_tags_content))
|
||||||
|
{
|
||||||
|
$nodes[] = $this->escape($value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next iteration is closing tag (probably ?)
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
$closing = ($value == '/');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag itself
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
$tag = $this->getTagName($value);
|
||||||
|
|
||||||
|
// Self-closing tag
|
||||||
|
if (substr($value, -1) == '/' || $this->isTagAutoclosing($tag))
|
||||||
|
{
|
||||||
|
$value = preg_replace('!\s*/$!', '', $value);
|
||||||
|
|
||||||
|
// Dismis un-authorized tag
|
||||||
|
if (!$tag)
|
||||||
|
{
|
||||||
|
if ($this->check_only)
|
||||||
|
throw new Garbage_Exception("Un-authorized tag <$value>");
|
||||||
|
|
||||||
|
if (!$this->remove_forbidden_tags)
|
||||||
|
$nodes[] = '<'.$this->escape($value).' />';
|
||||||
|
|
||||||
|
$in_forbidden_tag = false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->check_only)
|
||||||
|
{
|
||||||
|
$nodes[] = array(
|
||||||
|
'name' => $tag,
|
||||||
|
'attrs' => $this->getTagAttributes($value, $tag),
|
||||||
|
'children'=> array(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Closing tag
|
||||||
|
else if ($closing)
|
||||||
|
{
|
||||||
|
// Dismis un-authorized tag
|
||||||
|
if (!$tag)
|
||||||
|
{
|
||||||
|
if (!$this->remove_forbidden_tags)
|
||||||
|
$nodes[] = '</'.$this->escape($value).'>';
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$open = array_pop($this->opened);
|
||||||
|
|
||||||
|
// Uh-oh parse error !
|
||||||
|
// We could try to just dismiss tag errors or repair dirty HTML but
|
||||||
|
// it's too complicated. Just write valid xHTML.
|
||||||
|
if ($value != $open)
|
||||||
|
{
|
||||||
|
if ($this->check_only)
|
||||||
|
throw new Garbage_Exception("Tag <$value> closed, which is not open, on line ".$this->line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nodes;
|
||||||
|
}
|
||||||
|
// Opening tag
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!$tag)
|
||||||
|
{
|
||||||
|
if ($this->check_only)
|
||||||
|
throw new Garbage_Exception("Invalid tag <$value>");
|
||||||
|
|
||||||
|
if (!$this->remove_forbidden_tags)
|
||||||
|
$nodes[] = '<'.$this->escape($value).'>';
|
||||||
|
|
||||||
|
$in_forbidden_tag = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->check_only)
|
||||||
|
{
|
||||||
|
$node = array(
|
||||||
|
'name' => $tag,
|
||||||
|
'attrs' => $this->getTagAttributes($value, $tag),
|
||||||
|
'children'=> array(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->opened[] = $tag;
|
||||||
|
|
||||||
|
if ($this->check_only)
|
||||||
|
{
|
||||||
|
$this->buildTree();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Build child tree
|
||||||
|
$node['children'] = $this->buildTree();
|
||||||
|
|
||||||
|
// You need to enclose text in paragraphs in some tags
|
||||||
|
// (Yes, read the XHTML spec)
|
||||||
|
$node['children'] = $this->encloseChildren($node['children'], $node['name']);
|
||||||
|
|
||||||
|
$nodes[] = $node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enclose sub elements which need to be enclosed
|
||||||
|
*/
|
||||||
|
private function encloseChildren($children, $parent)
|
||||||
|
{
|
||||||
|
if (!empty($children) && (in_array($parent, $this->elements_need_enclose) || !$parent))
|
||||||
|
{
|
||||||
|
$n = array();
|
||||||
|
$open = false;
|
||||||
|
|
||||||
|
while (($child = array_shift($children)) !== NULL)
|
||||||
|
{
|
||||||
|
if (is_string($child) || !array_key_exists($child['name'], $this->block_tags))
|
||||||
|
{
|
||||||
|
if ($open === false)
|
||||||
|
{
|
||||||
|
$open = count($n);
|
||||||
|
$n[$open] = array('name' => 'p', 'attrs' => array(), 'children' => array());
|
||||||
|
}
|
||||||
|
|
||||||
|
$n[$open]['children'][] = $child;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$open = false;
|
||||||
|
|
||||||
|
$n[] = $child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$children = $n;
|
||||||
|
unset($n, $open, $child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function escape($str)
|
||||||
|
{
|
||||||
|
$out = htmlspecialchars($str, ENT_QUOTES, $this->encoding, false);
|
||||||
|
|
||||||
|
if (empty($out) && !empty($str))
|
||||||
|
{
|
||||||
|
throw new Garbage_Exception("Encoding error.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean entities
|
||||||
|
*/
|
||||||
|
private function cleanEntities($str)
|
||||||
|
{
|
||||||
|
return preg_replace('/&(#[0-9a-fx]+|[a-z]+);/i', '&\\1;', $str);
|
||||||
|
}
|
||||||
|
}
|
185
src/include/lib/KD2/Graphics/BarCode.php
Normal file
185
src/include/lib/KD2/Graphics/BarCode.php
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
This file is part of KD2FW -- <http://dev.kd2.org/>
|
||||||
|
|
||||||
|
Copyright (c) 2001-2019 BohwaZ <http://bohwaz.net/>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
KD2FW 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.
|
||||||
|
|
||||||
|
Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace KD2\Graphics;
|
||||||
|
|
||||||
|
class BarCode
|
||||||
|
{
|
||||||
|
const PRITY = [
|
||||||
|
[1,1,1,1,1,1],
|
||||||
|
[1,1,0,1,0,0],
|
||||||
|
[1,1,0,0,1,0],
|
||||||
|
[1,1,0,0,0,1],
|
||||||
|
[1,0,1,1,0,0],
|
||||||
|
[1,0,0,1,1,0],
|
||||||
|
[1,0,0,0,1,1],
|
||||||
|
[1,0,1,0,1,0],
|
||||||
|
[1,0,1,0,0,1],
|
||||||
|
[1,0,0,1,0,1]
|
||||||
|
];
|
||||||
|
|
||||||
|
const BARTABLE = [
|
||||||
|
['3211','1123'],
|
||||||
|
['2221','1222'],
|
||||||
|
['2122','2212'],
|
||||||
|
['1411','1141'],
|
||||||
|
['1132','2311'],
|
||||||
|
['1231','1321'],
|
||||||
|
['1114','4111'],
|
||||||
|
['1312','2131'],
|
||||||
|
['1213','3121'],
|
||||||
|
['3112','2113']
|
||||||
|
];
|
||||||
|
|
||||||
|
protected string $code;
|
||||||
|
|
||||||
|
public function __construct(string $code)
|
||||||
|
{
|
||||||
|
$this->code = preg_replace('/[^\d]/', '', $code);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(): string
|
||||||
|
{
|
||||||
|
return $this->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verify(): bool
|
||||||
|
{
|
||||||
|
if (strlen($this->code) < 13) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sum = 0;
|
||||||
|
$code = str_split($this->code);
|
||||||
|
$sum = ($code[1] + $code[3] + $code[5] + $code[7] + $code[9] + $code[11]) * 3;
|
||||||
|
$sum += $code[0] + $code[2] + $code[4] + $code[6] + $code[8] + $code[10];
|
||||||
|
$sum = 10 - ($sum % 10);
|
||||||
|
|
||||||
|
return (string) $sum === $code[12];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toSVG(string $width = '200px'): string
|
||||||
|
{
|
||||||
|
static $guard = [1, 0, 1];
|
||||||
|
static $center = [0, 1, 0, 1, 0];
|
||||||
|
|
||||||
|
$bw = 3; //bar width
|
||||||
|
$w = $bw * 106;
|
||||||
|
$h = $bw * 50;
|
||||||
|
$fs = 8 * $bw; //Font size
|
||||||
|
$yt = 45 * $bw;
|
||||||
|
$dx = 2 * $bw; //lengh between bar and text
|
||||||
|
$x = 7 * $bw;
|
||||||
|
$y = 2.5 * $bw;
|
||||||
|
$sb = 35 * $bw;
|
||||||
|
$lb = 45 * $bw;
|
||||||
|
|
||||||
|
$char = $this->code;
|
||||||
|
$first = substr($char, 0, 1);
|
||||||
|
$first = (int) $first;
|
||||||
|
$oe = self::PRITY[$first]; //Old event array for first number
|
||||||
|
$char = str_split($char);
|
||||||
|
|
||||||
|
$out = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . PHP_EOL;
|
||||||
|
$out .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' . PHP_EOL;
|
||||||
|
$out .= sprintf('<svg viewBox="0 0 %d %d" width="%s" version="1.1" xmlns="http://www.w3.org/2000/svg">', $w, $h, $width) . PHP_EOL;
|
||||||
|
|
||||||
|
$xt = $x + $dx - 8 * $bw; //Start point of text drawing
|
||||||
|
$out .= sprintf(' <text x="%d" y="%d" font-family="monospace" font-size="%s">%s</text>', $xt, $yt, $fs, $char[0]) . PHP_EOL;
|
||||||
|
|
||||||
|
// draw the left-most guarding bar
|
||||||
|
foreach ($guard as $bar) {
|
||||||
|
if ($bar === 1) {
|
||||||
|
$out .= sprintf(' <rect x="%d" y="%d" width="%d" height="%d" fill="black" stroke-width="0" />', $x, $y, $bw, $lb) . PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$x = $x + $bw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw the left bars
|
||||||
|
for ($i = 1; $i < 7; $i++) {
|
||||||
|
$id = $i - 1; //id for Old-event array
|
||||||
|
$oev = !$oe[$id]; //Old-event value
|
||||||
|
$val = self::BARTABLE[$char[$i]][$oev];
|
||||||
|
|
||||||
|
$xt = $x + $dx;
|
||||||
|
|
||||||
|
$out .= sprintf(' <text x="%d" y="%d" font-family="monospace" font-size="%d">%s</text>', $xt, $yt, $fs, $char[$i]) . PHP_EOL;
|
||||||
|
|
||||||
|
$val = str_split($val);
|
||||||
|
|
||||||
|
for ($j = 0; $j < 4; $j++) {
|
||||||
|
$num = (int) $val[$j];
|
||||||
|
$w = $bw * $num;
|
||||||
|
|
||||||
|
if ($j % 2) {
|
||||||
|
$out .= sprintf(' <rect x="%d" y="%d" width="%d" height="%d" fill="black" stroke-width="0" />', $x, $y, $w, $sb) . PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$x = $x + $w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw the center bar
|
||||||
|
foreach ($center as $bar) {
|
||||||
|
if ($bar === 1) {
|
||||||
|
$out .= sprintf(' <rect x="%d" y="%d" width="%d" height="%d" fill="black" stroke-width="0" />', $x, $y, $bw, $lb) . PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$x = $x + $bw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the right bars, always in first column
|
||||||
|
for ($i = 7; $i < 13; $i++) {
|
||||||
|
$val = self::BARTABLE[$char[$i]][0];
|
||||||
|
$xt = $x + $dx;
|
||||||
|
|
||||||
|
$out .= sprintf(' <text x="%d" y="%d" font-family="monospace" font-size="%d">%s</text>', $xt, $yt, $fs, $char[$i]) . PHP_EOL;
|
||||||
|
|
||||||
|
$val = str_split($val);
|
||||||
|
|
||||||
|
for ($j = 0; $j < 4; $j++) {
|
||||||
|
$num = (int) $val[$j];
|
||||||
|
$w = $bw * $num;
|
||||||
|
|
||||||
|
if (!($j % 2)) {
|
||||||
|
$out .= sprintf(' <rect x="%d" y="%d" width="%d" height="%d" fill="black" stroke-width="0" />', $x, $y, $w, $sb) . PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$x = $x + $w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the ending guard bar
|
||||||
|
foreach ($guard as $bar) {
|
||||||
|
if ($bar === 1) {
|
||||||
|
$out .= sprintf(' <rect x="%d" y="%d" width="%d" height="%d" fill="black" stroke-width="0" />', $x, $y, $bw, $lb) . PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$x = $x + $bw;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out .= '</svg>' . PHP_EOL;
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue