From b3e4910ae8c603fc54d19a0f084e4763b3442ccd Mon Sep 17 00:00:00 2001 From: toitoinebzh Date: Sun, 24 Feb 2019 18:43:56 +0100 Subject: [PATCH] All checks are succesful with package_check --- LICENSE | 674 +++++++++++++++++++++ README.md | 82 +++ README_fr.md | 83 +++ check_process | 45 ++ conf/app.src | 6 + conf/nginx.conf | 33 + conf/php-fpm.conf | 430 +++++++++++++ conf/systemd.service | 13 + manifest.json | 85 +++ scripts/_common.sh | 13 + scripts/backup | 77 +++ scripts/change_url | 102 ++++ scripts/install | 334 ++++++++++ scripts/remove | 118 ++++ scripts/restore | 127 ++++ scripts/upgrade | 176 ++++++ sources/extra_files/app/.gitignore | 2 + sources/images/PluXml-logo_transparent.png | Bin 0 -> 12497 bytes sources/images/screenshot.jpg | Bin 0 -> 45831 bytes sources/patches/.gitignore | 2 + 20 files changed, 2402 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 README_fr.md create mode 100644 check_process create mode 100644 conf/app.src create mode 100644 conf/nginx.conf create mode 100644 conf/php-fpm.conf create mode 100644 conf/systemd.service create mode 100644 manifest.json create mode 100644 scripts/_common.sh create mode 100755 scripts/backup create mode 100644 scripts/change_url create mode 100755 scripts/install create mode 100755 scripts/remove create mode 100755 scripts/restore create mode 100755 scripts/upgrade create mode 100644 sources/extra_files/app/.gitignore create mode 100644 sources/images/PluXml-logo_transparent.png create mode 100644 sources/images/screenshot.jpg create mode 100644 sources/patches/.gitignore diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..dfb6689 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is 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. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + 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. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + 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 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. Use with the GNU Affero General Public License. + + 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 Affero 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 special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 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 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 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. + + pluxml_ynh + Copyright (C) 2019 antoine + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + pluxml_ynh Copyright (C) 2019 antoine + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + 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 GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..160ca1e --- /dev/null +++ b/README.md @@ -0,0 +1,82 @@ +# PluXml package for Yunohost + +[![Integration level](https://dash.yunohost.org/integration/pluxml.svg)](https://dash.yunohost.org/appci/app/pluxml) +[![Install PluXml with YunoHost](https://install-app.yunohost.org/install-with-yunohost.png)](https://install-app.yunohost.org/?app=pluxml) + + +*[Lire ce readme en français.](./README_fr.md)* + +![Logo_Pluxml](sources/images/PluXml-logo_transparent.png) + +> *This package allow you to install PluXml quickly and simply on a YunoHost server. +If you don't have YunoHost, please see [here](https://yunohost.org/#/install) to know how to install and enjoy it.* + +## Overview + +[PluXml](https://www.pluxml.org/) : Blog or CMS storing data in XML. + +**Shipped version:** 5.7 + +## Screenshots + +![Screenshot_Pluxml](sources/images/screenshot.jpg) + +## Demo + +* [Official demo](https://demo.pluxml.org/) + +## Configuration + +The admin panel is in https://domain.tld/path/core/admin + +## Documentation + + * Official documentation: https://wiki.pluxml.org/ + * YunoHost documentation: If specific documentation is needed, feel free to contribute. + +## YunoHost specific features + +#### Multi-users support + +Are LDAP and HTTP auth supported? : no +Can the app be used by multiple users? : yes + +#### Supported architectures + +* x86-64b - [![Build Status](https://ci-apps.yunohost.org/ci/logs/pluxml%20%28Community%29.svg)](https://ci-apps.yunohost.org/ci/apps/pluxml/) +* ARMv8-A - [![Build Status](https://ci-apps-arm.yunohost.org/ci/logs/pluxml%20%28Community%29.svg)](https://ci-apps-arm.yunohost.org/ci/apps/pluxml/) +* Jessie x86-64b - [![Build Status](https://ci-stretch.nohost.me/ci/logs/pluxml%20%28Community%29.svg)](https://ci-stretch.nohost.me/ci/apps/pluxml/) + +## Limitations + +* Any known limitations. + +## Additional information + +* Other information you would add about this application + +**More information on the documentation page:** + +https://yunohost.org/packaging_apps + +## Links + + * Report a bug about pluxml_ynh: https://github.com/YunoHost-Apps/pluxml_ynh/issues + * Report a bug about PluXml: https://github.com/pluxml/PluXml/issues + * App website: https://www.pluxml.org/ + * YunoHost website: https://yunohost.org/ + +--- + +Developers info +---------------- + +**Only if you want to use a testing branch for coding, instead of merging directly into master.** +Please do your pull request to the [testing branch](https://framagit.org/toitoinebzh/pluxml_ynh/tree/testing). + +To try the testing branch, please proceed like that. +``` +sudo yunohost app install https://github.com/YunoHost-Apps/pluxml_ynh/tree/testing --debug +or +sudo yunohost app upgrade pluxml -u https://github.com/YunoHost-Apps/pluxml_ynh/tree/testing --debug +``` diff --git a/README_fr.md b/README_fr.md new file mode 100644 index 0000000..e790b66 --- /dev/null +++ b/README_fr.md @@ -0,0 +1,83 @@ +# Package PluXml pour Yunohost + +[![Integration level](https://dash.yunohost.org/integration/pluxml.svg)](https://dash.yunohost.org/appci/app/pluxml) +[![Install PluXml with YunoHost](https://install-app.yunohost.org/install-with-yunohost.png)](https://install-app.yunohost.org/?app=pluxml) + + +*[Read this readme in english.](./README.md)* + +![Logo_Pluxml](sources/images/PluXml-logo_transparent.png) + + +> *Ce package vous permet d'installer PluXml rapidement et simplement sur un serveur Yunohost. +Si vous n'avez pas YunoHost, regardez [ici](https://yunohost.org/#/install) pour savoir comment l'installer et en profiter.* + +## Vue d'ensemble + +[PluXml](https://www.pluxml.org/) : Blog ou CMS à l'Xml. + +**Version incluse:** 5.7 + +## Captures d'écran + +![Screenshot_Pluxml](sources/images/screenshot.jpg) + +## Démo + +* [Official demo](https://demo.pluxml.org/) + +## Configuration + +Le panneau d'administration est accessible via https://domain.tld/path/core/admin + +## Documentation + + * Documentation officielle: https://wiki.pluxml.org/ + * Documentation YunoHost: Si une documentation spécifique est nécessaire, n'hésitez pas à contribuer. + +## Caractéristiques spécifiques YunoHost + +#### Support multi-utilisateurs + +L'authentification LDAP et HTTP est-elle prise en charge? : non +L'application peut-elle être utilisée par plusieurs utilisateurs? : oui + +#### Supported architectures + +* x86-64b - [![Build Status](https://ci-apps.yunohost.org/ci/logs/pluxml%20%28Community%29.svg)](https://ci-apps.yunohost.org/ci/apps/pluxml/) +* ARMv8-A - [![Build Status](https://ci-apps-arm.yunohost.org/ci/logs/pluxml%20%28Community%29.svg)](https://ci-apps-arm.yunohost.org/ci/apps/pluxml/) +* Jessie x86-64b - [![Build Status](https://ci-stretch.nohost.me/ci/logs/pluxml%20%28Community%29.svg)](https://ci-stretch.nohost.me/ci/apps/pluxml/) + +## Limitations + +* Limitations connues. + +## Informations additionnelles + +* Autres informations à ajouter sur cette application + +**Plus d'informations sur la page de documentation:** + +https://yunohost.org/packaging_apps + +## Links + + * Signaler un bug sur pluxml_ynh: https://github.com/YunoHost-Apps/pluxml_ynh/issues + * Signaler un bug sur PluXml: https://github.com/pluxml/PluXml/issues + * Site de l'application: https://www.pluxml.org/ + * Site web YunoHost: https://yunohost.org/ + +--- + +Informations pour les développeurs +---------------- + +**Seulement si vous voulez utiliser une branche de test pour le codage, au lieu de fusionner directement dans la banche principale.** +Merci de faire vos pull request sur la [branche testing](https://framagit.org/toitoinebzh/pluxml_ynh/tree/testing ). + +Pour essayer la branche testing, procédez comme suit. +``` +sudo yunohost app install https://github.com/YunoHost-Apps/pluxml_ynh/tree/testing --debug +ou +sudo yunohost app upgrade pluxml -u https://github.com/YunoHost-Apps/pluxml_ynhtree/testing --debug +``` diff --git a/check_process b/check_process new file mode 100644 index 0000000..3a9d7c7 --- /dev/null +++ b/check_process @@ -0,0 +1,45 @@ +# See here for more information +# https://github.com/YunoHost/package_check#syntax-check_process-file + +# Move this file from check_process.default to check_process when you have filled it. + +;; Test complet + ; Manifest + domain="domain.tld" (DOMAIN) + path="/path" (PATH) + admin="john" (USER) + language="fr" + is_public=1 (PUBLIC|public=1|private=0) + password="pass" + port="666" (PORT) + ; Checks + pkg_linter=1 + setup_sub_dir=1 + setup_root=1 + setup_nourl=0 + setup_private=1 + setup_public=1 + upgrade=1 + backup_restore=1 + multi_instance=1 + incorrect_path=1 + port_already_use=1 + change_url=1 +;;; Level +# The level 4, 8, 9 and 10 shouldn't be fixed at auto, because they don't be tested by the script and they need a manuel check. + Level 1=auto + Level 2=auto + Level 3=auto +# Level 4: If the app supports LDAP and SSOwat, turn level 4 to '1' and add a link to an issue or a part of your code to show it. +# If the app does not use LDAP nor SSOwat, and can't use them, turn level 4 to 'na' and explain as well. + # PluXml does not support LDAP/SSOwat > Level4 set to na + Level 4=na + Level 5=auto + Level 6=auto + Level 7=auto + Level 8=0 + Level 9=0 + Level 10=0 +;;; Options +Email= +Notification=none diff --git a/conf/app.src b/conf/app.src new file mode 100644 index 0000000..80e0a8a --- /dev/null +++ b/conf/app.src @@ -0,0 +1,6 @@ +SOURCE_URL=https://github.com/pluxml/PluXml/archive/v5.7.zip +SOURCE_SUM=e13cf839d01a0c611c83943dce6deb3e0cad5ef81996830994aed6f29f52d7c1 +SOURCE_SUM_PRG=sha256sum +SOURCE_FORMAT=zip +SOURCE_IN_SUBDIR=true +SOURCE_FILENAME= diff --git a/conf/nginx.conf b/conf/nginx.conf new file mode 100644 index 0000000..f2277ea --- /dev/null +++ b/conf/nginx.conf @@ -0,0 +1,33 @@ +#sub_path_only rewrite ^__PATH__$ __PATH__/ permanent; +location __PATH__/ { + + # Path to source + alias __FINALPATH__/ ; + + # Force usage of https + if ($scheme = http) { + rewrite ^ https://$server_name$request_uri? permanent; + } + +### Example PHP configuration (remove it if not used) + index index.php; + + # Common parameter to increase upload size limit in conjunction with dedicated php-fpm file + #client_max_body_size 50M; + + try_files $uri $uri/ index.php; + location ~ [^/]\.php(/|$) { + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + fastcgi_pass unix:/var/run/php/php7.0-fpm-__NAME__.sock; + + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param REMOTE_USER $remote_user; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param SCRIPT_FILENAME $request_filename; + } +### End of PHP configuration part + + # Include SSOWAT user panel. + include conf.d/yunohost_panel.conf.inc; +} diff --git a/conf/php-fpm.conf b/conf/php-fpm.conf new file mode 100644 index 0000000..ab5dca9 --- /dev/null +++ b/conf/php-fpm.conf @@ -0,0 +1,430 @@ +; Start a new pool named 'www'. +; the variable $pool can be used in any directive and will be replaced by the +; pool name ('www' here) +[__NAMETOCHANGE__] + +; Per pool prefix +; It only applies on the following directives: +; - 'access.log' +; - 'slowlog' +; - 'listen' (unixsocket) +; - 'chroot' +; - 'chdir' +; - 'php_values' +; - 'php_admin_values' +; When not set, the global prefix (or /usr) applies instead. +; Note: This directive can also be relative to the global prefix. +; Default Value: none +;prefix = /path/to/pools/$pool + +; Unix user/group of processes +; Note: The user is mandatory. If the group is not set, the default user's group +; will be used. +user = __USER__ +group = __USER__ + +; The address on which to accept FastCGI requests. +; Valid syntaxes are: +; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on +; a specific port; +; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on +; a specific port; +; 'port' - to listen on a TCP socket to all addresses +; (IPv6 and IPv4-mapped) on a specific port; +; '/path/to/unix/socket' - to listen on a unix socket. +; Note: This value is mandatory. +listen = /var/run/php/php7.0-fpm-__NAMETOCHANGE__.sock + +; Set listen(2) backlog. +; Default Value: 511 (-1 on FreeBSD and OpenBSD) +;listen.backlog = 511 + +; Set permissions for unix socket, if one is used. In Linux, read/write +; permissions must be set in order to allow connections from a web server. Many +; BSD-derived systems allow connections regardless of permissions. +; Default Values: user and group are set as the running user +; mode is set to 0660 +listen.owner = www-data +listen.group = www-data +;listen.mode = 0660 +; When POSIX Access Control Lists are supported you can set them using +; these options, value is a comma separated list of user/group names. +; When set, listen.owner and listen.group are ignored +;listen.acl_users = +;listen.acl_groups = + +; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect. +; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original +; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address +; must be separated by a comma. If this value is left blank, connections will be +; accepted from any ip address. +; Default Value: any +;listen.allowed_clients = 127.0.0.1 + +; Specify the nice(2) priority to apply to the pool processes (only if set) +; The value can vary from -19 (highest priority) to 20 (lower priority) +; Note: - It will only work if the FPM master process is launched as root +; - The pool processes will inherit the master process priority +; unless it specified otherwise +; Default Value: no set +; process.priority = -19 + +; Set the process dumpable flag (PR_SET_DUMPABLE prctl) even if the process user +; or group is differrent than the master process user. It allows to create process +; core dump and ptrace the process for the pool user. +; Default Value: no +; process.dumpable = yes + +; Choose how the process manager will control the number of child processes. +; Possible Values: +; static - a fixed number (pm.max_children) of child processes; +; dynamic - the number of child processes are set dynamically based on the +; following directives. With this process management, there will be +; always at least 1 children. +; pm.max_children - the maximum number of children that can +; be alive at the same time. +; pm.start_servers - the number of children created on startup. +; pm.min_spare_servers - the minimum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is less than this +; number then some children will be created. +; pm.max_spare_servers - the maximum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is greater than this +; number then some children will be killed. +; ondemand - no children are created at startup. Children will be forked when +; new requests will connect. The following parameter are used: +; pm.max_children - the maximum number of children that +; can be alive at the same time. +; pm.process_idle_timeout - The number of seconds after which +; an idle process will be killed. +; Note: This value is mandatory. +pm = dynamic + +; The number of child processes to be created when pm is set to 'static' and the +; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. +; This value sets the limit on the number of simultaneous requests that will be +; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. +; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP +; CGI. The below defaults are based on a server without much resources. Don't +; forget to tweak pm.* to fit your needs. +; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' +; Note: This value is mandatory. +pm.max_children = 5 + +; The number of child processes created on startup. +; Note: Used only when pm is set to 'dynamic' +; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 +pm.start_servers = 2 + +; The desired minimum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.min_spare_servers = 1 + +; The desired maximum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.max_spare_servers = 3 + +; The number of seconds after which an idle process will be killed. +; Note: Used only when pm is set to 'ondemand' +; Default Value: 10s +;pm.process_idle_timeout = 10s; + +; The number of requests each child process should execute before respawning. +; This can be useful to work around memory leaks in 3rd party libraries. For +; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. +; Default Value: 0 +;pm.max_requests = 500 + +; The URI to view the FPM status page. If this value is not set, no URI will be +; recognized as a status page. It shows the following informations: +; pool - the name of the pool; +; process manager - static, dynamic or ondemand; +; start time - the date and time FPM has started; +; start since - number of seconds since FPM has started; +; accepted conn - the number of request accepted by the pool; +; listen queue - the number of request in the queue of pending +; connections (see backlog in listen(2)); +; max listen queue - the maximum number of requests in the queue +; of pending connections since FPM has started; +; listen queue len - the size of the socket queue of pending connections; +; idle processes - the number of idle processes; +; active processes - the number of active processes; +; total processes - the number of idle + active processes; +; max active processes - the maximum number of active processes since FPM +; has started; +; max children reached - number of times, the process limit has been reached, +; when pm tries to start more children (works only for +; pm 'dynamic' and 'ondemand'); +; Value are updated in real time. +; Example output: +; pool: www +; process manager: static +; start time: 01/Jul/2011:17:53:49 +0200 +; start since: 62636 +; accepted conn: 190460 +; listen queue: 0 +; max listen queue: 1 +; listen queue len: 42 +; idle processes: 4 +; active processes: 11 +; total processes: 15 +; max active processes: 12 +; max children reached: 0 +; +; By default the status page output is formatted as text/plain. Passing either +; 'html', 'xml' or 'json' in the query string will return the corresponding +; output syntax. Example: +; http://www.foo.bar/status +; http://www.foo.bar/status?json +; http://www.foo.bar/status?html +; http://www.foo.bar/status?xml +; +; By default the status page only outputs short status. Passing 'full' in the +; query string will also return status for each pool process. +; Example: +; http://www.foo.bar/status?full +; http://www.foo.bar/status?json&full +; http://www.foo.bar/status?html&full +; http://www.foo.bar/status?xml&full +; The Full status returns for each process: +; pid - the PID of the process; +; state - the state of the process (Idle, Running, ...); +; start time - the date and time the process has started; +; start since - the number of seconds since the process has started; +; requests - the number of requests the process has served; +; request duration - the duration in µs of the requests; +; request method - the request method (GET, POST, ...); +; request URI - the request URI with the query string; +; content length - the content length of the request (only with POST); +; user - the user (PHP_AUTH_USER) (or '-' if not set); +; script - the main script called (or '-' if not set); +; last request cpu - the %cpu the last request consumed +; it's always 0 if the process is not in Idle state +; because CPU calculation is done when the request +; processing has terminated; +; last request memory - the max amount of memory the last request consumed +; it's always 0 if the process is not in Idle state +; because memory calculation is done when the request +; processing has terminated; +; If the process is in Idle state, then informations are related to the +; last request the process has served. Otherwise informations are related to +; the current request being served. +; Example output: +; ************************ +; pid: 31330 +; state: Running +; start time: 01/Jul/2011:17:53:49 +0200 +; start since: 63087 +; requests: 12808 +; request duration: 1250261 +; request method: GET +; request URI: /test_mem.php?N=10000 +; content length: 0 +; user: - +; script: /home/fat/web/docs/php/test_mem.php +; last request cpu: 0.00 +; last request memory: 0 +; +; Note: There is a real-time FPM status monitoring sample web page available +; It's available in: /usr/share/php/7.0/fpm/status.html +; +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +;pm.status_path = /status + +; The ping URI to call the monitoring page of FPM. If this value is not set, no +; URI will be recognized as a ping page. This could be used to test from outside +; that FPM is alive and responding, or to +; - create a graph of FPM availability (rrd or such); +; - remove a server from a group if it is not responding (load balancing); +; - trigger alerts for the operating team (24/7). +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +;ping.path = /ping + +; This directive may be used to customize the response of a ping request. The +; response is formatted as text/plain with a 200 response code. +; Default Value: pong +;ping.response = pong + +; The access log file +; Default: not set +;access.log = log/$pool.access.log + +; The access log format. +; The following syntax is allowed +; %%: the '%' character +; %C: %CPU used by the request +; it can accept the following format: +; - %{user}C for user CPU only +; - %{system}C for system CPU only +; - %{total}C for user + system CPU (default) +; %d: time taken to serve the request +; it can accept the following format: +; - %{seconds}d (default) +; - %{miliseconds}d +; - %{mili}d +; - %{microseconds}d +; - %{micro}d +; %e: an environment variable (same as $_ENV or $_SERVER) +; it must be associated with embraces to specify the name of the env +; variable. Some exemples: +; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e +; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e +; %f: script filename +; %l: content-length of the request (for POST request only) +; %m: request method +; %M: peak of memory allocated by PHP +; it can accept the following format: +; - %{bytes}M (default) +; - %{kilobytes}M +; - %{kilo}M +; - %{megabytes}M +; - %{mega}M +; %n: pool name +; %o: output header +; it must be associated with embraces to specify the name of the header: +; - %{Content-Type}o +; - %{X-Powered-By}o +; - %{Transfert-Encoding}o +; - .... +; %p: PID of the child that serviced the request +; %P: PID of the parent of the child that serviced the request +; %q: the query string +; %Q: the '?' character if query string exists +; %r: the request URI (without the query string, see %q and %Q) +; %R: remote IP address +; %s: status (response code) +; %t: server time the request was received +; it can accept a strftime(3) format: +; %d/%b/%Y:%H:%M:%S %z (default) +; The strftime(3) format must be encapsuled in a %{}t tag +; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t +; %T: time the log has been written (the request has finished) +; it can accept a strftime(3) format: +; %d/%b/%Y:%H:%M:%S %z (default) +; The strftime(3) format must be encapsuled in a %{}t tag +; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t +; %u: remote user +; +; Default: "%R - %u %t \"%m %r\" %s" +;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%" + +; The log file for slow requests +; Default Value: not set +; Note: slowlog is mandatory if request_slowlog_timeout is set +;slowlog = log/$pool.log.slow + +; The timeout for serving a single request after which a PHP backtrace will be +; dumped to the 'slowlog' file. A value of '0s' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +;request_slowlog_timeout = 0 + +; The timeout for serving a single request after which the worker process will +; be killed. This option should be used when the 'max_execution_time' ini option +; does not stop script execution for some reason. A value of '0' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +request_terminate_timeout = 1d + +; Set open file descriptor rlimit. +; Default Value: system defined value +;rlimit_files = 1024 + +; Set max core size rlimit. +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_core = 0 + +; Chroot to this directory at the start. This value must be defined as an +; absolute path. When this value is not set, chroot is not used. +; Note: you can prefix with '$prefix' to chroot to the pool prefix or one +; of its subdirectories. If the pool prefix is not set, the global prefix +; will be used instead. +; Note: chrooting is a great security feature and should be used whenever +; possible. However, all PHP paths will be relative to the chroot +; (error_log, sessions.save_path, ...). +; Default Value: not set +;chroot = + +; Chdir to this directory at the start. +; Note: relative path can be used. +; Default Value: current directory or / when chroot +chdir = __FINALPATH__ + +; Redirect worker stdout and stderr into main error log. If not set, stdout and +; stderr will be redirected to /dev/null according to FastCGI specs. +; Note: on highloaded environement, this can cause some delay in the page +; process time (several ms). +; Default Value: no +;catch_workers_output = yes + +; Clear environment in FPM workers +; Prevents arbitrary environment variables from reaching FPM worker processes +; by clearing the environment in workers before env vars specified in this +; pool configuration are added. +; Setting to "no" will make all environment variables available to PHP code +; via getenv(), $_ENV and $_SERVER. +; Default Value: yes +;clear_env = no + +; Limits the extensions of the main script FPM will allow to parse. This can +; prevent configuration mistakes on the web server side. You should only limit +; FPM to .php extensions to prevent malicious users to use other extensions to +; execute php code. +; Note: set an empty value to allow all extensions. +; Default Value: .php +;security.limit_extensions = .php .php3 .php4 .php5 .php7 + +; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from +; the current environment. +; Default Value: clean env +;env[HOSTNAME] = $HOSTNAME +;env[PATH] = /usr/local/bin:/usr/bin:/bin +;env[TMP] = /tmp +;env[TMPDIR] = /tmp +;env[TEMP] = /tmp + +; Additional php.ini defines, specific to this pool of workers. These settings +; overwrite the values previously defined in the php.ini. The directives are the +; same as the PHP SAPI: +; php_value/php_flag - you can set classic ini defines which can +; be overwritten from PHP call 'ini_set'. +; php_admin_value/php_admin_flag - these directives won't be overwritten by +; PHP call 'ini_set' +; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. + +; Defining 'extension' will load the corresponding shared extension from +; extension_dir. Defining 'disable_functions' or 'disable_classes' will not +; overwrite previously defined php.ini values, but will append the new value +; instead. + +; Note: path INI options can be relative and will be expanded with the prefix +; (pool, global or /usr) + +; Default Value: nothing is defined by default except the values in php.ini and +; specified at startup with the -d argument +;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com +;php_flag[display_errors] = off +;php_admin_value[error_log] = /var/log/fpm-php.www.log +;php_admin_flag[log_errors] = on +;php_admin_value[memory_limit] = 32M + +; Common values to change to increase file upload limit +; php_admin_value[upload_max_filesize] = 50M +; php_admin_value[post_max_size] = 50M +; php_admin_flag[mail.add_x_header] = Off + +; Other common parameters +; php_admin_value[max_execution_time] = 600 +; php_admin_value[max_input_time] = 300 +; php_admin_value[memory_limit] = 256M +; php_admin_flag[short_open_tag] = On diff --git a/conf/systemd.service b/conf/systemd.service new file mode 100644 index 0000000..76cdf64 --- /dev/null +++ b/conf/systemd.service @@ -0,0 +1,13 @@ +[Unit] +Description=Small description of the service +After=network.target + +[Service] +Type=simple +User=__APP__ +Group=__APP__ +WorkingDirectory=__FINALPATH__/ +ExecStart=__FINALPATH__/script >> /var/log/__APP__/__APP__.log 2>&1 + +[Install] +WantedBy=multi-user.target diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..598cbb1 --- /dev/null +++ b/manifest.json @@ -0,0 +1,85 @@ +{ + "name": "PluXml", + "id": "pluxml", + "packaging_format": 1, + "description": { + "en": "Blog or CMS storing data in XML.", + "fr": "Blog ou CMS à l'Xml." + }, + "version": "5.7", + "url": "https://www.pluxml.org/", + "license": "GPL-2.0-only", + "maintainer": { + "name": "Antoine", + "email": "antoine@miaou.org", + "url": "https://miaou.org" + }, + "requirements": { + "yunohost": ">= 3.1.0" + }, + "multi_instance": true, + "services": [ + "nginx", + "php7.0-fpm" + ], + "arguments": { + "install" : [ + { + "name": "domain", + "type": "domain", + "ask": { + "en": "Choose a domain name for PluXml", + "fr": "Choisissez un nom de domaine pour PluXml" + }, + "example": "example.com" + }, + { + "name": "path", + "type": "path", + "ask": { + "en": "Choose a path for PluXml", + "fr": "Choisissez un chemin pour PluXml" + }, + "example": "/pluxml", + "default": "/pluxml" + }, + { + "name": "admin", + "type": "user", + "ask": { + "en": "Choose an admin user for PluXml", + "fr": "Choisissez l’administrateur de PluXml" + }, + "example": "John" + }, + { + "name": "password", + "type": "password", + "ask": { + "en": "Choose an admin password for PluXml", + "fr": "Choisissez un mot de passe administrateur pour PluXml" + }, + "example": "super_secret_password" + }, + { + "name": "is_public", + "type": "boolean", + "ask": { + "en": "Is it a public application?", + "fr": "Est-ce une application publique ?" + }, + "default": true + }, + { + "name": "language", + "type": "string", + "ask": { + "en": "Default language", + "fr": "Langue par défaut" + }, + "choices": ["de","en","es","fr","it","nl","pl","pt","po","ro","ru"], + "default": "en" + } + ] + } +} diff --git a/scripts/_common.sh b/scripts/_common.sh new file mode 100644 index 0000000..bb04a03 --- /dev/null +++ b/scripts/_common.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# ============= FUTURE YUNOHOST HELPER ============= +# Delete a file checksum from the app settings +# +# $app should be defined when calling this helper +# +# usage: ynh_remove_file_checksum file +# | arg: file - The file for which the checksum will be deleted +ynh_delete_file_checksum () { + local checksum_setting_name=checksum_${1//[\/ ]/_} # Replace all '/' and ' ' by '_' + ynh_app_setting_delete $app $checksum_setting_name +} \ No newline at end of file diff --git a/scripts/backup b/scripts/backup new file mode 100755 index 0000000..c65b227 --- /dev/null +++ b/scripts/backup @@ -0,0 +1,77 @@ +#!/bin/bash + +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source ../settings/scripts/_common.sh +source /usr/share/yunohost/helpers + +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +ynh_clean_setup () { + ### Remove this function if there's nothing to clean before calling the remove script. + true +} +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors + +#================================================= +# LOAD SETTINGS +#================================================= + +app=$YNH_APP_INSTANCE_NAME + +final_path=$(ynh_app_setting_get $app final_path) +domain=$(ynh_app_setting_get $app domain) +#db_name=$(ynh_app_setting_get $app db_name) + +#================================================= +# STANDARD BACKUP STEPS +#================================================= +# BACKUP THE APP MAIN DIR +#================================================= + +ynh_backup "$final_path" + +#================================================= +# BACKUP THE NGINX CONFIGURATION +#================================================= + +ynh_backup "/etc/nginx/conf.d/$domain.d/$app.conf" + +#================================================= +# BACKUP THE PHP-FPM CONFIGURATION +#================================================= + +ynh_backup "/etc/php/7.0/fpm/pool.d/$app.conf" + +#================================================= +# BACKUP THE MYSQL DATABASE +#================================================= + +#ynh_mysql_dump_db "$db_name" > db.sql + +#================================================= +# SPECIFIC BACKUP +#================================================= +# BACKUP LOGROTATE +#================================================= + +#ynh_backup "/etc/logrotate.d/$app" + +#================================================= +# BACKUP SYSTEMD +#================================================= + +ynh_backup "/etc/systemd/system/$app.service" + +#================================================= +# BACKUP A CRON FILE +#================================================= + +#ynh_backup "/etc/cron.d/$app" diff --git a/scripts/change_url b/scripts/change_url new file mode 100644 index 0000000..f71fc77 --- /dev/null +++ b/scripts/change_url @@ -0,0 +1,102 @@ +#!/bin/bash + +#================================================= +# GENERIC STARTING +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source _common.sh +source /usr/share/yunohost/helpers + +#================================================= +# RETRIEVE ARGUMENTS +#================================================= + +old_domain=$YNH_APP_OLD_DOMAIN +old_path=$YNH_APP_OLD_PATH + +new_domain=$YNH_APP_NEW_DOMAIN +new_path=$YNH_APP_NEW_PATH + +app=$YNH_APP_INSTANCE_NAME + +#================================================= +# LOAD SETTINGS +#================================================= + +# Needed for helper "ynh_add_nginx_config" +final_path=$(ynh_app_setting_get $app final_path) + +# Add settings here as needed by your application +#db_name=$(ynh_app_setting_get "$app" db_name) +#db_pwd=$(ynh_app_setting_get $app db_pwd) + +#================================================= +# CHECK THE SYNTAX OF THE PATHS +#================================================= + +test -n "$old_path" || old_path="/" +test -n "$new_path" || new_path="/" +new_path=$(ynh_normalize_url_path $new_path) +old_path=$(ynh_normalize_url_path $old_path) + +#================================================= +# CHECK WHICH PARTS SHOULD BE CHANGED +#================================================= + +change_domain=0 +if [ "$old_domain" != "$new_domain" ] +then + change_domain=1 +fi + +change_path=0 +if [ "$old_path" != "$new_path" ] +then + change_path=1 +fi + +#================================================= +# STANDARD MODIFICATIONS +#================================================= +# MODIFY URL IN NGINX CONF +#================================================= + +nginx_conf_path=/etc/nginx/conf.d/$old_domain.d/$app.conf + +# Change the path in the nginx config file +if [ $change_path -eq 1 ] +then + # Make a backup of the original nginx config file if modified + ynh_backup_if_checksum_is_different "$nginx_conf_path" + # Set global variables for nginx helper + domain="$old_domain" + path_url="$new_path" + # Create a dedicated nginx config + ynh_add_nginx_config +fi + +# Change the domain for nginx +if [ $change_domain -eq 1 ] +then + # Delete file checksum for the old conf file location + ynh_delete_file_checksum "$nginx_conf_path" + mv $nginx_conf_path /etc/nginx/conf.d/$new_domain.d/$app.conf + # Store file checksum for the new config file location + ynh_store_file_checksum "/etc/nginx/conf.d/$new_domain.d/$app.conf" +fi + +#================================================= +# SPECIFIC MODIFICATIONS +#================================================= +# ... +#================================================= + +#================================================= +# GENERIC FINALISATION +#================================================= +# RELOAD NGINX +#================================================= + +systemctl reload nginx diff --git a/scripts/install b/scripts/install new file mode 100755 index 0000000..769619c --- /dev/null +++ b/scripts/install @@ -0,0 +1,334 @@ +#!/bin/bash + +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source _common.sh +source /usr/share/yunohost/helpers + +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +ynh_clean_setup () { + ### Remove this function if there's nothing to clean before calling the remove script. + true +} +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors + +#================================================= +# RETRIEVE ARGUMENTS FROM THE MANIFEST +#================================================= + +domain=$YNH_APP_ARG_DOMAIN +path_url=$YNH_APP_ARG_PATH +admin=$YNH_APP_ARG_ADMIN +is_public=$YNH_APP_ARG_IS_PUBLIC +language=$YNH_APP_ARG_LANGUAGE +password=$YNH_APP_ARG_PASSWORD + +### If it's a multi-instance app, meaning it can be installed several times independently +### The id of the app as stated in the manifest is available as $YNH_APP_ID +### The instance number is available as $YNH_APP_INSTANCE_NUMBER (equals "1", "2", ...) +### The app instance name is available as $YNH_APP_INSTANCE_NAME +### - the first time the app is installed, YNH_APP_INSTANCE_NAME = ynhexample +### - the second time the app is installed, YNH_APP_INSTANCE_NAME = ynhexample__2 +### - ynhexample__{N} for the subsequent installations, with N=3,4, ... +### The app instance name is probably what interests you most, since this is +### guaranteed to be unique. This is a good unique identifier to define installation path, +### db names, ... +app=$YNH_APP_INSTANCE_NAME + +#================================================= +# CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS +#================================================= +ynh_print_info "Validating arguments ..." + +### If the app uses nginx as web server (written in HTML/PHP in most cases), the final path should be "/var/www/$app". +### If the app provides an internal web server (or uses another application server such as uwsgi), the final path should be "/opt/yunohost/$app" +final_path=/var/www/$app +test ! -e "$final_path" || ynh_die "This path already contains a folder" + +# Normalize the url path syntax +path_url=$(ynh_normalize_url_path $path_url) + +# Register (book) web path +ynh_webpath_register $app $domain $path_url + +#================================================= +# STORE SETTINGS FROM MANIFEST +#================================================= + +ynh_print_info "Starting PluXml app installation ..." +ynh_app_setting_set $app domain $domain +ynh_app_setting_set $app path $path_url +ynh_app_setting_set $app admin $admin +ynh_app_setting_set $app is_public $is_public +ynh_app_setting_set $app language $language + +#================================================= +# STANDARD MODIFICATIONS +#================================================= +# FIND AND OPEN A PORT +#================================================= + +### Use these lines if you have to open a port for the application +### `ynh_find_port` will find the first available port starting from the given port. +### If you're not using these lines: +### - Remove the section "CLOSE A PORT" in the remove script + +ynh_print_info "Configuring firewall ..." +## Find a free port +#port=$(ynh_find_port 8095) +## Open this port +#yunohost firewall allow --no-upnp TCP $port 2>&1 +#ynh_app_setting_set $app port $port + +#================================================= +# INSTALL DEPENDENCIES +#================================================= + +### `ynh_install_app_dependencies` allows you to add any "apt" dependencies to the package. +### Those deb packages will be installed as dependencies of this package. +### If you're not using this helper: +### - Remove the section "REMOVE DEPENDENCIES" in the remove script +### - As well as the section "REINSTALL DEPENDENCIES" in the restore script +### - And the section "UPGRADE DEPENDENCIES" in the upgrade script + +ynh_print_info "Installing dependencies ..." +#ynh_install_app_dependencies deb1 deb2 + + +#================================================= +# CREATE A MYSQL DATABASE +#================================================= + +### Use these lines if you need a database for the application. +### `ynh_mysql_setup_db` will create a database, an associated user and a ramdom password. +### The password will be stored as 'mysqlpwd' into the app settings, +### and will be available as $db_pwd +### If you're not using these lines: +### - Remove the section "BACKUP THE MYSQL DATABASE" in the backup script +### - Remove also the section "REMOVE THE MYSQL DATABASE" in the remove script +### - As well as the section "RESTORE THE MYSQL DATABASE" in the restore script + +ynh_print_info "Initializing database ..." +#db_name=$(ynh_sanitize_dbid $app) +#ynh_app_setting_set $app db_name $db_name +#ynh_mysql_setup_db $db_name $db_name + +#================================================= +# DOWNLOAD, CHECK AND UNPACK SOURCE +#================================================= + +### `ynh_setup_source` is used to install an app from a zip or tar.gz file, +### downloaded from an upstream source, like a git repository. +### `ynh_setup_source` use the file conf/app.src + +ynh_print_info "Setting up source files ..." +ynh_app_setting_set $app final_path $final_path +# Download, check integrity, uncompress and patch the source from app.src +ynh_setup_source "$final_path" + +#================================================= +# NGINX CONFIGURATION +#================================================= + +### `ynh_add_nginx_config` will use the file conf/nginx.conf + +ynh_print_info "Configuring nginx ..." +# Create a dedicated nginx config +ynh_add_nginx_config + +#================================================= +# CREATE DEDICATED USER +#================================================= + +# Create a system user +ynh_print_info "Configuring system user ..." +ynh_system_user_create $app + +#================================================= +# PHP-FPM CONFIGURATION +#================================================= + +### `ynh_add_fpm_config` is used to set up a PHP config. +### You can remove it if your app doesn't use PHP. +### `ynh_add_fpm_config` will use the files conf/php-fpm.conf and conf/php-fpm.ini +### If you're not using these lines: +### - You can remove these files in conf/. +### - Remove the section "BACKUP THE PHP-FPM CONFIGURATION" in the backup script +### - Remove also the section "REMOVE PHP-FPM CONFIGURATION" in the remove script +### - As well as the section "RESTORE THE PHP-FPM CONFIGURATION" in the restore script +### With the reload at the end of the script. +### - And the section "PHP-FPM CONFIGURATION" in the upgrade script + +# Create a dedicated php-fpm config +ynh_print_info "Configuring php-fpm ..." +ynh_add_fpm_config + +#================================================= +# SPECIFIC SETUP +#================================================= +# ... +#================================================= + +#================================================= +# SETUP SYSTEMD +#================================================= + +### `ynh_systemd_config` is used to configure a systemd script for an app. +### It can be used for apps that use sysvinit (with adaptation) or systemd. +### Have a look at the app to be sure this app needs a systemd script. +### `ynh_systemd_config` will use the file conf/systemd.service +### If you're not using these lines: +### - You can remove those files in conf/. +### - Remove the section "BACKUP SYSTEMD" in the backup script +### - Remove also the section "STOP AND REMOVE SERVICE" in the remove script +### - As well as the section "RESTORE SYSTEMD" in the restore script +### - And the section "SETUP SYSTEMD" in the upgrade script + +# Create a dedicated systemd config +ynh_print_info "Configuring systemd service ..." +ynh_add_systemd_config + +#================================================= +# SETUP APPLICATION WITH CURL +#================================================= + +### Use these lines only if the app installation needs to be finalized through +### web forms. We generally don't want to ask the final user, +### so we're going to use curl to automatically fill the fields and submit the +### forms. + +# Set right permissions for curl install +chown -R $app: $final_path + +# Set the app as temporarily public for curl call +ynh_print_info "Configuring ssowat ..." +ynh_app_setting_set $app skipped_uris "/" +# Reload SSOwat config +yunohost app ssowatconf + +# Reload Nginx +systemctl reload nginx + +# Installation with curl +ynh_print_info "Finalizing install ..." +#ynh_local_curl "/INSTALL_PATH" "key1=value1" "key2=value2" "key3=value3" +## === modif perso ==== +ynh_local_curl "/install.php" "default_lang=$language" "install=Installer" "name=$admin" "login=$admin" "pwd=$password" "pwd2=$password" +## === modif perso ==== + +# Remove the public access +if [ $is_public -eq 0 ] +then + ynh_app_setting_delete $app skipped_uris +fi + +#================================================= +# MODIFY A CONFIG FILE +#================================================= + +### `ynh_replace_string` is used to replace a string in a file. +### (It's compatible with sed regular expressions syntax) + +#ynh_replace_string "match_string" "replace_string" "$final_path/CONFIG_FILE" + +#================================================= +# STORE THE CONFIG FILE CHECKSUM +#================================================= + +### `ynh_store_file_checksum` is used to store the checksum of a file. +### That way, during the upgrade script, by using `ynh_backup_if_checksum_is_different`, +### you can make a backup of this file before modifying it again if the admin had modified it. + +# Calculate and store the config file checksum into the app settings +#ynh_store_file_checksum "$final_path/CONFIG_FILE" + +#================================================= +# GENERIC FINALIZATION +#================================================= + +## === modif perso ==== +ynh_print_info "Removing install.php and /update" +ynh_secure_remove ${final_path}/install.php # modif perso +ynh_secure_remove ${final_path}/update # modif perso +## === modif perso ==== + +#================================================= +# SECURE FILES AND DIRECTORIES +#================================================= + +### For security reason, any app should set the permissions to root: before anything else. +### Then, if write authorization is needed, any access should be given only to directories +### that really need such authorization. + +# Set permissions to app files +# chown -R root: $final_path +chown -R "$app":"$app" $final_path # modif perso + +#================================================= +# SETUP LOGROTATE +#================================================= + +### `ynh_use_logrotate` is used to configure a logrotate configuration for the logs of this app. +### Use this helper only if there is effectively a log file for this app. +### If you're not using this helper: +### - Remove the section "BACKUP LOGROTATE" in the backup script +### - Remove also the section "REMOVE LOGROTATE CONFIGURATION" in the remove script +### - As well as the section "RESTORE THE LOGROTATE CONFIGURATION" in the restore script +### - And the section "SETUP LOGROTATE" in the upgrade script + +# Use logrotate to manage application logfile(s) +#ynh_print_info "Configuring log rotation ..." +#ynh_use_logrotate + +#================================================= +# ADVERTISE SERVICE IN ADMIN PANEL +#================================================= + +### `yunohost service add` is a CLI yunohost command to add a service in the admin panel. +### You'll find the service in the 'services' section of YunoHost admin panel. +### This CLI command would be useless if the app does not have any services (systemd or sysvinit) +### If you're not using these lines: +### - You can remove these files in conf/. +### - Remove the section "REMOVE SERVICE FROM ADMIN PANEL" in the remove script +### - As well as the section "ADVERTISE SERVICE IN ADMIN PANEL" in the restore script + +#yunohost service add $app --log "/var/log/$app/$app.log" +# if using yunohost version 3.2 or more in the 'manifest.json', a description can be added +#yunohost service add $app --description "$app daemon for XXX" --log "/var/log/$app/$app.log" + +#================================================= +# SETUP SSOWAT +#================================================= + +# Make app public if necessary +if [ $is_public -eq 1 ] +then + # unprotected_uris allows SSO credentials to be passed anyway. + ynh_app_setting_set $app unprotected_uris "/" +fi + +#================================================= +# RELOAD NGINX +#================================================= + +ynh_print_info "Reloading nginx ..." +systemctl reload nginx + +#================================================= +# SEND A README FOR THE ADMIN +#================================================= + +#message=" +#Congratulations, PluXml has been sucessfully installed on your instance. +#If you are facing an issue or want to improve this app, please open a new issue in this project: https://framagit.org/toitoinebzh/pluxml_ynh +#" + +#ynh_send_readme_to_admin "$message" "$admin" diff --git a/scripts/remove b/scripts/remove new file mode 100755 index 0000000..056c502 --- /dev/null +++ b/scripts/remove @@ -0,0 +1,118 @@ +#!/bin/bash + +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source _common.sh +source /usr/share/yunohost/helpers + +#================================================= +# LOAD SETTINGS +#================================================= + +app=$YNH_APP_INSTANCE_NAME + +domain=$(ynh_app_setting_get $app domain) +port=$(ynh_app_setting_get $app port) +#db_name=$(ynh_app_setting_get $app db_name) +#db_user=$db_name +final_path=$(ynh_app_setting_get $app final_path) + +#================================================= +# STANDARD REMOVE +#================================================= +# REMOVE SERVICE FROM ADMIN PANEL +#================================================= + +# Remove a service from the admin panel, added by `yunohost service add` +if yunohost service status | grep -q $app +then + echo "Remove $app service" + yunohost service remove $app +fi + +#================================================= +# STOP AND REMOVE SERVICE +#================================================= + +# Remove the dedicated systemd config +ynh_remove_systemd_config + +#================================================= +# REMOVE THE MYSQL DATABASE +#================================================= + +# Remove a database if it exists, along with the associated user +#ynh_mysql_remove_db $db_user $db_name + +#================================================= +# REMOVE DEPENDENCIES +#================================================= + +# Remove metapackage and its dependencies +#ynh_remove_app_dependencies + +#================================================= +# REMOVE APP MAIN DIR +#================================================= + +# Remove the app directory securely +ynh_secure_remove "$final_path" + +#================================================= +# REMOVE NGINX CONFIGURATION +#================================================= + +# Remove the dedicated nginx config +ynh_remove_nginx_config + +#================================================= +# REMOVE PHP-FPM CONFIGURATION +#================================================= + +# Remove the dedicated php-fpm config +ynh_remove_fpm_config + +#================================================= +# REMOVE LOGROTATE CONFIGURATION +#================================================= + +# Remove the app-specific logrotate config +#ynh_remove_logrotate + +#================================================= +# CLOSE A PORT +#================================================= + +if yunohost firewall list | grep -q "\- $port$" +then + echo "Close port $port" >&2 + yunohost firewall disallow TCP $port 2>&1 +fi + +#================================================= +# SPECIFIC REMOVE +#================================================= +# REMOVE THE CRON FILE +#================================================= + +# Remove a cron file +#ynh_secure_remove "/etc/cron.d/$app" + +# Remove a directory securely +#ynh_secure_remove "/etc/$app/" + +# Remove the log files +#ynh_secure_remove "/var/log/$app/" + +#================================================= +# GENERIC FINALIZATION +#================================================= +# REMOVE DEDICATED USER +#================================================= + +# Delete a system user +ynh_system_user_delete $app diff --git a/scripts/restore b/scripts/restore new file mode 100755 index 0000000..a2b6382 --- /dev/null +++ b/scripts/restore @@ -0,0 +1,127 @@ +#!/bin/bash + +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source ../settings/scripts/_common.sh +source /usr/share/yunohost/helpers + +#================================================= +# MANAGE SCRIPT FAILURE +#================================================= + +ynh_clean_setup () { + #### Remove this function if there's nothing to clean before calling the remove script. + true +} +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors + +#================================================= +# LOAD SETTINGS +#================================================= + +app=$YNH_APP_INSTANCE_NAME + +domain=$(ynh_app_setting_get $app domain) +path_url=$(ynh_app_setting_get $app path) +final_path=$(ynh_app_setting_get $app final_path) +#db_name=$(ynh_app_setting_get $app db_name) + +#================================================= +# CHECK IF THE APP CAN BE RESTORED +#================================================= + +ynh_webpath_available $domain $path_url \ + || ynh_die "Path not available: ${domain}${path_url}" +test ! -d $final_path \ + || ynh_die "There is already a directory: $final_path " + +#================================================= +# STANDARD RESTORATION STEPS +#================================================= +# RESTORE THE NGINX CONFIGURATION +#================================================= + +ynh_restore_file "/etc/nginx/conf.d/$domain.d/$app.conf" + +#================================================= +# RESTORE THE APP MAIN DIR +#================================================= + +ynh_restore_file "$final_path" + +#================================================= +# RECREATE THE DEDICATED USER +#================================================= + +# Create the dedicated user (if not existing) +ynh_system_user_create $app + +#================================================= +# RESTORE USER RIGHTS +#================================================= + +# Restore permissions on app files +#chown -R root: $final_path +chown -R "$app":"$app" $final_path # modif perso + +#================================================= +# RESTORE THE PHP-FPM CONFIGURATION +#================================================= + +ynh_restore_file "/etc/php/7.0/fpm/pool.d/$app.conf" + +#================================================= +# SPECIFIC RESTORATION +#================================================= +# REINSTALL DEPENDENCIES +#================================================= + +# Define and install dependencies +#ynh_install_app_dependencies deb1 deb2 + +#================================================= +# RESTORE THE MYSQL DATABASE +#================================================= + +#db_pwd=$(ynh_app_setting_get $app mysqlpwd) +#ynh_mysql_setup_db $db_name $db_name $db_pwd +#ynh_mysql_connect_as $db_name $db_pwd $db_name < ./db.sql + +#================================================= +# RESTORE SYSTEMD +#================================================= + +ynh_restore_file "/etc/systemd/system/$app.service" +systemctl enable $app.service + +#================================================= +# ADVERTISE SERVICE IN ADMIN PANEL +#================================================= + +yunohost service add $app --log "/var/log/$app/$app.log" + +#================================================= +# RESTORE THE CRON FILE +#================================================= + +#ynh_restore_file "/etc/cron.d/$app" + +#================================================= +# RESTORE THE LOGROTATE CONFIGURATION +#================================================= + +#ynh_restore_file "/etc/logrotate.d/$app" + +#================================================= +# GENERIC FINALIZATION +#================================================= +# RELOAD NGINX AND PHP-FPM +#================================================= + +systemctl reload php7.0-fpm +systemctl reload nginx diff --git a/scripts/upgrade b/scripts/upgrade new file mode 100755 index 0000000..5ca4889 --- /dev/null +++ b/scripts/upgrade @@ -0,0 +1,176 @@ +#!/bin/bash + +#================================================= +# GENERIC START +#================================================= +# IMPORT GENERIC HELPERS +#================================================= + +source _common.sh +source /usr/share/yunohost/helpers + +#================================================= +# LOAD SETTINGS +#================================================= + +app=$YNH_APP_INSTANCE_NAME + +domain=$(ynh_app_setting_get $app domain) +path_url=$(ynh_app_setting_get $app path) +#admin=$(ynh_app_setting_get $app admin) +is_public=$(ynh_app_setting_get $app is_public) +final_path=$(ynh_app_setting_get $app final_path) +#language=$(ynh_app_setting_get $app language) +#db_name=$(ynh_app_setting_get $app db_name) + +#================================================= +# ENSURE DOWNWARD COMPATIBILITY +#================================================= + +# Fix is_public as a boolean value +if [ "$is_public" = "Yes" ]; then + ynh_app_setting_set $app is_public 1 + is_public=1 +elif [ "$is_public" = "No" ]; then + ynh_app_setting_set $app is_public 0 + is_public=0 +fi + +# If db_name doesn't exist, create it +#if [ -z $db_name ]; then +# db_name=$(ynh_sanitize_dbid $app) +# ynh_app_setting_set $app db_name $db_name +#fi + +# If final_path doesn't exist, create it +if [ -z $final_path ]; then + final_path=/var/www/$app + ynh_app_setting_set $app final_path $final_path +fi + +#================================================= +# BACKUP BEFORE UPGRADE THEN ACTIVE TRAP +#================================================= + +# Backup the current version of the app +ynh_backup_before_upgrade +ynh_clean_setup () { + # restore it if the upgrade fails + ynh_restore_upgradebackup +} +# Exit if an error occurs during the execution of the script +ynh_abort_if_errors + +#================================================= +# CHECK THE PATH +#================================================= + +# Normalize the URL path syntax +path_url=$(ynh_normalize_url_path $path_url) + +#================================================= +# STANDARD UPGRADE STEPS +#================================================= +# DOWNLOAD, CHECK AND UNPACK SOURCE +#================================================= + +# Download, check integrity, uncompress and patch the source from app.src +ynh_setup_source "$final_path" + +#================================================= +# NGINX CONFIGURATION +#================================================= + +# Create a dedicated nginx config +ynh_add_nginx_config + +#================================================= +# UPGRADE DEPENDENCIES +#================================================= + +#ynh_install_app_dependencies deb1 deb2 + +#================================================= +# CREATE DEDICATED USER +#================================================= + +# Create a dedicated user (if not existing) +ynh_system_user_create $app + +#================================================= +# PHP-FPM CONFIGURATION +#================================================= + +# Create a dedicated php-fpm config +ynh_add_fpm_config + +#================================================= +# SPECIFIC UPGRADE +#================================================= +# ... + +## === modif perso ==== +ynh_print_info "Removing install.php and /update" +ynh_secure_remove ${final_path}/install.php # modif perso +ynh_secure_remove ${final_path}/update # modif perso +## === modif perso ==== + +#================================================= + +### Verify the checksum of a file, stored by `ynh_store_file_checksum` in the install script. +### And create a backup of this file if the checksum is different. So the file will be backed up if the admin had modified it. +#ynh_backup_if_checksum_is_different "$final_path/CONFIG_FILE" +# Recalculate and store the checksum of the file for the next upgrade. +#ynh_store_file_checksum "$final_path/CONFIG_FILE" + +#================================================= +# SETUP LOGROTATE +#================================================= + +# Use logrotate to manage app-specific logfile(s) +#ynh_use_logrotate --non-append + +#================================================= +# SETUP SYSTEMD +#================================================= + +# Create a dedicated systemd config +ynh_add_systemd_config + +#================================================= +# GENERIC FINALIZATION +#================================================= +# SECURE FILES AND DIRECTORIES +#================================================= + +# Set permissions on app files +#chown -R root: $final_path +chown -R "$app":"$app" $final_path # modif perso + +#================================================= +# SETUP SSOWAT +#================================================= + +# Make app public if necessary +if [ $is_public -eq 1 ] +then + # unprotected_uris allows SSO credentials to be passed anyway + ynh_app_setting_set $app unprotected_uris "/" +fi + +#================================================= +# RELOAD NGINX +#================================================= + +systemctl reload nginx + +#================================================= +# SEND A README FOR THE ADMIN +#================================================= + +#message=" +#Congratulations, PluXml has been sucessfully removed on your instance. +#If you are facing an issue or want to improve this app, please open a new issue in this project: https://framagit.org/toitoinebzh/pluxml_ynh +#" + +#ynh_send_readme_to_admin "$message" "$admin" \ No newline at end of file diff --git a/sources/extra_files/app/.gitignore b/sources/extra_files/app/.gitignore new file mode 100644 index 0000000..783a4ae --- /dev/null +++ b/sources/extra_files/app/.gitignore @@ -0,0 +1,2 @@ +*~ +*.sw[op] diff --git a/sources/images/PluXml-logo_transparent.png b/sources/images/PluXml-logo_transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..ccb4d96af17ed4d22b4cea2be55c9107da37ef15 GIT binary patch literal 12497 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 WlZ95NdEoCTASlVJ%hkyM!v7yWC#9PJ literal 0 HcmV?d00001 diff --git a/sources/images/screenshot.jpg b/sources/images/screenshot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8fa52febb8c029cd7808090e90b9dd1ae42b74c2 GIT binary patch literal 45831 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 z