diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6973ff6d7..86e65c390 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,7 +8,7 @@ cache: before_script: # add extensions to postgres - - PGPASSWORD=$POSTGRES_PASSWORD psql -U $POSTGRES_USER -h db -c "CREATE EXTENSION IF NOT EXISTS unaccent; CREATE EXTENSION IF NOT EXISTS pg_trgm; CREATE EXTENSION IF NOT EXISTS btree_gist;" + - PGPASSWORD=$POSTGRES_PASSWORD psql -U $POSTGRES_USER -h db -c "CREATE EXTENSION IF NOT EXISTS unaccent; CREATE EXTENSION IF NOT EXISTS pg_trgm;" # Install and run Composer - curl -sS https://getcomposer.org/installer | php - php -d memory_limit=2G composer.phar install diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..1cf094aab --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + chill-bundles + Copyright (C) 2021 Chill Project + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/composer.json b/composer.json index 748a7d862..fb0d2dcd1 100644 --- a/composer.json +++ b/composer.json @@ -58,7 +58,8 @@ "symfony/css-selector": "^5.2", "twig/markdown-extra": "^3.3", "erusev/parsedown": "^1.7", - "symfony/serializer": "^5.2" + "symfony/serializer": "^5.2", + "symfony/webpack-encore-bundle": "^1.11" }, "conflict": { "symfony/symfony": "*" diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php index 3b5517a70..38ca08d1f 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php @@ -23,16 +23,20 @@ namespace Chill\ActivityBundle\Controller; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Privacy\PrivacyEvent; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Form\Form; use Symfony\Component\HttpFoundation\Request; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Core\Role\Role; use Chill\ActivityBundle\Entity\Activity; -use Chill\PersonBundle\Entity\Person; use Chill\ActivityBundle\Form\ActivityType; +use Symfony\Component\Serializer\SerializerInterface; /** * Class ActivityController @@ -41,216 +45,227 @@ use Chill\ActivityBundle\Form\ActivityType; */ class ActivityController extends AbstractController { + protected EventDispatcherInterface $eventDispatcher; - /** - * @var EventDispatcherInterface - */ - protected $eventDispatcher; + protected AuthorizationHelper $authorizationHelper; - /** - * @var AuthorizationHelper - */ - protected $authorizationHelper; + protected LoggerInterface $logger; - /** - * @var LoggerInterface - */ - protected $logger; + protected SerializerInterface $serializer; - /** - * ActivityController constructor. - * - * @param EventDispatcherInterface $eventDispatcher - * @param AuthorizationHelper $authorizationHelper - */ public function __construct( EventDispatcherInterface $eventDispatcher, AuthorizationHelper $authorizationHelper, - LoggerInterface $logger + LoggerInterface $logger, + SerializerInterface $serializer ) { $this->eventDispatcher = $eventDispatcher; $this->authorizationHelper = $authorizationHelper; $this->logger = $logger; + $this->serializer = $serializer; } /** * Lists all Activity entities. - * */ - public function listAction($person_id, Request $request) + public function listAction(Request $request): Response { $em = $this->getDoctrine()->getManager(); - $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); + $view = null; - if ($person === NULL) { - throw $this->createNotFoundException('Person not found'); + [$person, $accompanyingPeriod] = $this->getEntity($request); + + if ($person instanceof Person) { + $reachableScopes = $this->authorizationHelper + ->getReachableCircles($this->getUser(), new Role('CHILL_ACTIVITY_SEE'), + $person->getCenter()); + + $activities = $em->getRepository('ChillActivityBundle:Activity')->findBy( + ['person' => $person, 'scope' => $reachableScopes], + ['date' => 'DESC'], + ); + + $event = new PrivacyEvent($person, array( + 'element_class' => Activity::class, + 'action' => 'list' + )); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + $view = 'ChillActivityBundle:Activity:listPerson.html.twig'; + } elseif ($accompanyingPeriod instanceof AccompanyingPeriod) { + $activities = $em->getRepository('ChillActivityBundle:Activity')->findBy( + ['accompanyingPeriod' => $accompanyingPeriod], + ['date' => 'DESC'], + ); + + $view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig'; } - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); - - $reachableScopes = $this->authorizationHelper - ->getReachableScopes($this->getUser(), new Role('CHILL_ACTIVITY_SEE'), - $person->getCenter()); - - $activities = $em->getRepository('ChillActivityBundle:Activity') - ->findBy( - array('person' => $person, 'scope' => $reachableScopes), - array('date' => 'DESC') - ); - - $event = new PrivacyEvent($person, array( - 'element_class' => Activity::class, - 'action' => 'list' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - return $this->render('ChillActivityBundle:Activity:list.html.twig', array( + return $this->render($view, array( 'activities' => $activities, - 'person' => $person + 'person' => $person, + 'accompanyingCourse' => $accompanyingPeriod, )); } - /** - * Creates a new Activity entity. - * - */ - public function createAction($person_id, Request $request) + + public function selectTypeAction(Request $request): Response { $em = $this->getDoctrine()->getManager(); - $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); + $view = null; - if ($person === NULL) { - throw $this->createNotFoundException('person not found'); + [$person, $accompanyingPeriod] = $this->getEntity($request); + + if ($accompanyingPeriod instanceof AccompanyingPeriod) { + $view = 'ChillActivityBundle:Activity:selectTypeAccompanyingCourse.html.twig'; + } elseif ($person instanceof Person) { + $view = 'ChillActivityBundle:Activity:selectTypePerson.html.twig'; } - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + $data = []; + + $activityTypeCategories = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityTypeCategory::class) + ->findBy(['active' => true], ['ordering' => 'ASC']); + + foreach ($activityTypeCategories as $activityTypeCategory) { + $activityTypes = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityType::class) + ->findBy(['active' => true, 'category' => $activityTypeCategory], ['ordering' => 'ASC']); + + $data[] = [ + 'activityTypeCategory' => $activityTypeCategory, + 'activityTypes' => $activityTypes, + ]; + } + + if ($view === null) { + throw $this->createNotFoundException('Template not found'); + } + + return $this->render($view, [ + 'person' => $person, + 'accompanyingCourse' => $accompanyingPeriod, + 'data' => $data, + ]); + } + + public function newAction(Request $request): Response + { + $em = $this->getDoctrine()->getManager(); + + [$person, $accompanyingPeriod] = $this->getEntity($request); + + if ($accompanyingPeriod instanceof AccompanyingPeriod) { + $view = 'ChillActivityBundle:Activity:newAccompanyingCourse.html.twig'; + } elseif ($person instanceof Person) { + $view = 'ChillActivityBundle:Activity:newPerson.html.twig'; + } + + $activityType_id = $request->get('activityType_id', 0); + $activityType = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityType::class) + ->find($activityType_id); + + if (!$activityType instanceof \Chill\ActivityBundle\Entity\ActivityType || + !$activityType->isActive()) { + + $params = $this->buildParamsToUrl($person, $accompanyingPeriod); + return $this->redirectToRoute('chill_activity_activity_select_type', $params); + } $entity = new Activity(); - $entity->setPerson($person); - $form = $this->createCreateForm($entity, $person); - $form->handleRequest($request); + $entity->setUser($this->getUser()); - if ($form->isValid()) { - $em = $this->getDoctrine()->getManager(); + if ($person instanceof Person) { + $entity->setPerson($person); + } - $this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity, - 'creation of this activity not allowed'); + if ($accompanyingPeriod instanceof AccompanyingPeriod) { + $entity->setAccompanyingPeriod($accompanyingPeriod); + } + $entity->setType($activityType); + $entity->setDate(new \DateTime('now')); + + // TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période + // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity); + + $form = $this->createForm(ActivityType::class, $entity, [ + 'center' => $entity->getCenter(), + 'role' => new Role('CHILL_ACTIVITY_CREATE'), + 'activityType' => $entity->getType(), + 'accompanyingPeriod' => $accompanyingPeriod, + ])->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { $em->persist($entity); $em->flush(); - $this->get('session') - ->getFlashBag() - ->add('success', - $this->get('translator') - ->trans('Success : activity created!') - ); + $this->addFlash('success', $this->get('translator')->trans('Success : activity created!')); - return $this->redirect( - $this->generateUrl('chill_activity_activity_show', - array('id' => $entity->getId(), 'person_id' => $person_id))); + $params = $this->buildParamsToUrl($person, $accompanyingPeriod); + $params['id'] = $entity->getId(); + + return $this->redirectToRoute('chill_activity_activity_show', $params); } - $this->get('session') - ->getFlashBag()->add('danger', - $this->get('translator') - ->trans('The form is not valid. The activity has not been created !') - ); - - return $this->render('ChillActivityBundle:Activity:new.html.twig', array( - 'entity' => $entity, - 'form' => $form->createView(), - 'person' => $person - )); - } - - /** - * Creates a form to create a Activity entity. - * - * @param Activity $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(Activity $entity) - { - $form = $this->createForm(ActivityType::class, $entity, - array( - 'action' => $this->generateUrl('chill_activity_activity_create', [ - 'person_id' => $entity->getPerson()->getId(), - ]), - 'method' => 'POST', - 'center' => $entity->getCenter(), - 'role' => new Role('CHILL_ACTIVITY_CREATE') - ) - ); - - return $form; - } - - /** - * Displays a form to create a new Activity entity. - * - */ - public function newAction($person_id) - { - $em = $this->getDoctrine()->getManager(); - $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - - if ($person === NULL){ - throw $this->createNotFoundException('Person not found'); + if ($view === null) { + throw $this->createNotFoundException('Template not found'); } - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + $activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); - $entity = new Activity(); - $entity->setUser($this->get('security.token_storage')->getToken()->getUser()); - $entity->setPerson($person); - $entity->setDate(new \DateTime('now')); - - $this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity); - - $form = $this->createCreateForm($entity, $person); - - return $this->render('ChillActivityBundle:Activity:new.html.twig', array( + return $this->render($view, [ 'person' => $person, + 'accompanyingCourse' => $accompanyingPeriod, 'entity' => $entity, - 'form' => $form->createView(), - )); + 'form' => $form->createView(), + 'activity_json' => $activity_array + ]); } - /** - * Finds and displays a Activity entity. - * - */ - public function showAction($person_id, $id) + public function showAction(Request $request, $id): Response { $em = $this->getDoctrine()->getManager(); - $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - if (!$person) { - throw $this->createNotFoundException('person not found'); + [$person, $accompanyingPeriod] = $this->getEntity($request); + + if ($accompanyingPeriod instanceof AccompanyingPeriod) { + $view = 'ChillActivityBundle:Activity:showAccompanyingCourse.html.twig'; + } elseif ($person instanceof Person) { + $view = 'ChillActivityBundle:Activity:showPerson.html.twig'; } - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); - $entity = $em->getRepository('ChillActivityBundle:Activity')->find($id); if (!$entity) { throw $this->createNotFoundException('Unable to find Activity entity.'); } + + if (null !== $accompanyingPeriod) { + $entity->personsAssociated = $entity->getPersonsAssociated(); + $entity->personsNotAssociated = $entity->getPersonsNotAssociated(); + } - $this->denyAccessUnlessGranted('CHILL_ACTIVITY_SEE', $entity); + // TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période + // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_SEE', $entity); - $deleteForm = $this->createDeleteForm($id, $person); + $deleteForm = $this->createDeleteForm($id, $person, $accompanyingPeriod); + // TODO + /* $event = new PrivacyEvent($person, array( 'element_class' => Activity::class, 'element_id' => $entity->getId(), 'action' => 'show' )); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + */ - return $this->render('ChillActivityBundle:Activity:show.html.twig', array( + if ($view === null) { + throw $this->createNotFoundException('Template not found'); + } + + return $this->render($view, array( 'person' => $person, + 'accompanyingCourse' => $accompanyingPeriod, 'entity' => $entity, 'delete_form' => $deleteForm->createView(), )); @@ -260,118 +275,70 @@ class ActivityController extends AbstractController * Displays a form to edit an existing Activity entity. * */ - public function editAction($person_id, $id) + public function editAction($id, Request $request): Response { $em = $this->getDoctrine()->getManager(); - $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - if (!$person) { - throw $this->createNotFoundException('person not found'); + [$person, $accompanyingPeriod] = $this->getEntity($request); + + if ($accompanyingPeriod instanceof AccompanyingPeriod) { + $view = 'ChillActivityBundle:Activity:editAccompanyingCourse.html.twig'; + } elseif ($person instanceof Person) { + $view = 'ChillActivityBundle:Activity:editPerson.html.twig'; } - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); - $entity = $em->getRepository('ChillActivityBundle:Activity')->find($id); if (!$entity) { throw $this->createNotFoundException('Unable to find Activity entity.'); } - $this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity); + // TODO + // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity); - $editForm = $this->createEditForm($entity); - $deleteForm = $this->createDeleteForm($id, $person); + $form = $this->createForm(ActivityType::class, $entity, [ + 'center' => $entity->getCenter(), + 'role' => new Role('CHILL_ACTIVITY_UPDATE'), + 'activityType' => $entity->getType(), + 'accompanyingPeriod' => $accompanyingPeriod, + ])->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + $em->persist($entity); + $em->flush(); + + $this->addFlash('success', $this->get('translator')->trans('Success : activity updated!')); + + $params = $this->buildParamsToUrl($person, $accompanyingPeriod); + $params['id'] = $id; + return $this->redirectToRoute('chill_activity_activity_show', $params); + } + + $deleteForm = $this->createDeleteForm($id, $person, $accompanyingPeriod); + + /* + * TODO $event = new PrivacyEvent($person, array( 'element_class' => Activity::class, 'element_id' => $entity->getId(), 'action' => 'edit' )); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + */ - return $this->render('ChillActivityBundle:Activity:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - 'delete_form' => $deleteForm->createView(), - 'person' => $person - )); - } - - /** - * Creates a form to edit a Activity entity. - * - * @param Activity $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(Activity $entity) - { - $form = $this->createForm(ActivityType::class, $entity, array( - 'action' => $this->generateUrl('chill_activity_activity_update', - array( - 'id' => $entity->getId(), - 'person_id' => $entity->getPerson()->getId() - )), - 'method' => 'PUT', - 'center' => $entity->getCenter(), - 'role' => new Role('CHILL_ACTIVITY_UPDATE') - )); - - return $form; - } - /** - * Edits an existing Activity entity. - * - */ - public function updateAction(Request $request, $person_id, $id) - { - $em = $this->getDoctrine()->getManager(); - - $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - $entity = $em->getRepository('ChillActivityBundle:Activity')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find Activity entity.'); + if ($view === null) { + throw $this->createNotFoundException('Template not found'); } - $this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity); + $activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); - $deleteForm = $this->createDeleteForm($id, $person); - $editForm = $this->createEditForm($entity); - $editForm->handleRequest($request); - - $event = new PrivacyEvent($person, array( - 'element_class' => Activity::class, - 'element_id' => $entity->getId(), - 'action' => 'update' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - if ($editForm->isValid()) { - $em->flush(); - - $this->get('session') - ->getFlashBag() - ->add('success', - $this->get('translator') - ->trans('Success : activity updated!') - ); - - return $this->redirect($this->generateUrl('chill_activity_activity_show', array('id' => $id, 'person_id' => $person_id))); - } - - $this->get('session') - ->getFlashBag() - ->add('error', - $this->get('translator') - ->trans('This form contains errors') - ); - - return $this->render('ChillActivityBundle:Activity:edit.html.twig', array( - 'person' => $entity->getPerson(), + return $this->render($view, array( 'entity' => $entity, - 'edit_form' => $editForm->createView(), + 'edit_form' => $form->createView(), 'delete_form' => $deleteForm->createView(), + 'person' => $person, + 'accompanyingCourse' => $accompanyingPeriod, + 'activity_json' => $activity_array )); } @@ -379,22 +346,29 @@ class ActivityController extends AbstractController * Deletes a Activity entity. * */ - public function deleteAction(Request $request, $id, $person_id) + public function deleteAction(Request $request, $id) { $em = $this->getDoctrine()->getManager(); + [$person, $accompanyingPeriod] = $this->getEntity($request); + + if ($accompanyingPeriod instanceof AccompanyingPeriod) { + $view = 'ChillActivityBundle:Activity:confirm_deleteAccompanyingCourse.html.twig'; + } elseif ($person instanceof Person) { + $view = 'ChillActivityBundle:Activity:confirm_deletePerson.html.twig'; + } + /* @var $activity Activity */ - $activity = $em->getRepository('ChillActivityBundle:Activity') - ->find($id); - $person = $activity->getPerson(); + $activity = $em->getRepository('ChillActivityBundle:Activity')->find($id); if (!$activity) { throw $this->createNotFoundException('Unable to find Activity entity.'); } - $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity); + // TODO + // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity); - $form = $this->createDeleteForm($id, $person); + $form = $this->createDeleteForm($id, $person, $accompanyingPeriod); if ($request->getMethod() === Request::METHOD_DELETE) { $form->handleRequest($request); @@ -404,14 +378,14 @@ class ActivityController extends AbstractController $this->logger->notice("An activity has been removed", array( 'by_user' => $this->getUser()->getUsername(), 'activity_id' => $activity->getId(), - 'person_id' => $activity->getPerson()->getId(), + 'person_id' => $activity->getPerson() ? $activity->getPerson()->getId() : null, 'comment' => $activity->getComment()->getComment(), - 'scope_id' => $activity->getScope()->getId(), + 'scope_id' => $activity->getScope() ? $activity->getScope()->getId() : null, 'reasons_ids' => $activity->getReasons() ->map(function ($ar) { return $ar->getId(); }) ->toArray(), 'type_id' => $activity->getType()->getId(), - 'duration' => $activity->getDurationTime()->format('U'), + 'duration' => $activity->getDurationTime() ? $activity->getDurationTime()->format('U') : null, 'date' => $activity->getDate()->format('Y-m-d'), 'attendee' => $activity->getAttendee() )); @@ -422,37 +396,86 @@ class ActivityController extends AbstractController $this->addFlash('success', $this->get('translator') ->trans("The activity has been successfully removed.")); - return $this->redirect($this->generateUrl( - 'chill_activity_activity_list', array( - 'person_id' => $person_id - ))); + $params = $this->buildParamsToUrl($person, $accompanyingPeriod); + return $this->redirectToRoute('chill_activity_activity_list', $params); } } - return $this->render('ChillActivityBundle:Activity:confirm_delete.html.twig', array( + if ($view === null) { + throw $this->createNotFoundException('Template not found'); + } + + return $this->render($view, array( 'activity' => $activity, - 'delete_form' => $form->createView() + 'delete_form' => $form->createView(), + 'person' => $person, + 'accompanyingCourse' => $accompanyingPeriod, )); - - } /** * Creates a form to delete a Activity entity by id. - * - * @param mixed $id The entity id - * - * @return \Symfony\Component\Form\Form The form */ - private function createDeleteForm($id, $person) + private function createDeleteForm(int $id, ?Person $person, ?AccompanyingPeriod $accompanyingPeriod): Form { + $params = $this->buildParamsToUrl($person, $accompanyingPeriod); + $params['id'] = $id; + return $this->createFormBuilder() - ->setAction($this->generateUrl( - 'chill_activity_activity_delete', - array('id' => $id, 'person_id' => $person->getId()))) + ->setAction($this->generateUrl('chill_activity_activity_delete', $params)) ->setMethod('DELETE') ->add('submit', SubmitType::class, array('label' => 'Delete')) ->getForm() ; } + + private function getEntity(Request $request): array + { + $em = $this->getDoctrine()->getManager(); + $person = $accompanyingPeriod = null; + + if ($request->query->has('person_id')) { + $person_id = $request->get('person_id'); + $person = $em->getRepository(Person::class)->find($person_id); + + if ($person === null) { + throw $this->createNotFoundException('Person not found'); + } + + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + } elseif ($request->query->has('accompanying_period_id')) { + $accompanying_period_id = $request->get('accompanying_period_id'); + $accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($accompanying_period_id); + + if ($accompanyingPeriod === null) { + throw $this->createNotFoundException('Accompanying Period not found'); + } + + // TODO Add permission + // $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + } else { + throw $this->createNotFoundException("Person or Accompanying Period not found"); + } + + return [ + $person, $accompanyingPeriod + ]; + } + + private function buildParamsToUrl( + ?Person $person, + ?AccompanyingPeriod $accompanyingPeriod + ): array { + $params = []; + + if ($person) { + $params['person_id'] = $person->getId(); + } + + if ($accompanyingPeriod) { + $params['accompanying_period_id'] = $accompanyingPeriod->getId(); + } + + return $params; + } } diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityTypeController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityTypeController.php deleted file mode 100644 index f27bea0ae..000000000 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityTypeController.php +++ /dev/null @@ -1,178 +0,0 @@ -getDoctrine()->getManager(); - - $entities = $em->getRepository('ChillActivityBundle:ActivityType')->findAll(); - - return $this->render('ChillActivityBundle:ActivityType:index.html.twig', array( - 'entities' => $entities, - )); - } - /** - * Creates a new ActivityType entity. - * - */ - public function createAction(Request $request) - { - $entity = new ActivityType(); - $form = $this->createCreateForm($entity); - $form->handleRequest($request); - - if ($form->isValid()) { - $em = $this->getDoctrine()->getManager(); - $em->persist($entity); - $em->flush(); - - return $this->redirect($this->generateUrl('chill_activity_activitytype_show', array('id' => $entity->getId()))); - } - - return $this->render('ChillActivityBundle:ActivityType:new.html.twig', array( - 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Creates a form to create a ActivityType entity. - * - * @param ActivityType $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(ActivityType $entity) - { - $form = $this->createForm(ActivityTypeType::class, $entity, array( - 'action' => $this->generateUrl('chill_activity_activitytype_create'), - 'method' => 'POST', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Create')); - - return $form; - } - - /** - * Displays a form to create a new ActivityType entity. - * - */ - public function newAction() - { - $entity = new ActivityType(); - $form = $this->createCreateForm($entity); - - return $this->render('ChillActivityBundle:ActivityType:new.html.twig', array( - 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a ActivityType entity. - * - */ - public function showAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillActivityBundle:ActivityType')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find ActivityType entity.'); - } - - return $this->render('ChillActivityBundle:ActivityType:show.html.twig', array( - 'entity' => $entity, - )); - } - - /** - * Displays a form to edit an existing ActivityType entity. - * - */ - public function editAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillActivityBundle:ActivityType')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find ActivityType entity.'); - } - - $editForm = $this->createEditForm($entity); - - return $this->render('ChillActivityBundle:ActivityType:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView() - )); - } - - /** - * Creates a form to edit a ActivityType entity. - * - * @param ActivityType $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(ActivityType $entity) - { - $form = $this->createForm(ActivityTypeType::class, $entity, array( - 'action' => $this->generateUrl('chill_activity_activitytype_update', array('id' => $entity->getId())), - 'method' => 'PUT', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Update')); - - return $form; - } - /** - * Edits an existing ActivityType entity. - * - */ - public function updateAction(Request $request, $id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillActivityBundle:ActivityType')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find ActivityType entity.'); - } - - $editForm = $this->createEditForm($entity); - $editForm->handleRequest($request); - - if ($editForm->isValid()) { - $em->flush(); - - return $this->redirect($this->generateUrl('chill_activity_activitytype_edit', array('id' => $id))); - } - - return $this->render('ChillActivityBundle:ActivityType:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - )); - } -} diff --git a/src/Bundle/ChillActivityBundle/Controller/AdminActivityPresenceController.php b/src/Bundle/ChillActivityBundle/Controller/AdminActivityPresenceController.php new file mode 100644 index 000000000..a100c3f5d --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Controller/AdminActivityPresenceController.php @@ -0,0 +1,23 @@ +orderBy('e.id', 'ASC'); + } +} diff --git a/src/Bundle/ChillActivityBundle/Controller/AdminActivityTypeCategoryController.php b/src/Bundle/ChillActivityBundle/Controller/AdminActivityTypeCategoryController.php new file mode 100644 index 000000000..1aef0c183 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Controller/AdminActivityTypeCategoryController.php @@ -0,0 +1,23 @@ +orderBy('e.ordering', 'ASC'); + } +} diff --git a/src/Bundle/ChillActivityBundle/Controller/AdminActivityTypeController.php b/src/Bundle/ChillActivityBundle/Controller/AdminActivityTypeController.php new file mode 100644 index 000000000..8bf5da13d --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Controller/AdminActivityTypeController.php @@ -0,0 +1,23 @@ +orderBy('e.ordering', 'ASC'); + } +} diff --git a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php index dd24cfcd2..de1ea97c2 100644 --- a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php @@ -116,9 +116,10 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C ->setDurationTime($this->faker->dateTime(36000)) ->setType($this->getRandomActivityType()) ->setScope($this->getRandomScope()) - ->setAttendee($this->faker->boolean()) ; + // ->setAttendee($this->faker->boolean()) + $usedId = array(); for ($i = 0; $i < rand(0, 4); $i++) { $reason = $this->getRandomActivityReason($usedId); diff --git a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityType.php b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityType.php index fa846df68..de3c1d4de 100644 --- a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityType.php +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityType.php @@ -2,27 +2,27 @@ /* * Chill is a software for social workers - * - * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, + * + * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, * , - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ namespace Chill\ActivityBundle\DataFixtures\ORM; -use Doctrine\Common\DataFixtures\AbstractFixture; +use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; use Chill\ActivityBundle\Entity\ActivityType; @@ -32,36 +32,59 @@ use Chill\ActivityBundle\Entity\ActivityType; * * @author Champs-Libres Coop */ -class LoadActivityType extends AbstractFixture implements OrderedFixtureInterface +class LoadActivityType extends Fixture implements OrderedFixtureInterface { public function getOrder() { return 16100; } - + public static $references = array(); public function load(ObjectManager $manager) { $types = [ - [ 'name' => - ['fr' => 'Appel téléphonique', 'en' => 'Telephone call', 'nl' => 'Telefoon appel']], - [ 'name' => - ['fr' => 'Entretien', 'en' => 'Interview', 'nl' => 'Vraaggesprek']], - [ 'name' => - ['fr' => 'Inspection', 'en' => 'Inspection', 'nl' => 'Inspectie']] + # Exange + [ + 'name' => + ['fr' => 'Entretien physique avec l\'usager'], + 'category' => 'exchange' ], + [ + 'name' => + ['fr' => 'Appel téléphonique', 'en' => 'Telephone call', 'nl' => 'Telefoon appel'], + 'category' => 'exchange' ], + [ + 'name' => + ['fr' => 'Courriel', 'en' => 'Email', 'nl' => 'Email'], + 'category' => 'exchange' ], + # Meeting + [ + 'name' => + ['fr' => 'Point technique encadrant'], + 'category' => 'meeting' ], + [ + 'name' => + ['fr' => 'Réunion avec des partenaires'], + 'category' => 'meeting' ], + [ + 'name' => + ['fr' => 'Commission pluridisciplinaire et pluri-institutionnelle'], + 'category' => 'meeting' ], ]; - + foreach ($types as $t) { - print "Creating activity type : " . $t['name']['en'] . "\n"; + print "Creating activity type : " . $t['name']['fr'] . " (cat:". $t['category'] . " \n"; $activityType = (new ActivityType()) - ->setName(($t['name'])); + ->setName(($t['name'])) + ->setCategory($this->getReference('activity_type_cat_'.$t['category'])) + ->setSocialIssuesVisible(1) + ->setSocialActionsVisible(1); $manager->persist($activityType); - $reference = 'activity_type_'.$t['name']['en']; + $reference = 'activity_type_'.$t['name']['fr']; $this->addReference($reference, $activityType); static::$references[] = $reference; } - + $manager->flush(); } } diff --git a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityTypeCategory.php b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityTypeCategory.php new file mode 100644 index 000000000..40e45fcf4 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityTypeCategory.php @@ -0,0 +1,72 @@ +, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace Chill\ActivityBundle\DataFixtures\ORM; + +use Doctrine\Bundle\FixturesBundle\Fixture; +use Doctrine\Common\DataFixtures\OrderedFixtureInterface; +use Doctrine\Persistence\ObjectManager; +use Chill\ActivityBundle\Entity\ActivityTypeCategory; + +/** + * Fixtures for ActivityTypeCategory + * + * @author Champs-Libres Coop + */ +class LoadActivityTypeCategory extends Fixture implements OrderedFixtureInterface +{ + public static $references = array(); + + public function getOrder() + { + return 16050; + } + + public function load(ObjectManager $manager) + { + $categories = [ + [ + 'name' => ['fr' => 'Échange avec usager', 'en' => 'Exchange with user'], + 'ref' => 'exchange', + ], + [ + 'name' => ['fr' => 'Réunion', 'en' => 'Meeting'], + 'ref' => 'meeting', + ], + ]; + + foreach ($categories as $cat) { + print "Creating activity type category : " . $cat['ref'] . "\n"; + + $newCat = (new ActivityTypeCategory()) + ->setName(($cat['name'])); + + $manager->persist($newCat); + $reference = 'activity_type_cat_'.$cat['ref']; + + $this->addReference($reference, $newCat); + static::$references[] = $reference; + } + + $manager->flush(); + } +} diff --git a/src/Bundle/ChillActivityBundle/DependencyInjection/ChillActivityExtension.php b/src/Bundle/ChillActivityBundle/DependencyInjection/ChillActivityExtension.php index 81d00aa7b..61354c7c8 100644 --- a/src/Bundle/ChillActivityBundle/DependencyInjection/ChillActivityExtension.php +++ b/src/Bundle/ChillActivityBundle/DependencyInjection/ChillActivityExtension.php @@ -3,7 +3,7 @@ /* * Chill is a software for social workers * - * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, + * Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, * , * * This program is free software: you can redistribute it and/or modify @@ -44,7 +44,7 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf { $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); - + $container->setParameter('chill_activity.form.time_duration', $config['form']['time_duration']); $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config')); @@ -56,17 +56,18 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf $loader->load('services/form.yaml'); $loader->load('services/templating.yaml'); } - + public function prepend(ContainerBuilder $container) { $this->prependRoutes($container); $this->prependAuthorization($container); + $this->prependCruds($container); } /* (non-PHPdoc) * @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend() */ - public function prependRoutes(ContainerBuilder $container) + public function prependRoutes(ContainerBuilder $container) { //add routes for custom bundle $container->prependExtensionConfig('chill_main', array( @@ -77,7 +78,7 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf ) )); } - + public function prependAuthorization(ContainerBuilder $container) { $container->prependExtensionConfig('security', array( @@ -89,4 +90,75 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf ) )); } + + protected function prependCruds(ContainerBuilder $container) + { + $container->prependExtensionConfig('chill_main', [ + 'cruds' => [ + [ + 'class' => \Chill\ActivityBundle\Entity\ActivityType::class, + 'name' => 'activity_type', + 'base_path' => '/admin/activity/type', + 'form_class' => \Chill\ActivityBundle\Form\ActivityTypeType::class, + 'controller' => \Chill\ActivityBundle\Controller\AdminActivityTypeController::class, + 'actions' => [ + 'index' => [ + 'template' => '@ChillActivity/ActivityType/index.html.twig', + 'role' => 'ROLE_ADMIN' + ], + 'new' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillActivity/ActivityType/new.html.twig', + ], + 'edit' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillActivity/ActivityType/edit.html.twig', + ] + ] + ], + [ + 'class' => \Chill\ActivityBundle\Entity\ActivityTypeCategory::class, + 'name' => 'activity_type_category', + 'base_path' => '/admin/activity/type_category', + 'form_class' => \Chill\ActivityBundle\Form\ActivityTypeCategoryType::class, + 'controller' => \Chill\ActivityBundle\Controller\AdminActivityTypeCategoryController::class, + 'actions' => [ + 'index' => [ + 'template' => '@ChillActivity/ActivityTypeCategory/index.html.twig', + 'role' => 'ROLE_ADMIN' + ], + 'new' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillActivity/ActivityTypeCategory/new.html.twig', + ], + 'edit' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillActivity/ActivityTypeCategory/edit.html.twig', + ] + ] + ], + [ + 'class' => \Chill\ActivityBundle\Entity\ActivityPresence::class, + 'name' => 'activity_presence', + 'base_path' => '/admin/activity/presence', + 'form_class' => \Chill\ActivityBundle\Form\ActivityPresenceType::class, + 'controller' => \Chill\ActivityBundle\Controller\AdminActivityPresenceController::class, + 'actions' => [ + 'index' => [ + 'template' => '@ChillActivity/ActivityPresence/index.html.twig', + 'role' => 'ROLE_ADMIN' + ], + 'new' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillActivity/ActivityPresence/new.html.twig', + ], + 'edit' => [ + 'role' => 'ROLE_ADMIN', + 'template' => '@ChillActivity/ActivityPresence/edit.html.twig', + ] + ] + ], + ] + ]); + } } diff --git a/src/Bundle/ChillActivityBundle/Entity/Activity.php b/src/Bundle/ChillActivityBundle/Entity/Activity.php index afa631761..b0a84fa4e 100644 --- a/src/Bundle/ChillActivityBundle/Entity/Activity.php +++ b/src/Bundle/ChillActivityBundle/Entity/Activity.php @@ -20,19 +20,25 @@ namespace Chill\ActivityBundle\Entity; +use Chill\DocStoreBundle\Entity\Document; +use Chill\DocStoreBundle\Entity\StoredObject; use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; +use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\SocialWork\SocialAction; +use Chill\PersonBundle\Entity\SocialWork\SocialIssue; +use Chill\ThirdPartyBundle\Entity\ThirdParty; use Doctrine\ORM\Mapping as ORM; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\Center; -use Chill\ActivityBundle\Entity\ActivityReason; -use Chill\ActivityBundle\Entity\ActivityType; use Chill\PersonBundle\Entity\Person; use Chill\MainBundle\Entity\HasCenterInterface; use Chill\MainBundle\Entity\HasScopeInterface; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; use Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistency; +use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Serializer\Annotation\DiscriminatorMap; /** * Class Activity @@ -41,311 +47,513 @@ use Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistency; * @ORM\Entity(repositoryClass="Chill\ActivityBundle\Repository\ActivityRepository") * @ORM\Table(name="activity") * @ORM\HasLifecycleCallbacks() + * @DiscriminatorMap(typeProperty="type", mapping={ + * "activity"=Activity::class + * }) + */ + +/* + * TODO : revoir * @UserCircleConsistency( * "CHILL_ACTIVITY_SEE_DETAILS", * getUserFunction="getUser", * path="scope") */ + class Activity implements HasCenterInterface, HasScopeInterface { + const SENTRECEIVED_SENT = 'sent'; + const SENTRECEIVED_RECEIVED = 'received'; + /** - * @var integer - * * @ORM\Id * @ORM\Column(name="id", type="integer") * @ORM\GeneratedValue(strategy="AUTO") + * @Groups({"read"}) */ - private $id; + private ?int $id = null; /** - * @var User * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User") */ - private $user; + private User $user; /** - * @var \DateTime * @ORM\Column(type="datetime") */ - private $date; + private \DateTime $date; /** - * @var \DateTime - * @ORM\Column(type="time") + * @ORM\Column(type="time", nullable=true) */ - private $durationTime; + private ?\DateTime $durationTime = null; /** - * @var boolean - * @ORM\Column(type="boolean") + * @ORM\Column(type="time", nullable=true) */ - private $attendee; + private ?\DateTime $travelTime = null; + + /** + * @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityPresence") + */ + private ?ActivityPresence $attendee = null; /** - * @var ActivityReason * @ORM\ManyToMany(targetEntity="Chill\ActivityBundle\Entity\ActivityReason") */ - private $reasons; + private Collection $reasons; + + /** + * @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\SocialWork\SocialIssue") + * @ORM\JoinTable(name="chill_activity_activity_chill_person_socialissue") + */ + private $socialIssues; + + /** + * @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\SocialWork\SocialAction") + * @ORM\JoinTable(name="chill_activity_activity_chill_person_socialaction") + */ + private $socialActions; + /** - * @var ActivityType * @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityType") */ - private $type; + private ActivityType $type; /** - * @var Scope * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope") */ - private $scope; + private ?Scope $scope = null; /** - * @var Person * @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\Person") */ - private $person; + private ?Person $person = null; + + /** + * @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod") + * @Groups({"read"}) + */ + private ?AccompanyingPeriod $accompanyingPeriod = null; /** * @ORM\Embedded(class="Chill\MainBundle\Entity\Embeddable\CommentEmbeddable", columnPrefix="comment_") */ - private $comment; + private CommentEmbeddable $comment; /** - * Activity constructor. + * @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\Person") + * @Groups({"read"}) */ + private ?Collection $persons = null; + + /** + * @ORM\ManyToMany(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty") + * @Groups({"read"}) + */ + private ?Collection $thirdParties = null; + + /** + * @ORM\ManyToMany(targetEntity="Chill\DocStoreBundle\Entity\StoredObject") + */ + private Collection $documents; + + /** + * @ORM\ManyToMany(targetEntity="Chill\MainBundle\Entity\User") + * @Groups({"read"}) + */ + private ?Collection $users = null; + + /** + * @ORM\Column(type="boolean", options={"default"=false}) + */ + private bool $emergency = false; + + /** + * @ORM\Column(type="string", options={"default"=""}) + */ + private string $sentReceived = ''; + public function __construct() { $this->reasons = new ArrayCollection(); $this->comment = new CommentEmbeddable(); + $this->persons = new ArrayCollection(); + $this->thirdParties = new ArrayCollection(); + $this->documents = new ArrayCollection(); + $this->users = new ArrayCollection(); + $this->socialIssues = new ArrayCollection(); + $this->socialActions = new ArrayCollection(); } - /** - * Get id - * - * @return integer - */ - public function getId() + public function getId(): ?int { return $this->id; } - /** - * Set user - * - * @param User $user - * @return Activity - */ - public function setUser(User $user) + public function setUser(User $user): self { $this->user = $user; return $this; } - /** - * Get user - * - * @return User - */ - public function getUser() + public function getUser(): User { return $this->user; } - /** - * Set date - * - * @param \DateTime $date - * @return Activity - */ - public function setDate($date) + public function setDate(\DateTime $date): self { $this->date = $date; return $this; } - /** - * Get date - * - * @return \DateTime - */ - public function getDate() + public function getDate(): \DateTime { return $this->date; } - /** - * Set durationTime - * - * @param \DateTime $durationTime - * @return Activity - */ - public function setDurationTime($durationTime) + public function setDurationTime(?\DateTime $durationTime): self { $this->durationTime = $durationTime; return $this; } - /** - * Get durationTime - * - * @return \DateTime - */ - public function getDurationTime() + public function getDurationTime(): ?\DateTime { return $this->durationTime; } - /** - * Set attendee - * - * @param boolean $attendee - * @return Activity - */ - public function setAttendee($attendee) + public function setTravelTime(\DateTime $travelTime): self + { + $this->travelTime = $travelTime; + + return $this; + } + + public function getTravelTime(): ?\DateTime + { + return $this->travelTime; + } + + public function setAttendee(ActivityPresence $attendee): self { $this->attendee = $attendee; return $this; } - /** - * Get attendee - * - * @return boolean - */ - public function getAttendee() + public function getAttendee(): ?ActivityPresence { return $this->attendee; } - /** - * Add a reason - * - * @param ActivityReason $reason - * @return Activity - */ - public function addReason(ActivityReason $reason) + public function addReason(ActivityReason $reason): self { - $this->reasons[] = $reason; + $this->reasons->add($reason); + + return $this; + } + + public function removeReason(ActivityReason $reason): void + { + $this->reasons->removeElement($reason); + } + + public function getReasons(): Collection + { + return $this->reasons; + } + + public function setReasons(?ArrayCollection $reasons): self + { + $this->reasons = $reasons; + + return $this; + } + + public function getSocialIssues(): Collection + { + return $this->socialIssues; + } + + public function addSocialIssue(SocialIssue $socialIssue): self + { + if (!$this->socialIssues->contains($socialIssue)) { + $this->socialIssues[] = $socialIssue; + } + + return $this; + } + + public function removeSocialIssue(SocialIssue $socialIssue): self + { + $this->socialIssues->removeElement($socialIssue); return $this; } /** - * @param ActivityReason $reason + * @return Collection|SocialAction[] */ - public function removeReason(ActivityReason $reason) + public function getSocialActions(): Collection { - $this->reasons->removeElement($reason); + return $this->socialActions; } - /** - * Get reasons - * - * @return Collection - */ - public function getReasons() + public function addSocialAction(SocialAction $socialAction): self { - return $this->reasons; + if (!$this->socialActions->contains($socialAction)) { + $this->socialActions[] = $socialAction; + } + + return $this; } - /** - * Set type - * - * @param ActivityType $type - * @return Activity - */ - public function setType(ActivityType $type) + public function removeSocialAction(SocialAction $socialAction): self + { + $this->socialActions->removeElement($socialAction); + + return $this; + } + + + + + public function setType(ActivityType $type): self { $this->type = $type; return $this; } - /** - * Get type - * - * @return ActivityType - */ - public function getType() + public function getType(): ActivityType { return $this->type; } - /** - * Set scope - * - * @param Scope $scope - * @return Activity - */ - public function setScope(Scope $scope) + public function setScope(Scope $scope): self { $this->scope = $scope; return $this; } - /** - * Get scope - * - * @return Scope - */ - public function getScope() + public function getScope(): ?Scope { return $this->scope; } - /** - * Set person - * - * @param Person $person - * @return Activity - */ - public function setPerson(Person $person) + public function setPerson(?Person $person): self { $this->person = $person; return $this; } - /** - * Get person - * - * @return Person - */ - public function getPerson() + public function getPerson(): ?Person { return $this->person; } + public function getAccompanyingPeriod(): ?AccompanyingPeriod + { + return $this->accompanyingPeriod; + } + + public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self + { + $this->accompanyingPeriod = $accompanyingPeriod; + + return $this; + } + /** * get the center * center is extracted from person - * - * @return Center */ - public function getCenter() + public function getCenter(): ?Center { - return $this->person->getCenter(); + if ($this->person instanceof Person) { + return $this->person->getCenter(); + } + + return null; } - /** - * @return \Chill\MainBundle\Entity\Embeddalbe\CommentEmbeddable - */ - public function getComment() + public function getComment(): CommentEmbeddable { return $this->comment; } - /** - * @param \Chill\MainBundle\Entity\Embeddalbe\CommentEmbeddable $comment - */ - public function setComment($comment) + public function setComment(CommentEmbeddable $comment): self { $this->comment = $comment; + + return $this; + } + + /** + * Add a person to the person list + */ + public function addPerson(?Person $person): self + { + if (null !== $person) { + $this->persons[] = $person; + } + + return $this; + } + + public function removePerson(Person $person): void + { + $this->persons->removeElement($person); + } + + public function getPersons(): Collection + { + return $this->persons; + } + + public function getPersonsAssociated(): array + { + if (null !== $this->accompanyingPeriod) { + $personsAssociated = []; + foreach ($this->accompanyingPeriod->getParticipations() as $participation) { + if ($this->persons->contains($participation->getPerson())) { + $personsAssociated[] = $participation->getPerson(); + } + } + return $personsAssociated; + } + return []; + } + + public function getPersonsNotAssociated(): array + { + if (null !== $this->accompanyingPeriod) { + $personsNotAssociated = []; + foreach ($this->persons as $person) { + if (!in_array($person, $this->getPersonsAssociated())) { + $personsNotAssociated[] = $person; + } + } + return $personsNotAssociated; + } + return []; + } + + public function setPersons(?Collection $persons): self + { + $this->persons = $persons; + + return $this; + } + + public function addThirdParty(?ThirdParty $thirdParty): self + { + if (null !== $thirdParty) { + $this->thirdParties[] = $thirdParty; + } + return $this; + } + + public function removeThirdParty(ThirdParty $thirdParty): void + { + $this->thirdParties->removeElement($thirdParty); + } + + public function getThirdParties(): Collection + { + return $this->thirdParties; + } + + public function setThirdParties(?Collection $thirdParties): self + { + $this->thirdParties = $thirdParties; + + return $this; + } + + public function addDocument(Document $document): self + { + $this->documents[] = $document; + + return $this; + } + + public function removeDocument(Document $document): void + { + $this->documents->removeElement($document); + } + + public function getDocuments(): Collection + { + return $this->documents; + } + + public function setDocuments(Collection $documents): self + { + $this->documents = $documents; + + return $this; + } + + public function addUser(?User $user): self + { + if (null !== $user) { + $this->users[] = $user; + } + return $this; + } + + public function removeUser(User $user): void + { + $this->users->removeElement($user); + } + + public function getUsers(): Collection + { + return $this->users; + } + + public function setUsers(?Collection $users): self + { + $this->users = $users; + + return $this; + } + + public function isEmergency(): bool + { + return $this->getEmergency(); + } + + public function getEmergency(): bool + { + return $this->emergency; + } + + public function setEmergency(bool $emergency): self + { + $this->emergency = $emergency; + + return $this; + } + + public function getSentReceived(): string + { + return $this->sentReceived; + } + + public function setSentReceived(?string $sentReceived): self + { + $this->sentReceived = (string) $sentReceived; + + return $this; } } - diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityPresence.php b/src/Bundle/ChillActivityBundle/Entity/ActivityPresence.php new file mode 100644 index 000000000..ed9757549 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityPresence.php @@ -0,0 +1,97 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace Chill\ActivityBundle\Entity; + +use Doctrine\ORM\Mapping as ORM; + +/** + * Class ActivityPresence + * + * @package Chill\ActivityBundle\Entity + * @ORM\Entity() + * @ORM\Table(name="activitytpresence") + * @ORM\HasLifecycleCallbacks() + */ +class ActivityPresence +{ + /** + * @ORM\Id + * @ORM\Column(name="id", type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + private ?int $id; + + /** + * @ORM\Column(type="json") + */ + private array $name = []; + + /** + * @ORM\Column(type="boolean") + */ + private bool $active = true; + + public function getId(): int + { + return $this->id; + } + + public function setName(array $name): self + { + $this->name = $name; + + return $this; + } + + public function getName(): array + { + return $this->name; + } + + /** + * Get active + * return true if the category type is active. + */ + public function getActive(): bool + { + return $this->active; + } + + /** + * Is active + * return true if the category type is active + */ + public function isActive(): bool + { + return $this->getActive(); + } + + /** + * Set active + * set to true if the category type is active + */ + public function setActive(bool $active): self + { + $this->active = $active; + + return $this; + } +} diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityType.php b/src/Bundle/ChillActivityBundle/Entity/ActivityType.php index 25854d385..3446fa6dd 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityType.php @@ -1,19 +1,19 @@ - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -32,45 +32,239 @@ use Doctrine\ORM\Mapping as ORM; */ class ActivityType { + const FIELD_INVISIBLE = 0; + const FIELD_OPTIONAL = 1; + const FIELD_REQUIRED = 2; + /** - * @var integer - * * @ORM\Id * @ORM\Column(name="id", type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ - private $id; + private ?int $id; /** - * @var array * @ORM\Column(type="json_array") */ - private $name; - + private array $name = []; + /** - * @var bool * @ORM\Column(type="boolean") */ - private $active = true; + private bool $active = true; + /** + * @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityTypeCategory") + */ + private ?ActivityTypeCategory $category = null; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=2}) + */ + private int $personVisible = self::FIELD_REQUIRED; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $personLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=2}) + */ + private int $userVisible = self::FIELD_REQUIRED; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $userLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=2}) + */ + private int $dateVisible = self::FIELD_REQUIRED; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $dateLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $placeVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $placeLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $personsVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $personsLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $thirdPartiesVisible = self::FIELD_INVISIBLE; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $thirdPartiesLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $durationTimeVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $durationTimeLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $travelTimeVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $travelTimeLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $attendeeVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $attendeeLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $reasonsVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $reasonsLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $commentVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $commentLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $sentReceivedVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $sentReceivedLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $documentsVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $documentsLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $usersVisible = self::FIELD_OPTIONAL; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $usersLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $emergencyVisible = self::FIELD_INVISIBLE; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $emergencyLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $accompanyingPeriodVisible = self::FIELD_INVISIBLE; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $accompanyingPeriodLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $socialDataVisible = self::FIELD_INVISIBLE; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $socialDataLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $socialIssuesVisible = self::FIELD_INVISIBLE; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $socialIssuesLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default"=1}) + */ + private int $socialActionsVisible = self::FIELD_INVISIBLE; + + /** + * @ORM\Column(type="string", nullable=false, options={"default"=""}) + */ + private string $socialActionsLabel = ''; + + /** + * @ORM\Column(type="float", options={"default"="0.0"}) + */ + private float $ordering = 0.0; /** * Get id - * - * @return integer */ - public function getId() + public function getId(): int { return $this->id; } /** * Set name - * - * @param array $name - * @return ActivityType */ - public function setName($name) + public function setName(array $name): self { $this->name = $name; @@ -79,58 +273,551 @@ class ActivityType /** * Get name - * - * @return array | string */ - public function getName($locale = null) + public function getName(): array { - if ($locale) { - if (isset($this->name[$locale])) { - return $this->name[$locale]; - } else { - foreach ($this->name as $name) { - if (!empty($name)) { - return $name; - } - } - } - return ''; - } else { - return $this->name; - } + return $this->name; } - + /** * Get active * return true if the type is active. - * - * @return boolean */ - public function getActive() { + public function getActive(): bool + { return $this->active; } - + /** * Is active * return true if the type is active - * - * @return boolean */ - public function isActive() { + public function isActive(): bool + { return $this->getActive(); } /** * Set active * set to true if the type is active - * - * @param boolean $active - * @return ActivityType */ - public function setActive($active) { + public function setActive(bool $active): self + { $this->active = $active; + return $this; } -} + public function getCategory(): ?ActivityTypeCategory + { + return $this->category; + } + public function setCategory(?ActivityTypeCategory $category): self + { + $this->category = $category; + + return $this; + } + + public function getPersonVisible(): int + { + return $this->personVisible; + } + + public function setPersonVisible(int $personVisible): self + { + $this->personVisible = $personVisible; + + return $this; + } + + public function getPersonLabel(): string + { + return $this->personLabel; + } + + public function setPersonLabel(string $personLabel): self + { + $this->personLabel = $personLabel; + + return $this; + } + + public function getUserVisible(): int + { + return $this->userVisible; + } + + public function setUserVisible(int $userVisible): self + { + $this->userVisible = $userVisible; + + return $this; + } + + public function getUserLabel(): string + { + return $this->userLabel; + } + + public function setUserLabel(string $userLabel): self + { + $this->userLabel = $userLabel; + + return $this; + } + + public function getDateVisible(): int + { + return $this->dateVisible; + } + + public function setDateVisible(int $dateVisible): self + { + $this->dateVisible = $dateVisible; + + return $this; + } + + public function getDateLabel(): string + { + return $this->dateLabel; + } + + public function setDateLabel(string $dateLabel): self + { + $this->dateLabel = $dateLabel; + + return $this; + } + + public function getPlaceVisible(): int + { + return $this->placeVisible; + } + + public function setPlaceVisible(int $placeVisible): self + { + $this->placeVisible = $placeVisible; + + return $this; + } + + public function getPlaceLabel(): string + { + return $this->placeLabel; + } + + public function setPlaceLabel(string $placeLabel): self + { + $this->placeLabel = $placeLabel; + + return $this; + } + + public function getPersonsVisible(): int + { + return $this->personsVisible; + } + + public function setPersonsVisible(int $personsVisible): self + { + $this->personsVisible = $personsVisible; + + return $this; + } + + public function getPersonsLabel(): string + { + return $this->personsLabel; + } + + public function setPersonsLabel(string $personsLabel): self + { + $this->personsLabel = $personsLabel; + + return $this; + } + + public function getThirdPartiesVisible(): int + { + return $this->thirdPartiesVisible; + } + + public function setThirdPartiesVisible(int $thirdPartiesVisible): self + { + $this->thirdPartiesVisible = $thirdPartiesVisible; + + return $this; + } + + public function getThirdPartiesLabel(): string + { + return $this->thirdPartiesLabel; + } + + public function setThirdPartiesLabel(string $thirdPartiesLabel): self + { + $this->thirdPartiesLabel = $thirdPartiesLabel; + + return $this; + } + + public function getDurationTimeVisible(): int + { + return $this->durationTimeVisible; + } + + public function setDurationTimeVisible(int $durationTimeVisible): self + { + $this->durationTimeVisible = $durationTimeVisible; + + return $this; + } + + public function getDurationTimeLabel(): string + { + return $this->durationTimeLabel; + } + + public function setDurationTimeLabel(string $durationTimeLabel): self + { + $this->durationTimeLabel = $durationTimeLabel; + + return $this; + } + + public function getTravelTimeVisible(): int + { + return $this->travelTimeVisible; + } + + public function setTravelTimeVisible(int $TravelTimeVisible): self + { + $this->travelTimeVisible = $TravelTimeVisible; + + return $this; + } + + public function getTravelTimeLabel(): string + { + return $this->travelTimeLabel; + } + + public function setTravelTimeLabel(string $TravelTimeLabel): self + { + $this->travelTimeLabel = $TravelTimeLabel; + + return $this; + } + + public function getAttendeeVisible(): int + { + return $this->attendeeVisible; + } + + public function setAttendeeVisible(int $attendeeVisible): self + { + $this->attendeeVisible = $attendeeVisible; + + return $this; + } + + public function getAttendeeLabel(): string + { + return $this->attendeeLabel; + } + + public function setAttendeeLabel(string $attendeeLabel): self + { + $this->attendeeLabel = $attendeeLabel; + + return $this; + } + + public function getReasonsVisible(): int + { + return $this->reasonsVisible; + } + + public function setReasonsVisible(int $reasonsVisible): self + { + $this->reasonsVisible = $reasonsVisible; + + return $this; + } + + public function getReasonsLabel(): string + { + return $this->reasonsLabel; + } + + public function setReasonsLabel(string $reasonsLabel): self + { + $this->reasonsLabel = $reasonsLabel; + + return $this; + } + + public function getCommentVisible(): int + { + return $this->commentVisible; + } + + public function setCommentVisible(int $commentVisible): self + { + $this->commentVisible = $commentVisible; + + return $this; + } + + public function getCommentLabel(): string + { + return $this->commentLabel; + } + + public function setCommentLabel(string $commentLabel): self + { + $this->commentLabel = $commentLabel; + + return $this; + } + + public function getSentReceivedVisible(): int + { + return $this->sentReceivedVisible; + } + + public function setSentReceivedVisible(int $sentReceivedVisible): self + { + $this->sentReceivedVisible = $sentReceivedVisible; + + return $this; + } + + public function getSentReceivedLabel(): string + { + return $this->sentReceivedLabel; + } + + public function setSentReceivedLabel(string $sentReceivedLabel): self + { + $this->sentReceivedLabel = $sentReceivedLabel; + + return $this; + } + + public function getDocumentsVisible(): int + { + return $this->documentsVisible; + } + + public function setDocumentsVisible(int $documentsVisible): self + { + $this->documentsVisible = $documentsVisible; + + return $this; + } + + public function getDocumentsLabel(): string + { + return $this->documentsLabel; + } + + public function setDocumentsLabel(string $documentsLabel): self + { + $this->documentsLabel = $documentsLabel; + + return $this; + } + + public function getUsersVisible(): int + { + return $this->usersVisible; + } + + public function setUsersVisible(int $usersVisible): self + { + $this->usersVisible = $usersVisible; + + return $this; + } + + public function getUsersLabel(): string + { + return $this->usersLabel; + } + + public function setUsersLabel(string $usersLabel): self + { + $this->usersLabel = $usersLabel; + + return $this; + } + + public function getEmergencyVisible(): int + { + return $this->emergencyVisible; + } + + public function setEmergencyVisible(int $emergencyVisible): self + { + $this->emergencyVisible = $emergencyVisible; + + return $this; + } + + public function getEmergencyLabel(): string + { + return $this->emergencyLabel; + } + + public function setEmergencyLabel(string $emergencyLabel): self + { + $this->emergencyLabel = $emergencyLabel; + + return $this; + } + + public function getAccompanyingPeriodVisible(): int + { + return $this->accompanyingPeriodVisible; + } + + public function setAccompanyingPeriodVisible(int $accompanyingPeriodVisible): self + { + $this->accompanyingPeriodVisible = $accompanyingPeriodVisible; + + return $this; + } + + public function getAccompanyingPeriodLabel(): string + { + return $this->accompanyingPeriodLabel; + } + + public function setAccompanyingPeriodLabel(string $accompanyingPeriodLabel): self + { + $this->accompanyingPeriodLabel = $accompanyingPeriodLabel; + + return $this; + } + + public function getSocialDataVisible(): int + { + return $this->socialDataVisible; + } + + public function setSocialDataVisible(int $socialDataVisible): self + { + $this->socialDataVisible = $socialDataVisible; + + return $this; + } + + public function getSocialDataLabel(): string + { + return $this->socialDataLabel; + } + + public function setSocialDataLabel(string $socialDataLabel): self + { + $this->socialDataLabel = $socialDataLabel; + + return $this; + } + + public function isVisible(string $field): bool + { + $property = $field.'Visible'; + + if (!property_exists($this, $property)) { + throw new \InvalidArgumentException('Field "'.$field.'" not found'); + } + + return self::FIELD_INVISIBLE !== $this->$property; + } + + public function isRequired(string $field): bool + { + $property = $field.'Visible'; + + if (!property_exists($this, $property)) { + throw new \InvalidArgumentException('Field "'.$field.'" not found'); + } + + return self::FIELD_REQUIRED === $this->$property; + } + + public function getLabel(string $field): ?string + { + $property = $field.'Label'; + + if (!property_exists($this, $property)) { + throw new \InvalidArgumentException('Field "'.$field.'" not found'); + } + + return $this->$property; + } + + public function getOrdering(): float + { + return $this->ordering; + } + + public function setOrdering(float $ordering): self + { + $this->ordering = $ordering; + + return $this; + } + + public function getSocialIssuesVisible(): ?int + { + return $this->socialIssuesVisible; + } + + public function setSocialIssuesVisible(int $socialIssuesVisible): self + { + $this->socialIssuesVisible = $socialIssuesVisible; + + return $this; + } + + public function getSocialIssuesLabel(): ?string + { + return $this->socialIssuesLabel; + } + + public function setSocialIssuesLabel(string $socialIssuesLabel): self + { + $this->socialIssuesLabel = $socialIssuesLabel; + + return $this; + } + + public function getSocialActionsVisible(): ?int + { + return $this->socialActionsVisible; + } + + public function setSocialActionsVisible(int $socialActionsVisible): self + { + $this->socialActionsVisible = $socialActionsVisible; + + return $this; + } + + public function getSocialActionsLabel(): ?string + { + return $this->socialActionsLabel; + } + + public function setSocialActionsLabel(string $socialActionsLabel): self + { + $this->socialActionsLabel = $socialActionsLabel; + + return $this; + } +} diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php b/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php new file mode 100644 index 000000000..2da799980 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php @@ -0,0 +1,123 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace Chill\ActivityBundle\Entity; + +use Doctrine\ORM\Mapping as ORM; + +/** + * Class ActivityTypeCateogry + * + * @package Chill\ActivityBundle\Entity + * @ORM\Entity() + * @ORM\Table(name="activitytypecategory") + * @ORM\HasLifecycleCallbacks() + */ +class ActivityTypeCategory +{ + /** + * @ORM\Id + * @ORM\Column(name="id", type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + private ?int $id; + + /** + * @ORM\Column(type="json_array") + */ + private array $name = []; + + /** + * @ORM\Column(type="boolean") + */ + private bool $active = true; + + /** + * @ORM\Column(type="float", options={"default"="0.0"}) + */ + private float $ordering = 0.0; + + /** + * Get id + */ + public function getId(): int + { + return $this->id; + } + + /** + * Set name + */ + public function setName(array $name): self + { + $this->name = $name; + + return $this; + } + + /** + * Get name + */ + public function getName(): array + { + return $this->name; + } + + /** + * Get active + * return true if the category type is active. + */ + public function getActive(): bool + { + return $this->active; + } + + /** + * Is active + * return true if the category type is active + */ + public function isActive(): bool + { + return $this->getActive(); + } + + /** + * Set active + * set to true if the category type is active + */ + public function setActive(bool $active): self + { + $this->active = $active; + + return $this; + } + + public function getOrdering(): float + { + return $this->ordering; + } + + public function setOrdering(float $ordering): self + { + $this->ordering = $ordering; + + return $this; + } +} diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityPresenceType.php b/src/Bundle/ChillActivityBundle/Form/ActivityPresenceType.php new file mode 100644 index 000000000..42894cc25 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Form/ActivityPresenceType.php @@ -0,0 +1,33 @@ +add('name', TranslatableStringFormType::class) + ->add('active', ChoiceType::class, array( + 'choices' => array( + 'Yes' => true, + 'No' => false + ), + 'expanded' => true + )); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults(array( + 'data_class' => ActivityPresence::class + )); + } +} diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityType.php b/src/Bundle/ChillActivityBundle/Form/ActivityType.php index 3a9a307fd..8af7a204c 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityType.php @@ -2,8 +2,21 @@ namespace Chill\ActivityBundle\Form; +use Chill\ActivityBundle\Entity\Activity; +use Chill\ActivityBundle\Entity\ActivityPresence; +use Chill\ActivityBundle\Entity\ActivityReason; +use Chill\DocStoreBundle\Form\StoredObjectType; +use Chill\MainBundle\Form\Type\ChillCollectionType; use Chill\MainBundle\Form\Type\CommentType; +use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Entity\SocialWork\SocialIssue; +use Chill\PersonBundle\Entity\SocialWork\SocialAction; +use Chill\ThirdPartyBundle\Entity\ThirdParty; +use Doctrine\ORM\EntityRepository; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; @@ -15,178 +28,341 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTra use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Chill\ActivityBundle\Form\Type\TranslatableActivityType; -use Chill\ActivityBundle\Form\Type\TranslatableActivityReason; use Chill\MainBundle\Form\Type\UserPickerType; use Chill\MainBundle\Form\Type\ScopePickerType; use Chill\MainBundle\Form\Type\ChillDateType; +use Symfony\Component\Form\Extension\Core\Type\HiddenType; +use Symfony\Component\Form\CallbackTransformer; +use Chill\PersonBundle\Form\DataTransformer\PersonToIdTransformer; +use Chill\PersonBundle\Templating\Entity\SocialIssueRender; class ActivityType extends AbstractType { + protected User $user; - /** - * the user running this form - * - * @var User - */ - protected $user; + protected AuthorizationHelper $authorizationHelper; - /** - * - * @var AuthorizationHelper - */ - protected $authorizationHelper; + protected ObjectManager $om; - /** - * - * @var ObjectManager - */ - protected $om; + protected TranslatableStringHelper $translatableStringHelper; - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; + protected array $timeChoices; - protected $timeChoices; - - public function __construct( - TokenStorageInterface $tokenStorage, - AuthorizationHelper $authorizationHelper, ObjectManager $om, - TranslatableStringHelper $translatableStringHelper, - array $timeChoices - ) - { + public function __construct ( + TokenStorageInterface $tokenStorage, + AuthorizationHelper $authorizationHelper, + ObjectManager $om, + TranslatableStringHelper $translatableStringHelper, + array $timeChoices, + SocialIssueRender $socialIssueRender + ) { if (!$tokenStorage->getToken()->getUser() instanceof User) { throw new \RuntimeException("you should have a valid user"); } + $this->user = $tokenStorage->getToken()->getUser(); $this->authorizationHelper = $authorizationHelper; $this->om = $om; $this->translatableStringHelper = $translatableStringHelper; $this->timeChoices = $timeChoices; + $this->socialIssueRender = $socialIssueRender; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { // handle times choices - $timeChoices = array(); + $timeChoices = []; foreach ($this->timeChoices as $e) { $timeChoices[$e['label']] = $e['seconds']; - }; + } $durationTimeTransformer = new DateTimeToTimestampTransformer('GMT', 'GMT'); - $durationTimeOptions = array( - 'choices' => $timeChoices, - 'placeholder' => 'Choose the duration', - ); + $durationTimeOptions = [ + 'choices' => $timeChoices, + 'placeholder' => 'Choose the duration', + ]; - $builder - ->add('date', ChillDateType::class, array( - 'required' => true - )) - ->add('durationTime', ChoiceType::class, $durationTimeOptions) - ->add('attendee', ChoiceType::class, array( - 'expanded' => true, - 'required' => false, - 'choices' => array( - 'present' => true, - 'not present' => false - ) - )) - ->add('user', UserPickerType::class, [ + /** @var \Chill\ActivityBundle\Entity\ActivityType $activityType */ + $activityType = $options['activityType']; + + if (!$activityType->isActive()) { + throw new \InvalidArgumentException('Activity type must be active'); + } + + // TODO revoir la gestion des center au niveau du form des activité. + if ($options['center']) { + $builder->add('scope', ScopePickerType::class, [ 'center' => $options['center'], - 'role' => $options['role'] - ]) - ->add('scope', ScopePickerType::class, [ - 'center' => $options['center'], - 'role' => $options['role'] - ]) - ->add('reasons', TranslatableActivityReason::class, array( + 'role' => $options['role'] + ]); + } + + /** @var ? \Chill\PersonBundle\Entity\AccompanyingPeriod $accompanyingPeriod */ + $accompanyingPeriod = NULL; + if ($options['accompanyingPeriod']) { + $accompanyingPeriod = $options['accompanyingPeriod']; + } + + if ($activityType->isVisible('socialIssues') && $accompanyingPeriod) { + $builder->add('socialIssues', EntityType::class, [ + 'label' => $activityType->getLabel('socialIssues'), + 'required' => $activityType->isRequired('socialIssues'), + 'class' => SocialIssue::class, + 'choice_label' => function (SocialIssue $socialIssue) { + return $this->socialIssueRender->renderString($socialIssue, []); + }, 'multiple' => true, - 'required' => false, - )) - ->add('type', TranslatableActivityType::class, array( - 'placeholder' => 'Choose a type', - 'active_only' => true - )) - ->add('comment', CommentType::class, [ - 'required' => false, - ]) - ; + 'choices' => $accompanyingPeriod->getRecursiveSocialIssues(), + 'expanded' => true, + ]); + } - $builder->get('durationTime') + if ($activityType->isVisible('socialActions') && $accompanyingPeriod) { + $builder->add('socialActions', EntityType::class, [ + 'label' => $activityType->getLabel('socialActions'), + 'required' => $activityType->isRequired('socialActions'), + 'class' => SocialAction::class, + 'choice_label' => function (SocialAction $socialAction) { + return $this->translatableStringHelper->localize($socialAction->getTitle()); + }, + 'multiple' => true, + 'choices' => $accompanyingPeriod->getRecursiveSocialActions(), + 'expanded' => true, + ]); + } + + if ($activityType->isVisible('date')) { + $builder->add('date', ChillDateType::class, [ + 'label' => $activityType->getLabel('date'), + 'required' => $activityType->isRequired('date'), + ]); + } + + if ($activityType->isVisible('durationTime')) { + $durationTimeOptions['label'] = $activityType->getLabel('durationTime'); + $durationTimeOptions['required'] = $activityType->isRequired('durationTime'); + + $builder->add('durationTime', ChoiceType::class, $durationTimeOptions); + } + + if ($activityType->isVisible('travelTime')) { + $durationTimeOptions['label'] = $activityType->getLabel('travelTime'); + $durationTimeOptions['required'] = $activityType->isRequired('travelTime'); + + $builder->add('travelTime', ChoiceType::class, $durationTimeOptions); + } + + if ($activityType->isVisible('attendee')) { + $builder->add('attendee', EntityType::class, [ + 'label' => $activityType->getLabel('attendee'), + 'required' => $activityType->isRequired('attendee'), + 'expanded' => true, + 'class' => ActivityPresence::class, + 'choice_label' => function (ActivityPresence $activityPresence) { + return $this->translatableStringHelper->localize($activityPresence->getName()); + }, + 'query_builder' => function (EntityRepository $er) { + return $er->createQueryBuilder('a') + ->where('a.active = true'); + }, + ]); + } + + if ($activityType->isVisible('user') && $options['center']) { + $builder->add('user', UserPickerType::class, [ + 'label' => $activityType->getLabel('user'), + 'required' => $activityType->isRequired('user'), + 'center' => $options['center'], + 'role' => $options['role'] + ]); + } + + if ($activityType->isVisible('reasons')) { + $builder->add('reasons', EntityType::class, [ + 'label' => $activityType->getLabel('reasons'), + 'required' => $activityType->isRequired('reasons'), + 'class' => ActivityReason::class, + 'multiple' => true, + 'choice_label' => function (ActivityReason $activityReason) { + return $this->translatableStringHelper->localize($activityReason->getName()); + }, + 'attr' => array('class' => 'select2 '), + 'query_builder' => function (EntityRepository $er) { + return $er->createQueryBuilder('a') + ->where('a.active = true'); + }, + ]); + } + + if ($activityType->isVisible('comment')) { + $builder->add('comment', CommentType::class, [ + 'label' => $activityType->getLabel('comment'), + 'required' => $activityType->isRequired('comment'), + ]); + } + + if ($activityType->isVisible('persons')) { + $builder->add('persons', HiddenType::class, [ + //'data_class' => Person::class, + ]); + $builder->get('persons') + ->addModelTransformer(new CallbackTransformer( + function (iterable $personsAsIterable): string { + $personIds = []; + foreach ($personsAsIterable as $value) { + $personIds[] = $value->getId(); + } + return implode(',', $personIds); + }, + function (?string $personsAsString): array { + return array_map( + fn(string $id): ?Person => $this->om->getRepository(Person::class)->findOneBy(['id' => (int) $id]), + explode(',', $personsAsString) + ); + } + )) + ; + } + + if ($activityType->isVisible('thirdParties')) { + $builder->add('thirdParties', HiddenType::class, [ + //'data_class' => ThirdParty::class, + ]); + $builder->get('thirdParties') + ->addModelTransformer(new CallbackTransformer( + function (iterable $thirdpartyAsIterable): string { + $thirdpartyIds = []; + foreach ($thirdpartyAsIterable as $value) { + $thirdpartyIds[] = $value->getId(); + } + return implode(',', $thirdpartyIds); + }, + function (?string $thirdpartyAsString): array { + return array_map( + fn(string $id): ?ThirdParty => $this->om->getRepository(ThirdParty::class)->findOneBy(['id' => (int) $id]), + explode(',', $thirdpartyAsString) + ); + } + )) + ; + } + + if ($activityType->isVisible('documents')) { + $builder->add('documents', ChillCollectionType::class, [ + 'entry_type' => StoredObjectType::class, + 'label' => $activityType->getLabel('documents'), + 'required' => $activityType->isRequired('documents'), + 'allow_add' => true, + 'button_add_label' => 'activity.Insert a document', + 'button_remove_label' => 'activity.Remove a document' + ]); + } + + if ($activityType->isVisible('users')) { + $builder->add('users', HiddenType::class, [ + //'data_class' => User::class, + ]); + $builder->get('users') + ->addModelTransformer(new CallbackTransformer( + function (iterable $usersAsIterable): string { + $userIds = []; + foreach ($usersAsIterable as $value) { + $userIds[] = $value->getId(); + } + return implode(',', $userIds); + }, + function (?string $usersAsString): array { + return array_map( + fn(string $id): ?User => $this->om->getRepository(User::class)->findOneBy(['id' => (int) $id]), + explode(',', $usersAsString) + ); + } + )) + ; + } + + if ($activityType->isVisible('emergency')) { + $builder->add('emergency', CheckboxType::class, [ + 'label' => $activityType->getLabel('emergency'), + 'required' => $activityType->isRequired('emergency'), + ]); + } + + if ($activityType->isVisible('sentReceived')) { + $builder->add('sentReceived', ChoiceType::class, [ + 'label' => $activityType->getLabel('sentReceived'), + 'required' => $activityType->isRequired('sentReceived'), + 'choices' => [ + 'Sent' => Activity::SENTRECEIVED_SENT, + 'Received' => Activity::SENTRECEIVED_RECEIVED, + ], + ]); + } + + foreach (['durationTime', 'travelTime'] as $fieldName) { + if (!$activityType->isVisible($fieldName)) { + continue; + } + + $builder->get($fieldName) ->addModelTransformer($durationTimeTransformer); + $builder->get($fieldName) + ->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $formEvent) use ( + $timeChoices, + $builder, + $durationTimeTransformer, + $durationTimeOptions, + $fieldName + ) { + // set the timezone to GMT, and fix the difference between current and GMT + // the datetimetransformer will then handle timezone as GMT + $timezoneUTC = new \DateTimeZone('GMT'); + /* @var $data \DateTime */ + $data = $formEvent->getData() === NULL ? + \DateTime::createFromFormat('U', 300) : + $formEvent->getData(); + $seconds = $data->getTimezone()->getOffset($data); + $data->setTimeZone($timezoneUTC); + $data->add(new \DateInterval('PT'.$seconds.'S')); - $builder->get('durationTime') - ->addEventListener( - FormEvents::PRE_SET_DATA, - function(FormEvent $formEvent) use ( - $timeChoices, - $builder, - $durationTimeTransformer, - $durationTimeOptions - ) - { - // set the timezone to GMT, and fix the difference between current and GMT - // the datetimetransformer will then handle timezone as GMT - $timezoneUTC = new \DateTimeZone('GMT'); - /* @var $data \DateTime */ - $data = $formEvent->getData() === NULL ? - \DateTime::createFromFormat('U', 300) : - $formEvent->getData(); - $seconds = $data->getTimezone()->getOffset($data); - $data->setTimeZone($timezoneUTC); - $data->add(new \DateInterval('PT'.$seconds.'S')); - - // test if the timestamp is in the choices. - // If not, recreate the field with the new timestamp - if (!in_array($data->getTimestamp(), $timeChoices)) { - // the data are not in the possible values. add them - $timeChoices[$data->format('H:i')] = $data->getTimestamp(); - $form = $builder->create( - 'durationTime', - ChoiceType::class, - array_merge( - $durationTimeOptions, - array( - 'choices' => $timeChoices, - 'auto_initialize' => false - ) - )); - $form->addModelTransformer($durationTimeTransformer); - $formEvent->getForm()->getParent()->add($form->getForm()); - } - }); + // test if the timestamp is in the choices. + // If not, recreate the field with the new timestamp + if (!in_array($data->getTimestamp(), $timeChoices)) { + // the data are not in the possible values. add them + $timeChoices[$data->format('H:i')] = $data->getTimestamp(); + $form = $builder->create($fieldName, ChoiceType::class, array_merge( + $durationTimeOptions, [ + 'choices' => $timeChoices, + 'auto_initialize' => false + ] + )); + $form->addModelTransformer($durationTimeTransformer); + $formEvent->getForm()->getParent()->add($form->getForm()); + } + }); + } } - /** - * @param OptionsResolverInterface $resolver - */ - public function configureOptions(OptionsResolver $resolver) + + + public function configureOptions(OptionsResolver $resolver): void { - $resolver->setDefaults(array( - 'data_class' => 'Chill\ActivityBundle\Entity\Activity' - )); + $resolver->setDefaults([ + 'data_class' => Activity::class + ]); $resolver - ->setRequired(array('center', 'role')) - ->setAllowedTypes('center', 'Chill\MainBundle\Entity\Center') - ->setAllowedTypes('role', 'Symfony\Component\Security\Core\Role\Role') - ; + ->setRequired(['center', 'role', 'activityType', 'accompanyingPeriod']) + ->setAllowedTypes('center', ['null', 'Chill\MainBundle\Entity\Center']) + ->setAllowedTypes('role', 'Symfony\Component\Security\Core\Role\Role') + ->setAllowedTypes('activityType', \Chill\ActivityBundle\Entity\ActivityType::class) + ->setAllowedTypes('accompanyingPeriod', [\Chill\PersonBundle\Entity\AccompanyingPeriod::class, 'null']) + ; } - /** - * @return string - */ - public function getBlockPrefix() + public function getBlockPrefix(): string { return 'chill_activitybundle_activity'; } diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityTypeCategoryType.php b/src/Bundle/ChillActivityBundle/Form/ActivityTypeCategoryType.php new file mode 100644 index 000000000..0c592f519 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Form/ActivityTypeCategoryType.php @@ -0,0 +1,39 @@ +add('name', TranslatableStringFormType::class) + ->add('active', ChoiceType::class, array( + 'choices' => array( + 'Yes' => true, + 'No' => false + ), + 'expanded' => true + )) + ->add('ordering', NumberType::class, [ + 'required' => true, + 'scale' => 5 + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults(array( + 'data_class' => ActivityTypeCategory::class + )); + } +} diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php b/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php index a402f584c..d1a46b109 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php @@ -2,7 +2,13 @@ namespace Chill\ActivityBundle\Form; +use Chill\ActivityBundle\Entity\ActivityTypeCategory; +use Chill\ActivityBundle\Form\Type\ActivityFieldPresence; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\NumberType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; @@ -10,38 +16,56 @@ use Chill\MainBundle\Form\Type\TranslatableStringFormType; class ActivityTypeType extends AbstractType { - /** - * @param FormBuilderInterface $builder - * @param array $options - */ + private TranslatableStringHelper $translatableStringHelper; + + public function __construct(TranslatableStringHelper $translatableStringHelper) + { + $this->translatableStringHelper = $translatableStringHelper; + } + public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name', TranslatableStringFormType::class) - ->add('active', ChoiceType::class, array( - 'choices' => array( + ->add('active', ChoiceType::class, [ + 'choices' => [ 'Yes' => true, 'No' => false - ), + ], 'expanded' => true - )); + ]) + ->add('category', EntityType::class, [ + 'class' => ActivityTypeCategory::class, + 'choice_label' => function (ActivityTypeCategory $activityTypeCategory) { + return $this->translatableStringHelper->localize($activityTypeCategory->getName()); + }, + ]) + ->add('ordering', NumberType::class, [ + 'required' => true, + 'scale' => 5 + ]) + ; + + $fields = [ + 'persons', 'user', 'date', 'place', 'persons', + 'thirdParties', 'durationTime', 'travelTime', 'attendee', + 'reasons', 'comment', 'sentReceived', 'documents', + 'emergency', 'accompanyingPeriod', 'socialData', 'users' + ]; + foreach ($fields as $field) { + $builder + ->add($field.'Visible', ActivityFieldPresence::class) + ->add($field.'Label', TextType::class, [ + 'required' => false, + 'empty_data' => '', + ]); + } } - /** - * @param OptionsResolverInterface $resolver - */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( - 'data_class' => 'Chill\ActivityBundle\Entity\ActivityType' + 'data_class' => \Chill\ActivityBundle\Entity\ActivityType::class )); } - - /** - * @return string - */ - public function getBlockPrefix() - { - return 'chill_activitybundle_activitytype'; - } } diff --git a/src/Bundle/ChillActivityBundle/Form/Type/ActivityFieldPresence.php b/src/Bundle/ChillActivityBundle/Form/Type/ActivityFieldPresence.php new file mode 100644 index 000000000..8de67b546 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Form/Type/ActivityFieldPresence.php @@ -0,0 +1,29 @@ +setDefaults( + array( + 'choices' => [ + 'Invisible' => ActivityType::FIELD_INVISIBLE, + 'Optional' => ActivityType::FIELD_OPTIONAL, + 'Required' => ActivityType::FIELD_REQUIRED, + ], + ) + ); + } +} diff --git a/src/Bundle/ChillActivityBundle/Menu/AccompanyingCourseMenuBuilder.php b/src/Bundle/ChillActivityBundle/Menu/AccompanyingCourseMenuBuilder.php new file mode 100644 index 000000000..71d465b6c --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Menu/AccompanyingCourseMenuBuilder.php @@ -0,0 +1,54 @@ +translator = $translator; + $this->authorizationHelper = $authorizationHelper; + $this->tokenStorage = $tokenStorage; + } + public static function getMenuIds(): array + { + return ['accompanyingCourse']; + } + + public function buildMenu($menuId, MenuItem $menu, array $parameters) + { + $period = $parameters['accompanyingCourse']; + + $menu->addChild($this->translator->trans('Activity list'), [ + 'route' => 'chill_activity_activity_list', + 'routeParameters' => [ + 'accompanying_period_id' => $period->getId(), + ]]) + ->setExtras(['order' => 40]); + + $menu->addChild($this->translator->trans('Add a new activity'), [ + 'route' => 'chill_activity_activity_select_type', + 'routeParameters' => [ + 'accompanying_period_id' => $period->getId(), + ]]) + ->setExtras(['order' => 41]); + + + + } +} diff --git a/src/Bundle/ChillActivityBundle/Resources/public/activity/activity.scss b/src/Bundle/ChillActivityBundle/Resources/public/activity/activity.scss deleted file mode 100644 index bef8788f8..000000000 --- a/src/Bundle/ChillActivityBundle/Resources/public/activity/activity.scss +++ /dev/null @@ -1,10 +0,0 @@ -@import '~ChillMainSass/custom/config/colors'; -@import '~ChillMainSass/custom/mixins/entity'; - -.chill-entity.chill-entity__activity-reason { - @include entity($chill-pink, white); -} - -.activity { - color: $chill-green; -} diff --git a/src/Bundle/ChillActivityBundle/Resources/public/index.js b/src/Bundle/ChillActivityBundle/Resources/public/index.js index 74b2a8646..e219e368b 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/index.js +++ b/src/Bundle/ChillActivityBundle/Resources/public/index.js @@ -1 +1 @@ -require('./activity/activity.scss'); +require('./scss/chillactivity.scss'); diff --git a/src/Bundle/ChillActivityBundle/Resources/public/scss/chillactivity.scss b/src/Bundle/ChillActivityBundle/Resources/public/scss/chillactivity.scss new file mode 100644 index 000000000..64fd1cb18 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/public/scss/chillactivity.scss @@ -0,0 +1,114 @@ +@import '~ChillMainSass/custom/config/colors'; +@import '~ChillMainSass/custom/mixins/entity'; + +.chill-entity.chill-entity__activity-reason { + @include entity($chill-pink, white); +} + +.activity { + color: $chill-green; +} + +// exceptions for flex-bloc in concerned-groups +div.flex-bloc.concerned-groups { + margin-top: 1em; + div.item-bloc { + flex-grow: 0; flex-shrink: 0; flex-basis: 25%; //4 blocs + ul.list-content { + list-style-type: none; + padding-left: 0; + li { + margin-bottom: 0.2em; + a { + color: white; + cursor: pointer; + &:hover { + color: #ffffffab; + } + } + } + } + } + &.person div.item-bloc { + flex-basis: 33%; //3 blocs + } +} + +// exceptions for flex-table in list-records +div.flex-table.list-records { + div.item-bloc { + div.item-row.main { + div.item-col { + &:first-child { + flex-basis: 27%; + } + ul.list-content { + li.social-issues, li.social-actions { + .badge-primary { + font-variant: small-caps; + font-weight: bold; + font-size: 88%; + margin-bottom: 0.2em; + } + } + li.social-issues .badge-primary { + background-color: var(--chill-orange); + } + li.social-actions .badge-primary { + background-color: var(--chill-green); + } + } + } + } + div.item-row.details { + flex-direction: row; + & > div.item-col { + justify-content: flex-start; + align-self: center; + &:nth-child(1) { + flex-grow: 1; flex-shrink: 0; flex-basis: 30%; + } + &:nth-child(2) { + flex-grow: 0; flex-shrink: 1; flex-basis: 70%; + } + + &:only-child { + flex-grow: 0; flex-shrink: 0; flex-basis: 100%; + & > div.concerned-groups { + flex-grow: 0; flex-shrink: 0; flex-basis: 100%; + display: flex; + flex-direction: column; // TODO pas fini + div.group { + flex-grow: 1; flex-shrink: 0; flex-basis: 30%; + h4 {} + ul.list-content { + li { + display: inline; + } + } + } + } + } + } + div.concerned-groups { + font-size: 85%; + h4 { + text-transform: uppercase; + } + } + } + ul.list-content { + list-style-type: none; + padding-left: 1em; + margin: 0 0; + li { + margin-bottom: 0.2em; + } + } + } + div.duration { + font-size: smaller; + padding-left: 1em; + margin-top: 1em; + } +} diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/App.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/App.vue new file mode 100644 index 000000000..bf8467c2b --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/App.vue @@ -0,0 +1,170 @@ + + + + + diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/PersonBadge.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/PersonBadge.vue new file mode 100644 index 000000000..e27feb886 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/PersonBadge.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/PersonsBloc.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/PersonsBloc.vue new file mode 100644 index 000000000..f95e2add7 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/PersonsBloc.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/i18n.js b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/i18n.js new file mode 100644 index 000000000..778072e61 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/i18n.js @@ -0,0 +1,20 @@ +import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n' + +const appMessages = { + fr: { + activity: { + add_persons: "Ajouter des personnes concernées", + bloc_persons: "Usagers", + bloc_persons_associated: "Usagers du parcours", + bloc_persons_not_associated: "Tiers non-pro.", + bloc_thirdparty: "Tiers professionnels", + bloc_users: "T(M)S", + } + } +} + +Object.assign(appMessages.fr, personMessages.fr); + +export { + appMessages +}; diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/index.js b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/index.js new file mode 100644 index 000000000..bd850419e --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/index.js @@ -0,0 +1,16 @@ +import { createApp } from 'vue'; +import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n' +import { appMessages } from './i18n' +import store from './store' + +import App from './App.vue'; + +const i18n = _createI18n(appMessages); + +const app = createApp({ + template: ``, +}) +.use(store) +.use(i18n) +.component('app', App) +.mount('#activity'); diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js new file mode 100644 index 000000000..4f30cf516 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/store.js @@ -0,0 +1,98 @@ +import 'es6-promise/auto'; +import { createStore } from 'vuex'; + +const debug = process.env.NODE_ENV !== 'production'; +//console.log('window.activity', window.activity); + +const addIdToValue = (string, id) => { + let array = string ? string.split(',') : []; + array.push(id.toString()); + let str = array.join(); + return str; +}; + +const removeIdFromValue = (string, id) => { + let array = string.split(','); + array = array.filter(el => el !== id.toString()); + let str = array.join(); + return str; +}; + +const store = createStore({ + strict: debug, + state: { + activity: window.activity + }, + getters: { + }, + mutations: { + addPersonsInvolved(state, payload) { + //console.log('### mutation addPersonsInvolved', payload.result.type); + switch (payload.result.type) { + case 'person': + state.activity.persons.push(payload.result); + break; + case 'thirdparty': + state.activity.thirdParties.push(payload.result); + break; + case 'user': + state.activity.users.push(payload.result); + break; + }; + }, + removePersonInvolved(state, payload) { + //console.log('### mutation removePersonInvolved', payload.type); + switch (payload.type) { + case 'person': + state.activity.persons = state.activity.persons.filter(person => person !== payload); + break; + case 'thirdparty': + state.activity.thirdParties = state.activity.thirdParties.filter(thirdparty => thirdparty !== payload); + break; + case 'user': + state.activity.users = state.activity.users.filter(user => user !== payload); + break; + }; + } + }, + actions: { + addPersonsInvolved({ commit }, payload) { + console.log('### action addPersonsInvolved', payload.result.type); + switch (payload.result.type) { + case 'person': + let aPersons = document.getElementById("chill_activitybundle_activity_persons"); + aPersons.value = addIdToValue(aPersons.value, payload.result.id); + break; + case 'thirdparty': + let aThirdParties = document.getElementById("chill_activitybundle_activity_thirdParties"); + aThirdParties.value = addIdToValue(aThirdParties.value, payload.result.id); + break; + case 'user': + let aUsers = document.getElementById("chill_activitybundle_activity_users"); + aUsers.value = addIdToValue(aUsers.value, payload.result.id); + break; + }; + commit('addPersonsInvolved', payload); + }, + removePersonInvolved({ commit }, payload) { + console.log('### action removePersonInvolved', payload); + switch (payload.type) { + case 'person': + let aPersons = document.getElementById("chill_activitybundle_activity_persons"); + aPersons.value = removeIdFromValue(aPersons.value, payload.id); + break; + case 'thirdparty': + let aThirdParties = document.getElementById("chill_activitybundle_activity_thirdParties"); + aThirdParties.value = removeIdFromValue(aThirdParties.value, payload.id); + break; + case 'user': + let aUsers = document.getElementById("chill_activitybundle_activity_users"); + aUsers.value = removeIdFromValue(aUsers.value, payload.id); + break; + }; + commit('removePersonInvolved', payload); + } + } +}); + +export default store; diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/concernedGroups.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/concernedGroups.html.twig new file mode 100644 index 000000000..0e0f8695a --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/concernedGroups.html.twig @@ -0,0 +1,97 @@ +{% macro href(pathname, key, value) %} + {% set parms = { (key): value } %} + {{ path(pathname, parms) }} +{% endmacro %} + +{% if context == 'person' %} + {% set blocs = [ + { 'title': 'Others persons'|trans, + 'items': entity.persons, + 'path' : 'chill_person_view', + 'key' : 'person_id' + }, + { 'title': 'Third parties'|trans, + 'items': entity.thirdParties, + 'path' : 'chill_3party_3party_show', + 'key' : 'thirdparty_id' + }, + { 'title': 'Users concerned'|trans, + 'items': entity.users, + 'path' : 'admin_user_show', + 'key' : 'id' + }, + ] %} +{% else %} + {% set blocs = [ + { 'title': 'Persons in accompanying course'|trans, + 'items': entity.personsAssociated, + 'path' : 'chill_person_view', + 'key' : 'person_id' + }, + { 'title': 'Third persons'|trans, + 'items': entity.personsNotAssociated, + 'path' : 'chill_person_view', + 'key' : 'person_id' + }, + { 'title': 'Third parties'|trans, + 'items': entity.thirdParties, + 'path' : 'chill_3party_3party_show', + 'key' : 'thirdparty_id' + }, + { 'title': 'Users concerned'|trans, + 'items': entity.users, + 'path' : 'admin_user_show', + 'key' : 'id' + }, + ] %} +{% endif %} + +{% if (with_display == 'bloc') %} +
+ {% for bloc in blocs %} +
+
+
+

{{ bloc.title }}

+
+
+ +
+
+
+ {% endfor %} +
+{% endif %} + +{% if (with_display == 'row') %} +
+ {% for bloc in blocs %} +
+ {% if bloc.items|length > 0 %} +

{{ bloc.title }}

+ + {% endif %} +
+ {% endfor %} +
+{% endif %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/confirm_deleteAccompanyingCourse.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/confirm_deleteAccompanyingCourse.html.twig new file mode 100644 index 000000000..fbdf45c23 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/confirm_deleteAccompanyingCourse.html.twig @@ -0,0 +1,16 @@ +{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %} + +{% set activeRouteKey = 'chill_activity_activity_list' %} + +{% block title 'Remove activity'|trans %} + +{% block content %} + {{ include('@ChillMain/Util/confirmation_template.html.twig', + { + 'title' : 'Remove activity'|trans, + 'confirm_question' : 'Are you sure you want to remove the activity about "%name%" ?'|trans({ '%name%' : accompanyingCourse.id } ), + 'cancel_route' : 'chill_activity_activity_list', + 'cancel_parameters' : { 'accompanying_course_id' : accompanyingCourse.id, 'id' : activity.id }, + 'form' : delete_form + } ) }} +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/confirm_delete.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/confirm_deletePerson.html.twig similarity index 99% rename from src/Bundle/ChillActivityBundle/Resources/views/Activity/confirm_delete.html.twig rename to src/Bundle/ChillActivityBundle/Resources/views/Activity/confirm_deletePerson.html.twig index 5cd8f15a0..2d8e2affc 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/confirm_delete.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/confirm_deletePerson.html.twig @@ -6,7 +6,6 @@ {% block title 'Remove activity'|trans %} {% block personcontent %} - {{ include('@ChillMain/Util/confirmation_template.html.twig', { 'title' : 'Remove activity'|trans, @@ -15,5 +14,4 @@ 'cancel_parameters' : { 'person_id' : activity.person.id, 'id' : activity.id }, 'form' : delete_form } ) }} - {% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/edit.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/edit.html.twig index 7a69a8eee..3024148e1 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/edit.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/edit.html.twig @@ -1,59 +1,101 @@ -{# - * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . -#} -{% extends "@ChillPerson/layout.html.twig" %} +

{{ "Update activity"|trans }}

-{% set activeRouteKey = 'chill_activity_activity_list' %} +{{ form_start(edit_form) }} +{{ form_errors(edit_form) }} -{% block title 'Update activity'|trans %} +{%- if edit_form.emergency is defined -%} + {{ form_row(edit_form.emergency) }} +{% endif %} -{% block personcontent %} -

{{ "Update activity"|trans }}

- - {{ form_start(edit_form) }} +{%- if edit_form.sentReceived is defined -%} + {{ form_row(edit_form.sentReceived) }} +{% endif %} +{%- if edit_form.user is defined -%} {{ form_row(edit_form.user) }} +{% endif %} + +{%- if edit_form.scope is defined -%} {{ form_row(edit_form.scope) }} +{% endif %} -

{{ 'Activity data'|trans }}

- {{ form_row(edit_form.date) }} - {{ form_row(edit_form.durationTime) }} - {{ form_row(edit_form.type) }} - {{ form_row(edit_form.attendee) }} +{%- if edit_form.socialActions is defined -%} + {{ form_row(edit_form.socialActions) }} +{% endif %} + +{%- if edit_form.socialIssues is defined -%} + {{ form_row(edit_form.socialIssues) }} +{% endif %} + +{%- if edit_form.reasons is defined -%} {{ form_row(edit_form.reasons) }} +{% endif %} + +

{{ 'Concerned groups'|trans }}

+ +{%- if edit_form.persons is defined -%} + {{ form_widget(edit_form.persons) }} +{% endif %} +{%- if edit_form.thirdParties is defined -%} + {{ form_widget(edit_form.thirdParties) }} +{% endif %} +{%- if edit_form.users is defined -%} + {{ form_widget(edit_form.users) }} +{% endif %} + +
+ +

{{ 'Activity data'|trans }}

+ +{%- if edit_form.date is defined -%} + {{ form_row(edit_form.date) }} +{% endif %} + +.. location + +{%- if edit_form.durationTime is defined -%} + {{ form_row(edit_form.durationTime) }} +{% endif %} + +{%- if edit_form.travelTime is defined -%} + {{ form_row(edit_form.travelTime) }} +{% endif %} + +{%- if edit_form.comment is defined -%} + .. public and private {{ form_row(edit_form.comment) }} +{% endif %} - {{ form_widget(edit_form) }} - - {{ form_end(edit_form) }} +{%- if edit_form.documents is defined -%} + {{ form_row(edit_form.documents) }} +{% endif %} - {# {{ form(delete_form) }} #} -{% endblock %} +{%- if edit_form.attendee is defined -%} + {{ form_row(edit_form.attendee) }} +{% endif %} -{% block js %} - -{% endblock %} +.. status + +{% set person_id = null %} +{% if entity.person %} + {% set person_id = entity.person.id %} +{% endif %} + +{% set accompanying_course_id = null %} +{% if accompanyingCourse %} + {% set accompanying_course_id = accompanyingCourse.id %} +{% endif %} + + +{{ form_end(edit_form) }} + +{# {{ form(delete_form) }} #} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/editAccompanyingCourse.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/editAccompanyingCourse.html.twig new file mode 100644 index 000000000..aa64bc388 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/editAccompanyingCourse.html.twig @@ -0,0 +1,25 @@ +{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %} + +{% set activeRouteKey = 'chill_activity_activity_list' %} + +{% block title 'Update activity'|trans %} + +{% block content %} +
{# <=== vue component #} + {% include 'ChillActivityBundle:Activity:edit.html.twig' %} +{% endblock %} + +{% block js %} + {{ encore_entry_link_tags('async_upload') }} + + {{ encore_entry_script_tags('vue_activity') }} +{% endblock %} + +{% block css %} + {{ encore_entry_link_tags('async_upload') }} + {{ encore_entry_link_tags('vue_activity') }} +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/editPerson.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/editPerson.html.twig new file mode 100644 index 000000000..d8d3df0bd --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/editPerson.html.twig @@ -0,0 +1,41 @@ +{# + * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} +{% extends "@ChillPerson/layout.html.twig" %} + +{% set activeRouteKey = 'chill_activity_activity_list' %} + +{% block title 'Update activity'|trans %} + +{% block personcontent %} + {% include 'ChillActivityBundle:Activity:edit.html.twig' %} +
{# <=== vue component #} +{% endblock %} + +{% block js %} + {{ encore_entry_link_tags('async_upload') }} + + {{ encore_entry_script_tags('vue_activity') }} +{% endblock %} + +{% block css %} + {{ encore_entry_link_tags('async_upload') }} + {{ encore_entry_link_tags('vue_activity') }} +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/list.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/list.html.twig index 94a9d9a82..c84d61009 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/list.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/list.html.twig @@ -1,87 +1,179 @@ -{# - * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . -#} -{% extends "@ChillPerson/layout.html.twig" %} +{% set person_id = null %} +{% if person %} + {% set person_id = person.id %} +{% endif %} -{% set activeRouteKey = 'chill_activity_activity_list' %} +{% set accompanying_course_id = null %} +{% if accompanyingCourse %} + {% set accompanying_course_id = accompanyingCourse.id %} +{% endif %} -{% block title %}{{ 'Activity list' |trans }}{% endblock title %} +

{{ 'Activity list' |trans }}

-{% block personcontent %} -

{{ 'Activity list' |trans }}

+{% if activities|length == 0 %} +

+ {{ "There isn't any activities."|trans }} + +

+{% else %} - {% if activities|length == 0 %} -

- {{ "There isn't any activities."|trans }} - -

- {% else %} - - - - - - - - - - - - {% for activity in activities %} - - - - - - - - {% endfor %} - -
{{'Date' | trans }}{{'Duration Time' | trans }}{{'Reasons' | trans}}{{'Type' | trans}} 
{% if activity.date %}{{ activity.date|format_date('long') }}{% endif %}{{ activity.durationTime|date('H:i') }} - {% if activity.comment.comment is not empty %} - {{ activity.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }} +
+ + {% for activity in activities %} + {% set t = activity.type %} +
+
+
+ + {% if activity.date %} +

{{ activity.date|format_date('long') }}

{% endif %} - {%- if activity.reasons is empty -%} - {{ 'No reason associated'|trans }} - {%- else -%} - {% for r in activity.reasons %}{{ r|chill_entity_render_box }} {% endfor %} - {%- endif -%} -
{{ activity.type.name | localize_translatable_string }} + +
+ {% if t.durationTimeVisible > 0 %} +

+ + {{ activity.durationTime|date('H:i') }} +

+ {% endif %} + + {% if activity.travelTime and t.travelTimeVisible %} +

+ + {{ activity.travelTime|date('H:i') }} +

+ {% endif %} +
+ + +
+
    + {% if activity.user and t.userVisible %} +
  • + {{ 'by'|trans }}{{ activity.user.usernameCanonical }} +
  • + {% endif %} + +
  • + {{ activity.type.name | localize_translatable_string }} + + {% if activity.attendee is not null and t.attendeeVisible %} + {% if activity.attendee %} + {{ '→ ' ~ 'present'|trans|capitalize }} + {% else %} + {{ '→ ' ~ 'not present'|trans|capitalize }} + {% endif %} + {% endif %} +
  • + +
  • + {{ 'location'|trans ~ ': ' }} + Domicile de l'usager + {# + {% if activity.location %}{{ activity.location }}{% endif %} + #} +
  • + + {%- if t.reasonsVisible -%} +
  • + {%- if activity.reasons is empty -%} + {{ 'No reason associated'|trans }} + {%- else -%} + {% for r in activity.reasons %} + {{ r|chill_entity_render_box }} + {% endfor %} + {%- endif -%} +
  • + {% endif %} + + {%- if t.socialIssuesVisible %} + + {% endif %} + + {%- if t.socialActionsVisible -%} + + {% endif %} + + +
  • - +
  • + {# TOOD {% if is_granted('CHILL_ACTIVITY_UPDATE', activity) %} + #}
  • - +
  • + {# TOOD {% endif %} {% if is_granted('CHILL_ACTIVITY_DELETE', activity) %} + #}
  • - +
  • + {# {% endif %} -
- {% endif %} + #} + + + + + {% + if activity.comment.comment is not empty + or activity.persons|length > 0 + or activity.thirdParties|length > 0 + or activity.users|length > 0 + %} +
+
+ {% include 'ChillActivityBundle:Activity:concernedGroups.html.twig' with {'context': context, 'with_display': 'row', 'entity': activity } %} +
+ + {% if activity.comment.comment is not empty %} +
+ {{ activity.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }} +
+ {% endif %} +
+ {% endif %} + + + {% endfor %} + +{% endif %} - -{% endblock %} + diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig new file mode 100644 index 000000000..53e7ec86e --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/listAccompanyingCourse.html.twig @@ -0,0 +1,9 @@ +{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %} + +{% set activeRouteKey = 'chill_activity_activity_list' %} + +{% block title %}{{ 'Activity list' |trans }}{% endblock title %} + +{% block content %} + {% include 'ChillActivityBundle:Activity:list.html.twig' with {'context': 'accompanyingCourse'} %} +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/listPerson.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/listPerson.html.twig new file mode 100644 index 000000000..6856459c6 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/listPerson.html.twig @@ -0,0 +1,25 @@ +{# + * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} +{% extends "@ChillPerson/layout.html.twig" %} + +{% set activeRouteKey = 'chill_activity_activity_list' %} + +{% block title %}{{ 'Activity list' |trans }}{% endblock title %} + +{% block personcontent %} + {% include 'ChillActivityBundle:Activity:list.html.twig' with {'context': 'person'} %} +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/new.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/new.html.twig index e069bfce3..b65a3268c 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/new.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/new.html.twig @@ -1,50 +1,100 @@ -{# - * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . -#} -{% extends "@ChillPerson/layout.html.twig" %} +

{{ "Activity creation"|trans }}

-{% set activeRouteKey = 'chill_activity_activity_new' %} +{{ form_start(form) }} +{{ form_errors(form) }} -{% block title 'Activity creation' |trans %} -{% block personcontent %} -

{{ "Activity creation"|trans }}

+{%- if form.emergency is defined -%} + {{ form_row(form.emergency) }} +{% endif %} - {{ form_start(form) }} +{%- if form.sentReceived is defined -%} + {{ form_row(form.sentReceived) }} +{% endif %} +{%- if form.user is defined -%} {{ form_row(form.user) }} +{% endif %} + +{%- if form.scope is defined -%} {{ form_row(form.scope) }} +{% endif %} -

{{ 'Activity data'|trans }}

+{%- if form.socialActions is defined -%} + {{ form_row(form.socialActions) }} +{% endif %} - {{ form_row(form.date) }} - {{ form_row(form.durationTime) }} - {{ form_row(form.type) }} - {{ form_row(form.attendee) }} +{%- if form.socialIssues is defined -%} + {{ form_row(form.socialIssues) }} +{% endif %} + + +{%- if form.reasons is defined -%} {{ form_row(form.reasons) }} +{% endif %} + +

{{ 'Concerned groups'|trans }}

+ +{%- if form.persons is defined -%} + {{ form_widget(form.persons) }} +{% endif %} +{%- if form.thirdParties is defined -%} + {{ form_widget(form.thirdParties) }} +{% endif %} +{%- if form.users is defined -%} + {{ form_widget(form.users) }} +{% endif %} + +
+ +

{{ 'Activity data'|trans }}

+ +{%- if form.date is defined -%} + {{ form_row(form.date) }} +{% endif %} + +.. location + +{%- if form.durationTime is defined -%} + {{ form_row(form.durationTime) }} +{% endif %} + +{%- if form.travelTime is defined -%} + {{ form_row(form.travelTime) }} +{% endif %} + +{%- if form.comment is defined -%} + .. public and private {{ form_row(form.comment) }} +{% endif %} -
- -
- {{ form_end(form) }} -{% endblock %} +{%- if form.documents is defined -%} + {{ form_row(form.documents) }} +{% endif %} -{% block js %} - -{% endblock %} +{%- if form.attendee is defined -%} + {{ form_row(form.attendee) }} +{% endif %} + +.. status + + +{{ form_end(form) }} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/newAccompanyingCourse.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/newAccompanyingCourse.html.twig new file mode 100644 index 000000000..f5e3a8629 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/newAccompanyingCourse.html.twig @@ -0,0 +1,25 @@ +{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %} + +{% set activeRouteKey = 'chill_activity_activity_new' %} + +{% block title 'Activity creation' |trans %} + +{% block content %} +
{# <=== vue component #} + {% include 'ChillActivityBundle:Activity:new.html.twig' with {'context': 'accompanyingCourse'} %} +{% endblock %} + +{% block js %} + {{ encore_entry_script_tags('async_upload') }} + + {{ encore_entry_script_tags('vue_activity') }} +{% endblock %} + +{% block css %} + + {{ encore_entry_link_tags('vue_activity') }} +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/newPerson.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/newPerson.html.twig new file mode 100644 index 000000000..67eebdea0 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/newPerson.html.twig @@ -0,0 +1,25 @@ +{% extends "@ChillPerson/layout.html.twig" %} + +{% set activeRouteKey = 'chill_activity_activity_new' %} + +{% block title 'Activity creation' |trans %} + +{% block personcontent %} + {% include 'ChillActivityBundle:Activity:new.html.twig' with {'context': 'person'} %} +
{# <=== vue component #} +{% endblock %} + +{% block js %} + {{ encore_entry_link_tags('async_upload') }} + + {{ encore_entry_script_tags('vue_activity') }} +{% endblock %} + +{% block css %} + {{ encore_entry_link_tags('async_upload') }} + {{ encore_entry_link_tags('vue_activity') }} +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/selectType.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/selectType.html.twig new file mode 100644 index 000000000..76e3f25ad --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/selectType.html.twig @@ -0,0 +1,28 @@ +

{{ "Activity creation"|trans }}

+ +{# TODO: refaire l'html css des tuilles #} + +{% for row in data %} +

{{ row.activityTypeCategory.name|localize_translatable_string }}

+
+ {% for activityType in row.activityTypes %} + + {% set person_id = null %} + {% if person %} + {% set person_id = person.id %} + {% endif %} + + {% set accompanying_course_id = null %} + {% if accompanyingCourse %} + {% set accompanying_course_id = accompanyingCourse.id %} + {% endif %} + + + +
+ {{ activityType.name|localize_translatable_string }} +
+
+ {% endfor %} +
+{% endfor %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/selectTypeAccompanyingCourse.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/selectTypeAccompanyingCourse.html.twig new file mode 100644 index 000000000..5e73db597 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/selectTypeAccompanyingCourse.html.twig @@ -0,0 +1,9 @@ +{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %} + +{% set activeRouteKey = 'chill_activity_activity_new' %} + +{% block title 'Activity creation'|trans %} + +{% block content %} + {% include 'ChillActivityBundle:Activity:selectType.html.twig' %} +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/selectTypePerson.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/selectTypePerson.html.twig new file mode 100644 index 000000000..cb31749fd --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/selectTypePerson.html.twig @@ -0,0 +1,9 @@ +{% extends "@ChillPerson/layout.html.twig" %} + +{% set activeRouteKey = 'chill_activity_activity_new' %} + +{% block title 'Activity creation'|trans %} + +{% block personcontent %} + {% include 'ChillActivityBundle:Activity:selectType.html.twig' %} +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/show.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/show.html.twig index 73e91e8c5..584c0d149 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/show.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/show.html.twig @@ -1,68 +1,134 @@ -{% extends "@ChillPerson/layout.html.twig" %} +{%- set t = entity.type -%} +{%- import "@ChillDocStore/Macro/macro.html.twig" as m -%} -{% set activeRouteKey = 'chill_activity_activity_list' %} +

+ {{ "Activity"|trans }} + {%- if t.emergencyVisible and entity.emergency -%} + + {{- 'Emergency'|trans -}} + +{%- endif -%} +

-{% block title 'Activity'|trans %} +
-{% import 'ChillActivityBundle:ActivityReason:macro.html.twig' as m %} +
{{ 'by'|trans|capitalize }}
+
{{ entity.user }}
-{% block personcontent -%} -

{{ "Activity"|trans }}

+
{{ 'Type'|trans }}
+
{{ entity.type.name | localize_translatable_string }}
-
-
{{ 'User'|trans }}
-
{{ entity.user }}
+ {%- if entity.scope -%}
{{ 'Scope'|trans }}
{{ entity.scope.name|localize_translatable_string }}
+ {% endif %} -

{{ 'Activity data'|trans }}

-
{{ 'Person'|trans }}
-
{{ entity.person }}
- -
{{ 'Date'|trans }}
-
{{ entity.date|format_date('long') }}
-
{{ 'Duration Time'|trans }}
-
{{ entity.durationTime|date('H:i') }}
-
{{ 'Type'|trans }}
-
{{ entity.type.name | localize_translatable_string }}
- -
{{ 'Attendee'|trans }}
-
{% if entity.attendee is not null %}{% if entity.attendee %}{{ 'present'|trans|capitalize }} {% else %} {{ 'not present'|trans|capitalize }}{% endif %}{% else %}{{ 'None'|trans|capitalize }}{% endif %}
- -
{{ 'Reasons'|trans }}
- {%- if entity.reasons is empty -%} -
{{ 'No reason associated'|trans }}
- {%- else -%} -
{% for r in entity.reasons %}{{ r|chill_entity_render_box }} {% endfor %}
- {%- endif -%} - -
{{ 'Comment'|trans }}
- {%- if entity.comment is empty -%} -
{{ 'No comment associated'|trans }}
- {%- else -%} -
{{ entity.comment|chill_entity_render_box }}
- {%- endif -%} - -
- - + + {% endif %} -{% endblock personcontent %} + {% if t.socialActionsVisible %} +
{{ 'Social actions'|trans }}
+
+ {% if entity.socialActions|length == 0 %} +

{{ 'Any social actions'|trans }}

+ {% else %} + {% for sa in entity.socialActions %}{{ sa|chill_entity_render_box }}{% endfor %} + {% endif %} +
+ {% endif %} + + {% if t.reasonsVisible %} +
{{ 'Reasons'|trans }}
+ {%- if entity.reasons is empty -%} +
{{ 'No reason associated'|trans }}
+ {%- else -%} +
{% for r in entity.reasons %}{{ r|chill_entity_render_box }} {% endfor %}
+ {%- endif -%} + {% endif %} + +

{{ 'Concerned groups'|trans }}

+{% include 'ChillActivityBundle:Activity:concernedGroups.html.twig' with {'context': context, 'with_display': 'bloc' } %} + +

{{ 'Activity data'|trans }}

+ +
{{ 'Date'|trans }}
+
{{ entity.date|format_date('long') }}
+ + {% if t.durationTimeVisible %} +
{{ 'Duration Time'|trans }}
+
{{ entity.durationTime|date('H:i') }}
+ {% endif %} + + {% if t.travelTimeVisible %} +
{{ 'Travel Time'|trans }}
+
{{ entity.travelTime|date('H:i') }}
+ {% endif %} + + {% if t.commentVisible %} +
{{ 'Comment'|trans }}
+ {%- if entity.comment.empty -%} +
{{ 'No comment associated'|trans }}
+ {%- else -%} +
{{ entity.comment|chill_entity_render_box }}
+ {%- endif -%} + {% endif %} + + {% if t.documentsVisible and entity.documents|length > 0 %} +
{{ 'Documents'|trans }}
+
+
    + {% for d in entity.documents %} +
  • {{ m.download_button(d) }}
  • + {% endfor %} +
+
+ {% endif %} + + {% if t.attendeeVisible %} +
{{ 'Attendee'|trans }}
+
{% if entity.attendee is not null %}{% if entity.attendee %}{{ 'present'|trans|capitalize }} {% else %} {{ 'not present'|trans|capitalize }}{% endif %}{% else %}{{ 'None'|trans|capitalize }}{% endif %}
+ {% endif %} + +
+ +{% set person_id = null %} +{% if person %} + {% set person_id = person.id %} +{% endif %} + +{% set accompanying_course_id = null %} +{% if accompanyingCourse %} + {% set accompanying_course_id = accompanyingCourse.id %} +{% endif %} + + diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/showAccompanyingCourse.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/showAccompanyingCourse.html.twig new file mode 100644 index 000000000..fc046ed7e --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/showAccompanyingCourse.html.twig @@ -0,0 +1,11 @@ +{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %} + +{% set activeRouteKey = 'chill_activity_activity_list' %} + +{% block title 'Activity'|trans %} + +{% import 'ChillActivityBundle:ActivityReason:macro.html.twig' as m %} + +{% block content -%} + {% include 'ChillActivityBundle:Activity:show.html.twig' with {'context': 'accompanyingCourse'} %} +{% endblock content %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/showPerson.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/showPerson.html.twig new file mode 100644 index 000000000..b42de7b7e --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/showPerson.html.twig @@ -0,0 +1,11 @@ +{% extends "@ChillPerson/layout.html.twig" %} + +{% set activeRouteKey = 'chill_activity_activity_list' %} + +{% block title 'Activity'|trans %} + +{% import 'ChillActivityBundle:ActivityReason:macro.html.twig' as m %} + +{% block personcontent -%} + {% include 'ChillActivityBundle:Activity:show.html.twig' with {'context': 'person'} %} +{% endblock personcontent %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/ActivityPresence/edit.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/ActivityPresence/edit.html.twig new file mode 100644 index 000000000..16cf893e8 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/ActivityPresence/edit.html.twig @@ -0,0 +1,12 @@ +{% extends "@ChillActivity/Admin/layout_activity.html.twig" %} + +{% block title %} +{% include('@ChillMain/CRUD/_edit_title.html.twig') %} +{% endblock %} + +{% block layout_wvm_content %} +{% embed '@ChillMain/CRUD/_edit_content.html.twig' %} + {% block content_form_actions_view %}{% endblock %} + {% block content_form_actions_save_and_show %}{% endblock %} +{% endembed %} +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/ActivityPresence/index.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/ActivityPresence/index.html.twig new file mode 100644 index 000000000..04f0f5dec --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/ActivityPresence/index.html.twig @@ -0,0 +1,44 @@ +{% extends "@ChillActivity/Admin/layout_activity.html.twig" %} + +{% block admin_content %} +

{{ 'ActivityPresence list'|trans }}

+ + + + + + + + + + + {% for entity in entities %} + + + + + + {% endfor %} + +
{{ 'Name'|trans }}{{ 'Active'|trans }}{{ 'Actions'|trans }}
{{ entity.name|localize_translatable_string }} + {%- if entity.active -%} + + {%- else -%} + + {%- endif -%} + +
    +
  • + +
  • +
+
+ + +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/ActivityPresence/new.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/ActivityPresence/new.html.twig new file mode 100644 index 000000000..c95711529 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/ActivityPresence/new.html.twig @@ -0,0 +1,11 @@ +{% extends "@ChillActivity/Admin/layout_activity.html.twig" %} + +{% block title %} +{% include('@ChillMain/CRUD/_new_title.html.twig') %} +{% endblock %} + +{% block layout_wvm_content %} +{% embed '@ChillMain/CRUD/_new_content.html.twig' %} + {% block content_form_actions_save_and_show %}{% endblock %} +{% endembed %} +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/edit.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/edit.html.twig index 99bc71057..dacee767c 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/edit.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/edit.html.twig @@ -1,40 +1,12 @@ -{# - * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . -#} {% extends "@ChillActivity/Admin/layout_activity.html.twig" %} -{% block admin_content %} -

{{ 'ActivityType edit'|trans }}

- - {{ form_start(edit_form) }} - {{ form_row(edit_form.active) }} - {{ form_row(edit_form.name) }} - - - - - - {{ form_end(edit_form) }} +{% block title %} + {% include('@ChillMain/CRUD/_edit_title.html.twig') %} +{% endblock %} + +{% block layout_wvm_content %} + {% embed '@ChillMain/CRUD/_edit_content.html.twig' %} + {% block content_form_actions_view %}{% endblock %} + {% block content_form_actions_save_and_show %}{% endblock %} + {% endembed %} {% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/index.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/index.html.twig index d9f0cbca6..fd1fd8e29 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/index.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/index.html.twig @@ -30,7 +30,7 @@ {% for entity in entities %} - {{ entity.name|localize_translatable_string }} + {{ entity.name|localize_translatable_string }} {%- if entity.active -%} @@ -41,10 +41,7 @@
  • - -
  • -
  • - +
@@ -55,7 +52,7 @@
  • - + {{ 'Create a new activity type'|trans }}
  • diff --git a/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/new.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/new.html.twig index efc294efd..d7ac89752 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/new.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/new.html.twig @@ -1,38 +1,11 @@ -{# - * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . -#} {% extends "@ChillActivity/Admin/layout_activity.html.twig" %} -{% block admin_content %} -

    {{ 'ActivityType creation'|trans }}

    - - {{ form_start(form) }} - {{ form_row(form.active) }} - {{ form_row(form.name) }} - - - {{ form_end(form) }} - +{% block title %} + {% include('@ChillMain/CRUD/_new_title.html.twig') %} +{% endblock %} + +{% block layout_wvm_content %} + {% embed '@ChillMain/CRUD/_new_content.html.twig' %} + {% block content_form_actions_save_and_show %}{% endblock %} + {% endembed %} {% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/show.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/show.html.twig deleted file mode 100644 index bce0ed95b..000000000 --- a/src/Bundle/ChillActivityBundle/Resources/views/ActivityType/show.html.twig +++ /dev/null @@ -1,42 +0,0 @@ -{# - * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . -#} -{% extends "@ChillActivity/Admin/layout_activity.html.twig" %} - -{% block admin_content %} -

    {{ 'ActivityType'|trans }}

    - - - - - - - - -
    {{ 'Name'|trans }}{{ entity.name|localize_translatable_string }}
    - -{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/ActivityTypeCategory/edit.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/ActivityTypeCategory/edit.html.twig new file mode 100644 index 000000000..16cf893e8 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/ActivityTypeCategory/edit.html.twig @@ -0,0 +1,12 @@ +{% extends "@ChillActivity/Admin/layout_activity.html.twig" %} + +{% block title %} +{% include('@ChillMain/CRUD/_edit_title.html.twig') %} +{% endblock %} + +{% block layout_wvm_content %} +{% embed '@ChillMain/CRUD/_edit_content.html.twig' %} + {% block content_form_actions_view %}{% endblock %} + {% block content_form_actions_save_and_show %}{% endblock %} +{% endembed %} +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/ActivityTypeCategory/index.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/ActivityTypeCategory/index.html.twig new file mode 100644 index 000000000..2834e50dd --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/ActivityTypeCategory/index.html.twig @@ -0,0 +1,44 @@ +{% extends "@ChillActivity/Admin/layout_activity.html.twig" %} + +{% block admin_content %} +

    {{ 'ActivityTypeCategory list'|trans }}

    + + + + + + + + + + + {% for entity in entities %} + + + + + + {% endfor %} + +
    {{ 'Name'|trans }}{{ 'Active'|trans }}{{ 'Actions'|trans }}
    {{ entity.name|localize_translatable_string }} + {%- if entity.active -%} + + {%- else -%} + + {%- endif -%} + +
      +
    • + +
    • +
    +
    + + +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/ActivityTypeCategory/new.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/ActivityTypeCategory/new.html.twig new file mode 100644 index 000000000..c95711529 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Resources/views/ActivityTypeCategory/new.html.twig @@ -0,0 +1,11 @@ +{% extends "@ChillActivity/Admin/layout_activity.html.twig" %} + +{% block title %} +{% include('@ChillMain/CRUD/_new_title.html.twig') %} +{% endblock %} + +{% block layout_wvm_content %} +{% embed '@ChillMain/CRUD/_new_content.html.twig' %} + {% block content_form_actions_save_and_show %}{% endblock %} +{% endembed %} +{% endblock %} diff --git a/src/Bundle/ChillActivityBundle/chill.webpack.config.js b/src/Bundle/ChillActivityBundle/chill.webpack.config.js index 724184f63..d40ae2d4a 100644 --- a/src/Bundle/ChillActivityBundle/chill.webpack.config.js +++ b/src/Bundle/ChillActivityBundle/chill.webpack.config.js @@ -1,4 +1,10 @@ // this file loads all assets from the Chill person bundle module.exports = function(encore, entries) { entries.push(__dirname + '/Resources/public/index.js'); + + encore.addAliases({ + ChillActivityAssets: __dirname + '/Resources/public' + }); + + encore.addEntry('vue_activity', __dirname + '/Resources/public/vuejs/Activity/index.js'); }; diff --git a/src/Bundle/ChillActivityBundle/config/routes.yaml b/src/Bundle/ChillActivityBundle/config/routes.yaml index 86b5d6764..5403529ae 100644 --- a/src/Bundle/ChillActivityBundle/config/routes.yaml +++ b/src/Bundle/ChillActivityBundle/config/routes.yaml @@ -10,10 +10,6 @@ chill_activity_activityreasoncategory: resource: "@ChillActivityBundle/config/routes/activityreasoncategory.yaml" prefix: / -chill_activity_activitytype: - resource: "@ChillActivityBundle/config/routes/activitytype.yaml" - prefix: / - chill_admin_activity_index: path: /{_locale}/admin/activity controller: Chill\ActivityBundle\Controller\AdminController::indexActivityAction @@ -32,3 +28,30 @@ chill_admin_activity_redirect_to_admin_index: admin_activity: order: 0 label: Main admin menu + +chill_activity_type_admin: + path: /{_locale}/admin/activity/type + controller: cscrud_activity_type_controller:index + options: + menus: + admin_activity: + order: 2020 + label: 'Activity Types' + +chill_activity_type_category_admin: + path: /{_locale}/admin/activity/type_category + controller: cscrud_activity_type_category_controller:index + options: + menus: + admin_activity: + order: 2999 + label: 'Activity Types Categories' + +chill_activity_presence_admin: + path: /{_locale}/admin/activity/presence + controller: cscrud_activity_presence_controller:index + options: + menus: + admin_activity: + order: 2021 + label: 'Activity Presences' diff --git a/src/Bundle/ChillActivityBundle/config/routes/activity.yaml b/src/Bundle/ChillActivityBundle/config/routes/activity.yaml index a320bb2ac..179de905b 100644 --- a/src/Bundle/ChillActivityBundle/config/routes/activity.yaml +++ b/src/Bundle/ChillActivityBundle/config/routes/activity.yaml @@ -1,30 +1,26 @@ chill_activity_activity_list: - path: /{_locale}/person/{person_id}/activity/ + path: /{_locale}/activity/ controller: Chill\ActivityBundle\Controller\ActivityController::listAction chill_activity_activity_show: - path: /{_locale}/person/{person_id}/activity/{id}/show + path: /{_locale}/activity/{id}/show controller: Chill\ActivityBundle\Controller\ActivityController::showAction -chill_activity_activity_new: - path: /{_locale}/person/{person_id}/activity/new - controller: Chill\ActivityBundle\Controller\ActivityController::newAction +chill_activity_activity_select_type: + path: /{_locale}/activity/select-type + controller: Chill\ActivityBundle\Controller\ActivityController::selectTypeAction -chill_activity_activity_create: - path: /{_locale}/person/{person_id}/activity/create - controller: Chill\ActivityBundle\Controller\ActivityController::createAction - methods: POST +chill_activity_activity_new: + path: /{_locale}/activity/new + controller: Chill\ActivityBundle\Controller\ActivityController::newAction + methods: [POST, GET] chill_activity_activity_edit: - path: /{_locale}/person/{person_id}/activity/{id}/edit + path: /{_locale}/activity/{id}/edit controller: Chill\ActivityBundle\Controller\ActivityController::editAction - -chill_activity_activity_update: - path: /{_locale}/person/{person_id}/activity/{id}/update - controller: Chill\ActivityBundle\Controller\ActivityController::updateAction - methods: [POST, PUT] + methods: [GET, POST, PUT] chill_activity_activity_delete: - path: /{_locale}/person/{person_id}/activity/{id}/delete + path: /{_locale}/activity/{id}/delete controller: Chill\ActivityBundle\Controller\ActivityController::deleteAction methods: [GET, POST, DELETE] diff --git a/src/Bundle/ChillActivityBundle/config/routes/activitytype.yaml b/src/Bundle/ChillActivityBundle/config/routes/activitytype.yaml deleted file mode 100644 index 2995458f1..000000000 --- a/src/Bundle/ChillActivityBundle/config/routes/activitytype.yaml +++ /dev/null @@ -1,35 +0,0 @@ -chill_activity_activitytype: - path: /{_locale}/admin/activitytype/ - controller: Chill\ActivityBundle\Controller\ActivityTypeController::indexAction - options: - menus: - admin_activity: - order: 2020 - label: "Activity Types" - -chill_activity_activitytype_show: - path: /{_locale}/admin/activitytype/{id}/show - controller: Chill\ActivityBundle\Controller\ActivityTypeController::showAction - -chill_activity_activitytype_new: - path: /{_locale}/admin/activitytype/new - controller: Chill\ActivityBundle\Controller\ActivityTypeController::newAction - -chill_activity_activitytype_create: - path: /{_locale}/admin/activitytype/create - controller: Chill\ActivityBundle\Controller\ActivityTypeController::createAction - methods: POST - -chill_activity_activitytype_edit: - path: /{_locale}/admin/activitytype/{id}/edit - controller: Chill\ActivityBundle\Controller\ActivityTypeController::editAction - -chill_activity_activitytype_update: - path: /{_locale}/admin/activitytype/{id}/update - controller: Chill\ActivityBundle\Controller\ActivityTypeController::updateAction - methods: [POST, PUT] - -chill_activity_activitytype_delete: - path: /{_locale}/admin/activitytype/{id}/delete - controller: Chill\ActivityBundle\Controller\ActivityTypeController::deleteAction - methods: [POST, DELETE] diff --git a/src/Bundle/ChillActivityBundle/config/services/controller.yaml b/src/Bundle/ChillActivityBundle/config/services/controller.yaml index cf36e482d..106b2c6e4 100644 --- a/src/Bundle/ChillActivityBundle/config/services/controller.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/controller.yaml @@ -4,4 +4,5 @@ services: $eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface' $authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper' $logger: '@chill.main.logger' + $serializer: '@Symfony\Component\Serializer\SerializerInterface' tags: ['controller.service_arguments'] diff --git a/src/Bundle/ChillActivityBundle/config/services/form.yaml b/src/Bundle/ChillActivityBundle/config/services/form.yaml index e9f81c14e..3da20cce5 100644 --- a/src/Bundle/ChillActivityBundle/config/services/form.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/form.yaml @@ -6,7 +6,7 @@ services: - "@request_stack" tags: - { name: form.type, alias: translatable_activity_reason_category } - + chill.activity.form.type.translatableactivityreason: class: Chill\ActivityBundle\Form\Type\TranslatableActivityReason arguments: @@ -14,7 +14,7 @@ services: $reasonRender: '@Chill\ActivityBundle\Templating\Entity\ActivityReasonRender' tags: - { name: form.type, alias: translatable_activity_reason } - + chill.activity.form.type.translatableactivitytype: class: Chill\ActivityBundle\Form\Type\TranslatableActivityType arguments: @@ -22,7 +22,7 @@ services: - "@chill_activity.repository.activity_type" tags: - { name: form.type, alias: translatable_activity_type } - + chill.activity.form.type.activity: class: Chill\ActivityBundle\Form\ActivityType arguments: @@ -31,5 +31,13 @@ services: - "@doctrine.orm.entity_manager" - "@chill.main.helper.translatable_string" - "%chill_activity.form.time_duration%" + - '@Chill\PersonBundle\Templating\Entity\SocialIssueRender' tags: - { name: form.type, alias: chill_activitybundle_activity } + + chill.activity.form.type.activityTypeType: + class: Chill\ActivityBundle\Form\ActivityTypeType + arguments: + - "@chill.main.helper.translatable_string" + tags: + - { name: form.type, alias: translatable_activity_type } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210401090853.php b/src/Bundle/ChillActivityBundle/migrations/Version20210401090853.php new file mode 100644 index 000000000..43f8c8460 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210401090853.php @@ -0,0 +1,36 @@ +addSql('CREATE SEQUENCE activitytypecategory_id_seq INCREMENT BY 1 MINVALUE 1 START 1000'); + $this->addSql('CREATE TABLE activitytypecategory (id INT NOT NULL, name JSON NOT NULL, active BOOLEAN NOT NULL, PRIMARY KEY(id))'); + $this->addSql('COMMENT ON COLUMN activitytypecategory.name IS \'(DC2Type:json_array)\''); + $this->addSql('INSERT INTO activitytypecategory VALUES(1, \'{"fr": "Défaut", "en": "Default"}\', true)'); + + } + + public function down(Schema $schema) : void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP SEQUENCE activitytypecategory_id_seq CASCADE'); + $this->addSql('DROP TABLE activitytypecategory'); + } +} diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210408122329.php b/src/Bundle/ChillActivityBundle/migrations/Version20210408122329.php new file mode 100644 index 000000000..53a5219bd --- /dev/null +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210408122329.php @@ -0,0 +1,93 @@ +addSql('ALTER TABLE activitytype ADD personVisible SMALLINT DEFAULT 2 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD personLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD userVisible SMALLINT DEFAULT 2 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD userLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD dateVisible SMALLINT DEFAULT 2 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD dateLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD placeVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD placeLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD personsVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD personsLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD thirdpartyVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD thirdpartyLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD durationTimeVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD durationTimeLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD attendeeVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD attendeeLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD reasonsVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD reasonsLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD commentVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD commentLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD sentReceivedVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD sentReceivedLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD documentVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD documentLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD emergencyVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD emergencyLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD accompanyingPeriodVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD accompanyingPeriodLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD socialDataVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD socialDataLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ALTER name SET NOT NULL'); + $this->addSql('ALTER TABLE activitytype ALTER active DROP DEFAULT'); + $this->addSql('COMMENT ON COLUMN activitytype.name IS \'(DC2Type:json_array)\''); + } + + public function down(Schema $schema) : void + { + $this->addSql('ALTER TABLE activitytype DROP personVisible'); + $this->addSql('ALTER TABLE activitytype DROP personLabel'); + $this->addSql('ALTER TABLE activitytype DROP userVisible'); + $this->addSql('ALTER TABLE activitytype DROP userLabel'); + $this->addSql('ALTER TABLE activitytype DROP dateVisible'); + $this->addSql('ALTER TABLE activitytype DROP dateLabel'); + $this->addSql('ALTER TABLE activitytype DROP placeVisible'); + $this->addSql('ALTER TABLE activitytype DROP placeLabel'); + $this->addSql('ALTER TABLE activitytype DROP personsVisible'); + $this->addSql('ALTER TABLE activitytype DROP personsLabel'); + $this->addSql('ALTER TABLE activitytype DROP thirdpartyVisible'); + $this->addSql('ALTER TABLE activitytype DROP thirdpartyLabel'); + $this->addSql('ALTER TABLE activitytype DROP durationTimeVisible'); + $this->addSql('ALTER TABLE activitytype DROP durationTimeLabel'); + $this->addSql('ALTER TABLE activitytype DROP attendeeVisible'); + $this->addSql('ALTER TABLE activitytype DROP attendeeLabel'); + $this->addSql('ALTER TABLE activitytype DROP reasonsVisible'); + $this->addSql('ALTER TABLE activitytype DROP reasonsLabel'); + $this->addSql('ALTER TABLE activitytype DROP commentVisible'); + $this->addSql('ALTER TABLE activitytype DROP commentLabel'); + $this->addSql('ALTER TABLE activitytype DROP sentReceivedVisible'); + $this->addSql('ALTER TABLE activitytype DROP sentReceivedLabel'); + $this->addSql('ALTER TABLE activitytype DROP documentVisible'); + $this->addSql('ALTER TABLE activitytype DROP documentLabel'); + $this->addSql('ALTER TABLE activitytype DROP emergencyVisible'); + $this->addSql('ALTER TABLE activitytype DROP emergencyLabel'); + $this->addSql('ALTER TABLE activitytype DROP accompanyingPeriodVisible'); + $this->addSql('ALTER TABLE activitytype DROP accompanyingPeriodLabel'); + $this->addSql('ALTER TABLE activitytype DROP socialDataVisible'); + $this->addSql('ALTER TABLE activitytype DROP socialDataLabel'); + $this->addSql('ALTER TABLE activitytype ALTER name DROP NOT NULL'); + $this->addSql('ALTER TABLE activitytype ALTER active SET DEFAULT \'true\''); + $this->addSql('COMMENT ON COLUMN activitytype.name IS NULL'); + } +} diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210415113216.php b/src/Bundle/ChillActivityBundle/migrations/Version20210415113216.php new file mode 100644 index 000000000..6cf9c2923 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210415113216.php @@ -0,0 +1,43 @@ +addSql('ALTER TABLE activitytype ADD thirdPartiesVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD thirdPartiesLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD documentsVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD documentsLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype DROP thirdpartyvisible'); + $this->addSql('ALTER TABLE activitytype DROP thirdpartylabel'); + $this->addSql('ALTER TABLE activitytype DROP documentvisible'); + $this->addSql('ALTER TABLE activitytype DROP documentlabel'); + } + + public function down(Schema $schema) : void + { + $this->addSql('ALTER TABLE activitytype ADD thirdpartyvisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD thirdpartylabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD documentvisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD documentlabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype DROP thirdPartiesVisible'); + $this->addSql('ALTER TABLE activitytype DROP thirdPartiesLabel'); + $this->addSql('ALTER TABLE activitytype DROP documentsVisible'); + $this->addSql('ALTER TABLE activitytype DROP documentsLabel'); + } +} diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210422073711.php b/src/Bundle/ChillActivityBundle/migrations/Version20210422073711.php new file mode 100644 index 000000000..8d5dcfa84 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210422073711.php @@ -0,0 +1,52 @@ +addSql('CREATE SEQUENCE activitytpresence_id_seq INCREMENT BY 1 MINVALUE 1 START 6'); + $this->addSql('CREATE TABLE activitytpresence (id INT NOT NULL, name JSON NOT NULL, active BOOLEAN NOT NULL, PRIMARY KEY(id))'); + + $list = [ + 'Usager pésent', "Absence de l''usager", + "Refus de visite ou d''entretien", 'Domicile non trouvé', + 'Domicile erronéee' + ]; + for ($i = 1; $i <= count($list); $i++) { + $this->addSql("INSERT INTO activitytpresence VALUES(".$i.", json_build_object('fr', '".$list[$i-1]."'), true)"); + } + + $this->addSql('ALTER TABLE activity ADD emergency BOOLEAN NOT NULL DEFAULT false'); + $this->addSql('ALTER TABLE activity ADD sentReceived VARCHAR(255) NOT NULL DEFAULT \'\' '); + $this->addSql('ALTER TABLE activity ALTER attendee TYPE INT USING CASE WHEN attendee is false THEN 2 WHEN attendee is true THEN 1 ELSE null END'); + $this->addSql('ALTER TABLE activity RENAME COLUMN attendee TO attendee_id'); + $this->addSql('ALTER TABLE activity ADD CONSTRAINT FK_AC74095ABCFD782A FOREIGN KEY (attendee_id) REFERENCES activitytpresence (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + + public function down(Schema $schema) : void + { + $this->addSql('ALTER TABLE activity DROP emergency'); + $this->addSql('ALTER TABLE activity DROP CONSTRAINT FK_AC74095ABCFD782A'); + $this->addSql('ALTER TABLE activity ADD attendee BOOLEAN DEFAULT NULL'); + $this->addSql('ALTER TABLE activity DROP attendee_id'); + $this->addSql('ALTER TABLE activity DROP sentReceived'); + + $this->addSql('DROP SEQUENCE activitytpresence_id_seq CASCADE'); + $this->addSql('DROP TABLE activitytpresence'); + } +} diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210422123846.php b/src/Bundle/ChillActivityBundle/migrations/Version20210422123846.php new file mode 100644 index 000000000..0fde71257 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210422123846.php @@ -0,0 +1,65 @@ +addSql('CREATE TABLE activity_person (activity_id INT NOT NULL, person_id INT NOT NULL, PRIMARY KEY(activity_id, person_id))'); + $this->addSql('CREATE INDEX IDX_66AA317681C06096 ON activity_person (activity_id)'); + $this->addSql('CREATE INDEX IDX_66AA3176217BBB47 ON activity_person (person_id)'); + $this->addSql('CREATE TABLE activity_thirdparty (activity_id INT NOT NULL, thirdparty_id INT NOT NULL, PRIMARY KEY(activity_id, thirdparty_id))'); + $this->addSql('CREATE INDEX IDX_C6F0DE0381C06096 ON activity_thirdparty (activity_id)'); + $this->addSql('CREATE INDEX IDX_C6F0DE03C7D3A8E6 ON activity_thirdparty (thirdparty_id)'); + $this->addSql('CREATE TABLE activity_document (activity_id INT NOT NULL, document_id INT NOT NULL, PRIMARY KEY(activity_id, document_id))'); + $this->addSql('CREATE INDEX IDX_78633A7881C06096 ON activity_document (activity_id)'); + $this->addSql('CREATE INDEX IDX_78633A78C33F7837 ON activity_document (document_id)'); + $this->addSql('CREATE TABLE activity_user (activity_id INT NOT NULL, user_id INT NOT NULL, PRIMARY KEY(activity_id, user_id))'); + $this->addSql('CREATE INDEX IDX_8E570DDB81C06096 ON activity_user (activity_id)'); + $this->addSql('CREATE INDEX IDX_8E570DDBA76ED395 ON activity_user (user_id)'); + $this->addSql('ALTER TABLE activity_person ADD CONSTRAINT FK_66AA317681C06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE activity_person ADD CONSTRAINT FK_66AA3176217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE activity_thirdparty ADD CONSTRAINT FK_C6F0DE0381C06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE activity_thirdparty ADD CONSTRAINT FK_C6F0DE03C7D3A8E6 FOREIGN KEY (thirdparty_id) REFERENCES chill_3party.third_party (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE activity_document ADD CONSTRAINT FK_78633A7881C06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + #$this->addSql('ALTER TABLE activity_document ADD CONSTRAINT FK_78633A78C33F7837 FOREIGN KEY (document_id) REFERENCES Document (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE activity_user ADD CONSTRAINT FK_8E570DDB81C06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE activity_user ADD CONSTRAINT FK_8E570DDBA76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + + $this->addSql('ALTER TABLE activity ADD travelTime TIME(0) WITHOUT TIME ZONE DEFAULT NULL'); + + $this->addSql('ALTER TABLE activitytype ADD travelTimeVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD travelTimeLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD usersVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD usersLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + } + + public function down(Schema $schema) : void + { + $this->addSql('DROP TABLE activity_person'); + $this->addSql('DROP TABLE activity_thirdparty'); + $this->addSql('DROP TABLE activity_document'); + $this->addSql('DROP TABLE activity_user'); + + $this->addSql('ALTER TABLE activity DROP travelTime'); + + $this->addSql('ALTER TABLE activitytype DROP travelTimeVisible'); + $this->addSql('ALTER TABLE activitytype DROP travelTimeLabel'); + $this->addSql('ALTER TABLE activitytype DROP usersVisible'); + $this->addSql('ALTER TABLE activitytype DROP usersLabel'); + } +} diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210506071150.php b/src/Bundle/ChillActivityBundle/migrations/Version20210506071150.php new file mode 100644 index 000000000..3a1a4e513 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210506071150.php @@ -0,0 +1,30 @@ +addSql('ALTER TABLE activity ALTER durationtime DROP NOT NULL'); + } + + public function down(Schema $schema) : void + { + $this->addSql('ALTER TABLE activity ALTER durationTime SET NOT NULL'); + } +} diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210506090417.php b/src/Bundle/ChillActivityBundle/migrations/Version20210506090417.php new file mode 100644 index 000000000..b1e4e43fc --- /dev/null +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210506090417.php @@ -0,0 +1,26 @@ +addSql('ALTER TABLE activitytype ADD ordering DOUBLE PRECISION DEFAULT \'0.0\' NOT NULL'); + $this->addSql('ALTER TABLE activitytypecategory ADD ordering DOUBLE PRECISION DEFAULT \'0.0\' NOT NULL'); + } + + public function down(Schema $schema) : void + { + $this->addSql('ALTER TABLE activitytypecategory DROP ordering'); + $this->addSql('ALTER TABLE activitytype DROP ordering'); + } +} diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210506094520.php b/src/Bundle/ChillActivityBundle/migrations/Version20210506094520.php new file mode 100644 index 000000000..a31d23ae4 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210506094520.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE activitytype ADD category_id INT DEFAULT 1'); + $this->addSql('ALTER TABLE activitytype ADD CONSTRAINT FK_B38CD05112469DE2 FOREIGN KEY (category_id) REFERENCES activitytypecategory (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + + public function down(Schema $schema) : void + { + $this->addSql('ALTER TABLE activitytype DROP CONSTRAINT FK_B38CD05112469DE2');; + $this->addSql('ALTER TABLE activitytype DROP category_id'); + } +} diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210506112500.php b/src/Bundle/ChillActivityBundle/migrations/Version20210506112500.php new file mode 100644 index 000000000..ca80d7720 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210506112500.php @@ -0,0 +1,42 @@ +addSql('CREATE TABLE activity_storedobject (activity_id INT NOT NULL, storedobject_id INT NOT NULL, PRIMARY KEY(activity_id, storedobject_id))'); + $this->addSql('CREATE INDEX IDX_6F660E9381C06096 ON activity_storedobject (activity_id)'); + $this->addSql('CREATE INDEX IDX_6F660E93EE684399 ON activity_storedobject (storedobject_id)'); + $this->addSql('ALTER TABLE activity_storedobject ADD CONSTRAINT FK_6F660E9381C06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE activity_storedobject ADD CONSTRAINT FK_6F660E93EE684399 FOREIGN KEY (storedobject_id) REFERENCES chill_doc.stored_object (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('DROP TABLE activity_document'); + + } + + public function down(Schema $schema) : void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA public'); + $this->addSql('CREATE TABLE activity_document (activity_id INT NOT NULL, document_id INT NOT NULL, PRIMARY KEY(activity_id, document_id))'); + $this->addSql('CREATE INDEX idx_78633a78c33f7837 ON activity_document (document_id)'); + $this->addSql('CREATE INDEX idx_78633a7881c06096 ON activity_document (activity_id)'); + $this->addSql('ALTER TABLE activity_document ADD CONSTRAINT fk_78633a7881c06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('DROP TABLE activity_storedobject'); + } +} diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210520095626.php b/src/Bundle/ChillActivityBundle/migrations/Version20210520095626.php new file mode 100644 index 000000000..f5a0abda6 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210520095626.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE activity ADD accompanyingPeriod_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE activity ADD CONSTRAINT FK_AC74095AD7FA8EF0 FOREIGN KEY (accompanyingPeriod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE activity DROP CONSTRAINT FK_AC74095AD7FA8EF0'); + $this->addSql('ALTER TABLE activity DROP accompanyingPeriod_id'); + } +} diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210528161250.php b/src/Bundle/ChillActivityBundle/migrations/Version20210528161250.php new file mode 100644 index 000000000..8eaf7e1a4 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210528161250.php @@ -0,0 +1,39 @@ +addSql('CREATE TABLE chill_activity_activity_chill_person_socialissue (activity_id INT NOT NULL, socialissue_id INT NOT NULL, PRIMARY KEY(activity_id, socialissue_id))'); + $this->addSql('CREATE INDEX IDX_3DA33F2681C06096 ON chill_activity_activity_chill_person_socialissue (activity_id)'); + $this->addSql('CREATE INDEX IDX_3DA33F26A549916C ON chill_activity_activity_chill_person_socialissue (socialissue_id)'); + $this->addSql('CREATE TABLE chill_activity_activity_chill_person_socialaction (activity_id INT NOT NULL, socialaction_id INT NOT NULL, PRIMARY KEY(activity_id, socialaction_id))'); + $this->addSql('CREATE INDEX IDX_548F1AD881C06096 ON chill_activity_activity_chill_person_socialaction (activity_id)'); + $this->addSql('CREATE INDEX IDX_548F1AD83DC32179 ON chill_activity_activity_chill_person_socialaction (socialaction_id)'); + $this->addSql('ALTER TABLE chill_activity_activity_chill_person_socialissue ADD CONSTRAINT FK_3DA33F2681C06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_activity_activity_chill_person_socialissue ADD CONSTRAINT FK_3DA33F26A549916C FOREIGN KEY (socialissue_id) REFERENCES chill_person_social_issue (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_activity_activity_chill_person_socialaction ADD CONSTRAINT FK_548F1AD881C06096 FOREIGN KEY (activity_id) REFERENCES activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_activity_activity_chill_person_socialaction ADD CONSTRAINT FK_548F1AD83DC32179 FOREIGN KEY (socialaction_id) REFERENCES chill_person_social_action (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + + public function down(Schema $schema): void + { + $this->addSql('DROP TABLE chill_activity_activity_chill_person_socialissue'); + $this->addSql('DROP TABLE chill_activity_activity_chill_person_socialaction'); + } +} diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210602103243.php b/src/Bundle/ChillActivityBundle/migrations/Version20210602103243.php new file mode 100644 index 000000000..4c773c161 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210602103243.php @@ -0,0 +1,35 @@ +addSql('ALTER TABLE activitytype ADD socialIssuesVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD socialIssuesLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD socialActionsVisible SMALLINT DEFAULT 1 NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD socialActionsLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE activitytype DROP socialIssuesVisible'); + $this->addSql('ALTER TABLE activitytype DROP socialIssuesLabel'); + $this->addSql('ALTER TABLE activitytype DROP socialActionsVisible'); + $this->addSql('ALTER TABLE activitytype DROP socialActionsLabel'); + } +} diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 92ac3f7b4..dc2894499 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -5,6 +5,7 @@ Activity: Activité Duration time: Durée Duration Time: Durée durationTime: durée +Travel time: Durée de déplacement Reasons: Sujets Attendee: Présence de la personne attendee: présence de la personne @@ -19,16 +20,30 @@ present: présent not present: absent Delete: Supprimer Update: Mettre à jour -Update activity: Édition de l'activité +Update activity: Modifier l'activité Scope: Cercle Activity data: Données de l'activité No reason associated: Aucun sujet +No social issues associated: Aucune problématique sociale +No social actions associated: Aucune action d'accompagnement There isn't any activities.: Aucune activité enregistrée. type_name: type de l'activité person_firstname: prénom person_lastname: nom de famille person_id: identifiant de la personne Type: Type +Invisible: Invisible +Optional: Optionnel +Required: Obligatoire +Persons: Personnes +Users: Utilisateurs +Emergency: Urgent +Sent received: Envoyer / Recevoir +Sent: Envoyer +Received: Recevoir +by: 'Par ' +location: Lieu + #forms Activity creation: Nouvelle activité @@ -50,6 +65,15 @@ Choose a type: Choisir un type 1 hour 30: 1 heure 30 1 hour 45: 1 heure 45 2 hours: 2 heures +Concerned groups: Parties concernées +Persons in accompanying course: Usagers du parcours +Third persons: Tiers non-pro. +Others persons: Usagers +Third parties: Tiers professionnels +Users concerned: T(M)S +activity: + Insert a document: Insérer un document + Remove a document: Supprimer le document #timeline @@ -77,6 +101,16 @@ Activity configuration menu: Configuration des activités Activity Types: Types d'activité Activity Reasons: Sujets d'une activité Activity Reasons Category: Catégories de sujet d'activités +Activity Types Categories: Catégories des types d'activité + +# Crud +crud: + activity_type: + title_new: Nouveau type d'activité + title_edit: Edition d'un type d'activité + activity_type_category: + title_new: Nouvelle catégorie de type d'activité + title_edit: Edition d'une catégorie de type d'activité # activity reason admin ActivityReason list: Liste des sujets @@ -98,12 +132,41 @@ ActivityReasonCategory: Catégorie de sujet d'activité ActivityReasonCategory is active and will be proposed: La catégorie est active et sera proposée ActivityReasonCategory is inactive and won't be proposed: La catégorie est inactive et ne sera pas proposée -# activity type admin +# activity type type admin ActivityType list: Types d'activités Create a new activity type: Créer un nouveau type d'activité -ActivityType creation: Nouveau type d'activité -ActivityType: Type d'activité -ActivityType edit: Modifier une activité +Persons visible: Visibilté du champ Personnes +Persons label: Libellé du champ Personnes +User visible: Visibilté du champ Utilisateur +User label: Libellé du champ Utilisateur +Date visible: Visibilté du champ Date +Date label: Libellé du champ Date +Place visible: Visibilté du champ Lieu +Place label: Libellé du champ Lieu +Third parties visible: Visibilté du champ Tiers +Third parties label: Libellé du champ Tiers +Duration time visible: Visibilté du champ Durée +Duration time label: Libellé du champ Durée +Travel time visible: Visibilté du champ Durée de déplacement +Travel time label: Libellé du champ Durée de déplacement +Attendee visible: Visibilté du champ Présence de l'usager +Attendee label: Libellé du champ Présence de l'usager +Reasons visible: Visibilté du champ Sujet +Reasons label: Libellé du champ Sujet +Comment visible: Visibilté du champ Commentaire +Comment label: Libellé du champ Commentaire +Emergency visible: Visibilté du champ Urgent +Emergency label: Libellé du champ Urgent +Accompanying period visible: Visibilté du champ Période d'accompagnement +Accompanying period label: Libellé du champ Période d'accompagnement +Social data visible: Visibilté du champ Données sociales +Social data label: Libellé du champ Données sociales +Users visible: Visibilté du champ Utilisateurs +Users label: Libellé du champ Utilisateurs + +# activity type category admin +ActivityTypeCategory list: Liste des catégories des types d'activité +Create a new activity type category: Créer une nouvelle catégorie de type d'activité # activity delete Remove activity: Supprimer une activité diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index d5c24b110..23a6e4de9 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -115,7 +115,6 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, $loader->load('services.yaml'); $loader->load('services/doctrine.yaml'); $loader->load('services/logger.yaml'); - $loader->load('services/repositories.yaml'); $loader->load('services/pagination.yaml'); $loader->load('services/export.yaml'); $loader->load('services/form.yaml'); diff --git a/src/Bundle/ChillMainBundle/Entity/Address.php b/src/Bundle/ChillMainBundle/Entity/Address.php index 2fc024e8c..3bbbfa368 100644 --- a/src/Bundle/ChillMainBundle/Entity/Address.php +++ b/src/Bundle/ChillMainBundle/Entity/Address.php @@ -11,7 +11,7 @@ use Chill\ThirdPartyBundle\Entity\ThirdParty; /** * Address * - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="chill_main_address") * @ORM\HasLifecycleCallbacks() */ diff --git a/src/Bundle/ChillMainBundle/Entity/AddressReference.php b/src/Bundle/ChillMainBundle/Entity/AddressReference.php index d13de4de9..2a50932f4 100644 --- a/src/Bundle/ChillMainBundle/Entity/AddressReference.php +++ b/src/Bundle/ChillMainBundle/Entity/AddressReference.php @@ -7,7 +7,7 @@ use Chill\MainBundle\Doctrine\Model\Point; use Symfony\Component\Serializer\Annotation\Groups; /** - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="chill_main_address_reference") * @ORM\HasLifecycleCallbacks() */ diff --git a/src/Bundle/ChillMainBundle/Entity/Center.php b/src/Bundle/ChillMainBundle/Entity/Center.php index b3792dab9..2d87a20ab 100644 --- a/src/Bundle/ChillMainBundle/Entity/Center.php +++ b/src/Bundle/ChillMainBundle/Entity/Center.php @@ -25,7 +25,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; /** - * @ORM\Entity(repositoryClass="Chill\MainBundle\Repository\CenterRepository") + * @ORM\Entity * @ORM\Table(name="centers") * * @author Julien Fastré diff --git a/src/Bundle/ChillMainBundle/Entity/Country.php b/src/Bundle/ChillMainBundle/Entity/Country.php index 932944d03..043a4e82e 100644 --- a/src/Bundle/ChillMainBundle/Entity/Country.php +++ b/src/Bundle/ChillMainBundle/Entity/Country.php @@ -8,7 +8,7 @@ use Symfony\Component\Serializer\Annotation\Groups; /** * Country * - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="country") * @ORM\Cache(usage="READ_ONLY", region="country_cache_region") * @ORM\HasLifecycleCallbacks() diff --git a/src/Bundle/ChillMainBundle/Entity/Embeddable/CommentEmbeddable.php b/src/Bundle/ChillMainBundle/Entity/Embeddable/CommentEmbeddable.php index 730d530d5..9c99c98b4 100644 --- a/src/Bundle/ChillMainBundle/Entity/Embeddable/CommentEmbeddable.php +++ b/src/Bundle/ChillMainBundle/Entity/Embeddable/CommentEmbeddable.php @@ -37,6 +37,11 @@ class CommentEmbeddable return $this->comment; } + public function isEmpty() + { + return empty($this->getComment()); + } + /** * @param string $comment */ diff --git a/src/Bundle/ChillMainBundle/Entity/GroupCenter.php b/src/Bundle/ChillMainBundle/Entity/GroupCenter.php index fee1081ff..a7700001f 100644 --- a/src/Bundle/ChillMainBundle/Entity/GroupCenter.php +++ b/src/Bundle/ChillMainBundle/Entity/GroupCenter.php @@ -27,7 +27,7 @@ use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; /** - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="group_centers") * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region") * diff --git a/src/Bundle/ChillMainBundle/Entity/Language.php b/src/Bundle/ChillMainBundle/Entity/Language.php index 2f59eda6d..22895b61b 100644 --- a/src/Bundle/ChillMainBundle/Entity/Language.php +++ b/src/Bundle/ChillMainBundle/Entity/Language.php @@ -25,7 +25,7 @@ use Doctrine\ORM\Mapping as ORM; /** * Language * - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="language") * @ORM\Cache(usage="READ_ONLY", region="language_cache_region") * @ORM\HasLifecycleCallbacks() diff --git a/src/Bundle/ChillMainBundle/Entity/PermissionsGroup.php b/src/Bundle/ChillMainBundle/Entity/PermissionsGroup.php index 8be256595..456ee29e3 100644 --- a/src/Bundle/ChillMainBundle/Entity/PermissionsGroup.php +++ b/src/Bundle/ChillMainBundle/Entity/PermissionsGroup.php @@ -27,7 +27,7 @@ use Chill\MainBundle\Entity\RoleScope; use Symfony\Component\Validator\Context\ExecutionContextInterface; /** - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="permission_groups") * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region") * diff --git a/src/Bundle/ChillMainBundle/Entity/PostalCode.php b/src/Bundle/ChillMainBundle/Entity/PostalCode.php index 26d75a532..61527e422 100644 --- a/src/Bundle/ChillMainBundle/Entity/PostalCode.php +++ b/src/Bundle/ChillMainBundle/Entity/PostalCode.php @@ -8,7 +8,7 @@ use Symfony\Component\Serializer\Annotation\Groups; /** * PostalCode * - * @ORM\Entity(repositoryClass="Chill\MainBundle\Repository\PostalCodeRepository") + * @ORM\Entity * @ORM\Table( * name="chill_main_postal_code", * indexes={@ORM\Index( diff --git a/src/Bundle/ChillMainBundle/Entity/RoleScope.php b/src/Bundle/ChillMainBundle/Entity/RoleScope.php index 9944a96cc..7842267a9 100644 --- a/src/Bundle/ChillMainBundle/Entity/RoleScope.php +++ b/src/Bundle/ChillMainBundle/Entity/RoleScope.php @@ -25,7 +25,7 @@ use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; /** - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="role_scopes") * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region") * diff --git a/src/Bundle/ChillMainBundle/Entity/Scope.php b/src/Bundle/ChillMainBundle/Entity/Scope.php index aba06ab7e..ba11a1842 100644 --- a/src/Bundle/ChillMainBundle/Entity/Scope.php +++ b/src/Bundle/ChillMainBundle/Entity/Scope.php @@ -28,7 +28,7 @@ use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\DiscriminatorMap; /** - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="scopes") * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region") * @DiscriminatorMap(typeProperty="type", mapping={ diff --git a/src/Bundle/ChillMainBundle/Entity/User.php b/src/Bundle/ChillMainBundle/Entity/User.php index 11d168f84..76bb7b54d 100644 --- a/src/Bundle/ChillMainBundle/Entity/User.php +++ b/src/Bundle/ChillMainBundle/Entity/User.php @@ -12,7 +12,7 @@ use Symfony\Component\Serializer\Annotation\DiscriminatorMap; /** * User * - * @ORM\Entity(repositoryClass="Chill\MainBundle\Repository\UserRepository") + * @ORM\Entity * @ORM\Table(name="users") * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region") * @DiscriminatorMap(typeProperty="type", mapping={ diff --git a/src/Bundle/ChillMainBundle/Form/Type/AddressType.php b/src/Bundle/ChillMainBundle/Form/Type/AddressType.php index 68cfdda09..f17721881 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/AddressType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/AddressType.php @@ -23,9 +23,9 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\Extension\Core\Type\TextType; -use Symfony\Component\Form\Extension\Core\Type\DateType; use Chill\MainBundle\Entity\Address; use Chill\MainBundle\Form\Type\PostalCodeType; +use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\DataMapper\AddressDataMapper; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; @@ -60,10 +60,8 @@ class AddressType extends AbstractType if ($options['has_valid_from']) { $builder - ->add('validFrom', DateType::class, array( + ->add('validFrom', ChillDateType::class, array( 'required' => true, - 'widget' => 'single_text', - 'format' => 'dd-MM-yyyy' ) ); } diff --git a/src/Bundle/ChillMainBundle/Form/Type/ChillDateType.php b/src/Bundle/ChillMainBundle/Form/Type/ChillDateType.php index 2f5a6945c..8502febbb 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ChillDateType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ChillDateType.php @@ -35,8 +35,7 @@ class ChillDateType extends AbstractType { $resolver ->setDefault('widget', 'single_text') - ->setDefault('attr', [ 'class' => 'datepicker' ]) - ->setDefault('format', 'dd-MM-yyyy') + ->setDefault('html5', true) ; } diff --git a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/CenterTransformer.php b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/CenterTransformer.php index 4b1b9a2d9..b90ab5a46 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/CenterTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/CenterTransformer.php @@ -19,26 +19,18 @@ namespace Chill\MainBundle\Form\Type\DataTransformer; +use Chill\MainBundle\Entity\Center; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Form\DataTransformerInterface; -use Doctrine\Persistence\ObjectManager; use Symfony\Component\Form\Exception\TransformationFailedException; -/** - * Transform a center object to his id, and vice-versa - * - * @author Julien Fastré - */ class CenterTransformer implements DataTransformerInterface { - /** - * - * @var ObjectManager - */ - private $om; - - public function __construct(ObjectManager $om) + private EntityManagerInterface $em; + + public function __construct(EntityManagerInterface $em) { - $this->om = $om; + $this->em = $em; } public function reverseTransform($id) @@ -46,15 +38,17 @@ class CenterTransformer implements DataTransformerInterface if ($id === NULL) { return NULL; } - - $center = $this->om->getRepository('ChillMainBundle:Center') - ->find($id); - + + $center = $this + ->em + ->getRepository(Center::class) + ->find($id); + if ($center === NULL) { throw new TransformationFailedException(sprintf( 'No center found with id %d', $id)); } - + return $center; } @@ -63,7 +57,7 @@ class CenterTransformer implements DataTransformerInterface if ($center === NULL) { return ''; } - + return $center->getId(); } diff --git a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/MultipleObjectsToIdTransformer.php b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/MultipleObjectsToIdTransformer.php index 4686a5e17..00ee26fff 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/MultipleObjectsToIdTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/MultipleObjectsToIdTransformer.php @@ -24,28 +24,20 @@ use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; use Doctrine\Persistence\ObjectManager; use Doctrine\Common\Collections\ArrayCollection; - +use Doctrine\ORM\EntityManagerInterface; + class MultipleObjectsToIdTransformer implements DataTransformerInterface { - /** - * @var ObjectManager - */ - private $em; - - /** - * @var string - */ - private $class; - - /** - * @param ObjectManager $em - */ - public function __construct(ObjectManager $em, $class) + private EntityManagerInterface $em; + + private ?string $class; + + public function __construct(EntityManagerInterface $em, ?string $class = null) { $this->em = $em; $this->class = $class; } - + /** * Transforms an object (use) to a string (id). * diff --git a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ObjectToIdTransformer.php b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ObjectToIdTransformer.php index d041dce7c..82cdf6c21 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ObjectToIdTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ObjectToIdTransformer.php @@ -20,28 +20,20 @@ namespace Chill\MainBundle\Form\Type\DataTransformer; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; use Doctrine\Persistence\ObjectManager; class ObjectToIdTransformer implements DataTransformerInterface { - /** - * @var ObjectManager - */ - private $om; + private EntityManagerInterface $em; - /** - * @var string - */ - private $class; + private ?string $class; - /** - * @param ObjectManager $om - */ - public function __construct(ObjectManager $om, $class) + public function __construct(EntityManagerInterface $em, ?string $class = null) { - $this->om = $om; + $this->em = $em; $this->class = $class; } @@ -73,7 +65,7 @@ class ObjectToIdTransformer implements DataTransformerInterface return null; } - $object = $this->om + $object = $this->em ->getRepository($this->class) ->find($id) ; diff --git a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ScopeTransformer.php b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ScopeTransformer.php index 09ef90063..bd1185333 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ScopeTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ScopeTransformer.php @@ -19,41 +19,28 @@ namespace Chill\MainBundle\Form\Type\DataTransformer; +use Chill\MainBundle\Entity\Scope; use Symfony\Component\Form\DataTransformerInterface; use Doctrine\Persistence\ObjectManager; use Symfony\Component\Form\Exception\TransformationFailedException; use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\ORM\EntityManagerInterface; -/** - * - * - * @author Julien Fastré - */ class ScopeTransformer implements DataTransformerInterface { - /** - * - * @var ObjectManager - */ - protected $om; - - /** - * - * @var TranslatableStringHelper - */ - protected $helper; - - public function __construct(ObjectManager $om) + private EntityManagerInterface $em; + + public function __construct(EntityManagerInterface $em) { - $this->om = $om; + $this->em = $em; } - + public function transform($scope) { if ($scope === NULL) { return NULL; } - + return $scope->getId(); } @@ -62,15 +49,17 @@ class ScopeTransformer implements DataTransformerInterface if ($id == NULL) { return NULL; } - - $scope = $this->om->getRepository('ChillMainBundle:Scope') - ->find($id); - + + $scope = $this + ->em + ->getRepository(Scope::class) + ->find($id); + if ($scope === NULL) { throw new TransformationFailedException(sprintf("The scope with id " . "'%d' were not found", $id)); } - + return $scope; } diff --git a/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php b/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php index 379bb2183..832db628f 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php @@ -22,6 +22,7 @@ use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Form\DataMapper\ScopePickerDataMapper; +use Chill\MainBundle\Repository\ScopeRepository; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Templating\TranslatableStringHelper; use Doctrine\ORM\EntityRepository; @@ -60,7 +61,7 @@ class ScopePickerType extends AbstractType protected $tokenStorage; /** - * @var EntityRepository + * @var ScopeRepository */ protected $scopeRepository; @@ -72,7 +73,7 @@ class ScopePickerType extends AbstractType public function __construct( AuthorizationHelper $authorizationHelper, TokenStorageInterface $tokenStorage, - EntityRepository $scopeRepository, + ScopeRepository $scopeRepository, TranslatableStringHelper $translatableStringHelper ) { $this->authorizationHelper = $authorizationHelper; diff --git a/src/Bundle/ChillMainBundle/Form/Type/UserPickerType.php b/src/Bundle/ChillMainBundle/Form/Type/UserPickerType.php index a179f4740..fece2d6d4 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/UserPickerType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/UserPickerType.php @@ -25,6 +25,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Repository\UserRepository; use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; use Symfony\Component\Security\Core\Role\Role; @@ -53,16 +54,12 @@ class UserPickerType extends AbstractType */ protected $tokenStorage; - /** - * - * @var \Chill\MainBundle\Repository\UserRepository - */ - protected $userRepository; + protected UserRepository $userRepository; public function __construct( AuthorizationHelper $authorizationHelper, TokenStorageInterface $tokenStorage, - EntityRepository $userRepository + UserRepository $userRepository ) { $this->authorizationHelper = $authorizationHelper; $this->tokenStorage = $tokenStorage; diff --git a/src/Bundle/ChillMainBundle/Repository/AddressReferenceRepository.php b/src/Bundle/ChillMainBundle/Repository/AddressReferenceRepository.php index 208151420..f040446b3 100644 --- a/src/Bundle/ChillMainBundle/Repository/AddressReferenceRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/AddressReferenceRepository.php @@ -1,50 +1,50 @@ repository = $entityManager->getRepository(AddressReference::class); } - // /** - // * @return AddressReference[] Returns an array of AddressReference objects - // */ - /* - public function findByExampleField($value) + public function find($id, $lockMode = null, $lockVersion = null): ?AddressReference { - return $this->createQueryBuilder('a') - ->andWhere('a.exampleField = :val') - ->setParameter('val', $value) - ->orderBy('a.id', 'ASC') - ->setMaxResults(10) - ->getQuery() - ->getResult() - ; + return $this->repository->find($id, $lockMode, $lockVersion); } - */ - /* - public function findOneBySomeField($value): ?AddressReference + public function findOneBy(array $criteria, array $orderBy = null): ?AddressReference { - return $this->createQueryBuilder('a') - ->andWhere('a.exampleField = :val') - ->setParameter('val', $value) - ->getQuery() - ->getOneOrNullResult() - ; + return $this->repository->findOneBy($criteria, $orderBy); + } + + /** + * @return AddressReference[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @return AddressReference[] + */ + public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function getClassName() { + return AddressReference::class; } - */ } diff --git a/src/Bundle/ChillMainBundle/Repository/AddressRepository.php b/src/Bundle/ChillMainBundle/Repository/AddressRepository.php new file mode 100644 index 000000000..76f6c93bb --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/AddressRepository.php @@ -0,0 +1,50 @@ +repository = $entityManager->getRepository(Address::class); + } + + public function find($id, $lockMode = null, $lockVersion = null): ?Address + { + return $this->repository->find($id, $lockMode, $lockVersion); + } + + public function findOneBy(array $criteria, array $orderBy = null): ?Address + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + /** + * @return Address[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @return Address[] + */ + public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function getClassName() { + return Address::class; + } +} diff --git a/src/Bundle/ChillMainBundle/Repository/CenterRepository.php b/src/Bundle/ChillMainBundle/Repository/CenterRepository.php index 05a439bfd..3cf8cf38b 100644 --- a/src/Bundle/ChillMainBundle/Repository/CenterRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/CenterRepository.php @@ -1,27 +1,50 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ + +declare(strict_types=1); + namespace Chill\MainBundle\Repository; -/** - * - * - */ -class CenterRepository extends \Doctrine\ORM\EntityRepository +use Chill\MainBundle\Entity\Center; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\EntityRepository; +use Doctrine\Persistence\ObjectRepository; + +final class CenterRepository implements ObjectRepository { - + private EntityRepository $repository; + + public function __construct(EntityManagerInterface $entityManager) + { + $this->repository = $entityManager->getRepository(Center::class); + } + + public function find($id, $lockMode = null, $lockVersion = null): ?Center + { + return $this->repository->find($id, $lockMode, $lockVersion); + } + + public function findOneBy(array $criteria, array $orderBy = null): ?Center + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + /** + * @return Center[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @return Center[] + */ + public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function getClassName() { + return Center::class; + } } diff --git a/src/Bundle/ChillMainBundle/Repository/CountryRepository.php b/src/Bundle/ChillMainBundle/Repository/CountryRepository.php new file mode 100644 index 000000000..336768948 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/CountryRepository.php @@ -0,0 +1,50 @@ +repository = $entityManager->getRepository(Country::class); + } + + public function find($id, $lockMode = null, $lockVersion = null): ?Country + { + return $this->repository->find($id, $lockMode, $lockVersion); + } + + public function findOneBy(array $criteria, array $orderBy = null): ?Country + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + /** + * @return Country[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @return Country[] + */ + public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function getClassName() { + return Country::class; + } +} diff --git a/src/Bundle/ChillMainBundle/Repository/GroupCenterRepository.php b/src/Bundle/ChillMainBundle/Repository/GroupCenterRepository.php new file mode 100644 index 000000000..6faed8e47 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/GroupCenterRepository.php @@ -0,0 +1,50 @@ +repository = $entityManager->getRepository(GroupCenter::class); + } + + public function find($id, $lockMode = null, $lockVersion = null): ?GroupCenter + { + return $this->repository->find($id, $lockMode, $lockVersion); + } + + public function findOneBy(array $criteria, array $orderBy = null): ?GroupCenter + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + /** + * @return GroupCenter[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @return GroupCenter[] + */ + public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function getClassName() { + return GroupCenter::class; + } +} diff --git a/src/Bundle/ChillMainBundle/Repository/LanguageRepository.php b/src/Bundle/ChillMainBundle/Repository/LanguageRepository.php new file mode 100644 index 000000000..f6a7ec284 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/LanguageRepository.php @@ -0,0 +1,50 @@ +repository = $entityManager->getRepository(Language::class); + } + + public function find($id, $lockMode = null, $lockVersion = null): ?Language + { + return $this->repository->find($id, $lockMode, $lockVersion); + } + + public function findOneBy(array $criteria, array $orderBy = null): ?Language + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + /** + * @return Language[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @return Language[] + */ + public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function getClassName() { + return Language::class; + } +} diff --git a/src/Bundle/ChillMainBundle/Repository/PermissionsGroupRepository.php b/src/Bundle/ChillMainBundle/Repository/PermissionsGroupRepository.php new file mode 100644 index 000000000..0bb4c7bfd --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/PermissionsGroupRepository.php @@ -0,0 +1,50 @@ +repository = $entityManager->getRepository(PermissionsGroup::class); + } + + public function find($id, $lockMode = null, $lockVersion = null): ?PermissionsGroup + { + return $this->repository->find($id, $lockMode, $lockVersion); + } + + public function findOneBy(array $criteria, array $orderBy = null): ?PermissionsGroup + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + /** + * @return PermissionsGroup[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @return PermissionsGroup[] + */ + public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function getClassName() { + return PermissionsGroup::class; + } +} diff --git a/src/Bundle/ChillMainBundle/Repository/PostalCodeRepository.php b/src/Bundle/ChillMainBundle/Repository/PostalCodeRepository.php index 5b8ab8423..0087c9aa9 100644 --- a/src/Bundle/ChillMainBundle/Repository/PostalCodeRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/PostalCodeRepository.php @@ -1,28 +1,50 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ + +declare(strict_types=1); + namespace Chill\MainBundle\Repository; -/** - * - * - * @author Julien Fastré - */ -class PostalCodeRepository extends \Doctrine\ORM\EntityRepository +use Chill\MainBundle\Entity\PostalCode; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\EntityRepository; +use Doctrine\Persistence\ObjectRepository; + +final class PostalCodeRepository implements ObjectRepository { - + private EntityRepository $repository; + + public function __construct(EntityManagerInterface $entityManager) + { + $this->repository = $entityManager->getRepository(PostalCode::class); + } + + public function find($id, $lockMode = null, $lockVersion = null): ?PostalCode + { + return $this->repository->find($id, $lockMode, $lockVersion); + } + + public function findOneBy(array $criteria, array $orderBy = null): ?PostalCode + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + /** + * @return PostalCode[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @return PostalCode[] + */ + public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function getClassName() { + return PostalCode::class; + } } diff --git a/src/Bundle/ChillMainBundle/Repository/RoleScopeRepository.php b/src/Bundle/ChillMainBundle/Repository/RoleScopeRepository.php new file mode 100644 index 000000000..6996f384c --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/RoleScopeRepository.php @@ -0,0 +1,50 @@ +repository = $entityManager->getRepository(RoleScope::class); + } + + public function find($id, $lockMode = null, $lockVersion = null): ?RoleScope + { + return $this->repository->find($id, $lockMode, $lockVersion); + } + + public function findOneBy(array $criteria, array $orderBy = null): ?RoleScope + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + /** + * @return RoleScope[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @return RoleScope[] + */ + public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function getClassName() { + return RoleScope::class; + } +} diff --git a/src/Bundle/ChillMainBundle/Repository/ScopeRepository.php b/src/Bundle/ChillMainBundle/Repository/ScopeRepository.php new file mode 100644 index 000000000..a2d4058da --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/ScopeRepository.php @@ -0,0 +1,50 @@ +repository = $entityManager->getRepository(Scope::class); + } + + public function find($id, $lockMode = null, $lockVersion = null): ?Scope + { + return $this->repository->find($id, $lockMode, $lockVersion); + } + + public function findOneBy(array $criteria, array $orderBy = null): ?Scope + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + /** + * @return Scope[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @return Scope[] + */ + public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function getClassName() { + return Scope::class; + } +} diff --git a/src/Bundle/ChillMainBundle/Repository/UserRepository.php b/src/Bundle/ChillMainBundle/Repository/UserRepository.php index 51bcda6eb..e5427325a 100644 --- a/src/Bundle/ChillMainBundle/Repository/UserRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/UserRepository.php @@ -1,121 +1,148 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ + +declare(strict_types=1); + namespace Chill\MainBundle\Repository; -use Chill\MainBundle\Entity\GroupCenter; use Chill\MainBundle\Entity\User; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\QueryBuilder; +use Doctrine\Persistence\ObjectRepository; -/** - * - * - */ -class UserRepository extends \Doctrine\ORM\EntityRepository +final class UserRepository implements ObjectRepository { - public function countByUsernameOrEmail($pattern) + private EntityRepository $repository; + + private EntityManagerInterface $entityManager; + + public function __construct(EntityManagerInterface $entityManager) + { + $this->entityManager = $entityManager; + $this->repository = $entityManager->getRepository(User::class); + } + + public function find($id, $lockMode = null, $lockVersion = null): ?User + { + return $this->repository->find($id, $lockMode, $lockVersion); + } + + public function findOneBy(array $criteria, array $orderBy = null): ?User + { + return $this->repository->findOneBy($criteria, $orderBy); + } + + /** + * @return User[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @return User[] + */ + public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function getClassName() { + return User::class; + } + + public function countByUsernameOrEmail(string $pattern): int { $qb = $this->queryByUsernameOrEmail($pattern); - + $qb->select('COUNT(u)'); - + return (int) $qb->getQuery()->getSingleScalarResult(); } - - public function findByUsernameOrEmail($pattern) + + public function findByUsernameOrEmail(string $pattern) { $qb = $this->queryByUsernameOrEmail($pattern); - + return $qb->getQuery()->getResult(); } - - public function findOneByUsernameOrEmail($pattern) + + public function findOneByUsernameOrEmail(string $pattern) { $qb = $this->queryByUsernameOrEmail($pattern); - + return $qb->getQuery()->getSingleResult(); } - + /** * Get the users having a specific flags - * - * If provided, only the users amongst "filtered users" are searched. This - * allows to make a first search amongst users based on role and center + * + * If provided, only the users amongst "filtered users" are searched. This + * allows to make a first search amongst users based on role and center * and, then filter those users having some flags. - * + * * @param \Chill\MainBundle\Entity\User[] $amongstUsers */ - public function findUsersHavingFlags($flag, $amongstUsers = []) + public function findUsersHavingFlags($flag, array $amongstUsers = []): array { - $gcs = $this->_em->createQuery("SELECT DISTINCT gc " - . "FROM ".GroupCenter::class." gc " - . "JOIN gc.permissionsGroup pg " - . "WHERE " - . "JSONB_EXISTS_IN_ARRAY(pg.flags, :flag) = :true ") + $gcs = $this + ->entityManager + ->createQuery( + "SELECT DISTINCT gc " . + "FROM ".GroupCenter::class." gc " . + "JOIN gc.permissionsGroup pg " . + "WHERE " . + "JSONB_EXISTS_IN_ARRAY(pg.flags, :flag) = :true " + ) ->setParameters([ 'true' => true, 'flag' => $flag ]) ->getResult(); - + if (count($gcs) === 0) { return []; } - - $qb = $this->_em->createQueryBuilder(); + + $qb = $this->entityManager->createQueryBuilder(); $qb ->select('DISTINCT u') ->from(User::class, 'u') - ->where("u.enabled = 'TRUE'") - ; - + ->where("u.enabled = 'TRUE'"); + $orx = $qb->expr()->orX(); + foreach($gcs as $i => $gc) { - $orx->add(':gc_'.$i.' MEMBER OF u.groupCenters'); - $qb->setParameter('gc_'.$i, $gc); + $orx->add(':gc_' . $i . ' MEMBER OF u.groupCenters'); + $qb->setParameter('gc_' . $i, $gc); } - + $qb->andWhere($orx); - - if (count($amongstUsers) > 0) { + + if ($amongstUsers !== []) { $qb ->andWhere($qb->expr()->in('u', ':amongstUsers')) - ->setParameter('amongstUsers', $amongstUsers) - ; + ->setParameter('amongstUsers', $amongstUsers); } - + return $qb->getQuery()->getResult(); } - - protected function queryByUsernameOrEmail($pattern) + + protected function queryByUsernameOrEmail(string $pattern): QueryBuilder { - $qb = $this->createQueryBuilder('u'); - + $qb = $this->entityManager->createQueryBuilder('u'); + $searchByPattern = $qb->expr()->orX(); - + $searchByPattern ->add($qb->expr()->eq('u.usernameCanonical', 'LOWER(UNACCENT(:pattern))')) - ->add($qb->expr()->eq('u.emailCanonical', 'LOWER(UNACCENT(:pattern))')) - ; - + ->add($qb->expr()->eq('u.emailCanonical', 'LOWER(UNACCENT(:pattern))')); + $qb ->where($searchByPattern) - ->setParameter('pattern', $pattern) - ; - + ->setParameter('pattern', $pattern); + return $qb; } } diff --git a/src/Bundle/ChillMainBundle/Resources/public/img/draggable.svg b/src/Bundle/ChillMainBundle/Resources/public/img/draggable.svg new file mode 100644 index 000000000..0b3561cce --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/public/img/draggable.svg @@ -0,0 +1,121 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Bundle/ChillMainBundle/Resources/public/js/chill.js b/src/Bundle/ChillMainBundle/Resources/public/js/chill.js index 23f339b32..709c755c6 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/js/chill.js +++ b/src/Bundle/ChillMainBundle/Resources/public/js/chill.js @@ -5,84 +5,6 @@ var chill = function() { - /* intialiase the pikaday module */ - function initPikaday(locale) { - var i18n_trad = { - fr: { - previousMonth : 'Mois précédent', - nextMonth : 'Mois suivant', - months : ['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre'], - weekdays : ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], - weekdaysShort : ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'] - }, - nl: { - previousMonth : 'Vorig maand', - nextMonth : 'Volgende maand', - months : ['Januari','Februari','Maart','April','Mei','Juni','Juli','Augustus','September','Oktober','November','December'], - weekdays : ['Zondag','Maandag','Dinsdag','Woensdag','Donderdag','Vrijdag','Zaterdag'], - weekdaysShort : ['Zon','Ma','Di','Wo','Do','Vri','Zat'] - } - }; - - var pikaday_options = { - format: 'D-M-YYYY', - yearRange: [parseInt(moment().format('YYYY')) - 100, parseInt(moment().format('YYYY'))], - }; - - if(locale in i18n_trad) { - pikaday_options.i18n = i18n_trad[locale]; - } - - $('.datepicker').pikaday( - pikaday_options - ); - } - - /* emulate the position:sticky */ - function emulateSticky() { - var need_emulation = false; - - $('.sticky-form-buttons').each(function(i,stick_element) { - if($(stick_element).css('position') !== 'sticky') { - need_emulation = true; - stick_element.init_offset_top = $(stick_element).offset().top; - } - }); - - function emulate() { - $('.sticky-form-buttons').each(function(i,stick_element) { - if (($(window).scrollTop() + $(window).height()) < stick_element.init_offset_top) { - //sticky at bottom - $(stick_element).css('position','fixed'); - $(stick_element).css('bottom','0'); - $(stick_element).css('top',''); - $(stick_element).css('width',$(stick_element).parent().outerWidth()); - } else if (stick_element.init_offset_top < $(window).scrollTop()) { - //sticky at top - $(stick_element).css('position','fixed'); - $(stick_element).css('top','0'); - $(stick_element).css('bottom',''); - $(stick_element).css('width',$(stick_element).parent().outerWidth()); - } else { - //no sticky - $(stick_element).css('position','initial'); - $(stick_element).css('bottom',''); - $(stick_element).css('width',''); - $(stick_element).css('top',''); - } - }); - } - - if(need_emulation) { - $(window).scroll(function() { - emulate(); - }); - - emulate(); - } - } - - /** * Display an alert message when the user wants to leave a page containing a given form * in a given state. @@ -411,8 +333,6 @@ var chill = function() { } return { - initPikaday: initPikaday, - emulateSticky: emulateSticky, checkOtherValueOnChange: checkOtherValueOnChange, displayAlertWhenLeavingModifiedForm: displayAlertWhenLeavingModifiedForm, displayAlertWhenLeavingUnsubmittedForm: displayAlertWhenLeavingUnsubmittedForm, diff --git a/src/Bundle/ChillMainBundle/Resources/public/js/collection/collections.js b/src/Bundle/ChillMainBundle/Resources/public/js/collection/collections.js index e8e697058..395f24412 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/js/collection/collections.js +++ b/src/Bundle/ChillMainBundle/Resources/public/js/collection/collections.js @@ -57,7 +57,6 @@ var handleAdd = function(button) { entry.classList.add('chill-collection__list__entry'); initializeRemove(collection, entry); collection.appendChild(entry); - chill.initPikaday('fr'); collection.dispatchEvent(event); window.dispatchEvent(event); diff --git a/src/Bundle/ChillMainBundle/Resources/public/js/date.js b/src/Bundle/ChillMainBundle/Resources/public/js/date.js new file mode 100644 index 000000000..7b9bf88a2 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/public/js/date.js @@ -0,0 +1,88 @@ +/** + * Some utils for manipulating dates + * + * **WARNING** experimental + */ + +/** + * Return the date to local ISO date, like YYYY-mm-dd + * + * The date is valid for the same timezone as the date's locale + * + * Do not take time into account + * + * **Experimental** + */ +const dateToISO = (date) => { + return [ + this.$store.state.startDate.getFullYear(), + (this.$store.state.startDate.getMonth() + 1).toString().padStart(2, '0'), + this.$store.state.startDate.getDate().toString().padStart(2, '0') + ].join('-'); +}; + +/** + * Return a date object from iso string formatted as YYYY-mm-dd + * + * **Experimental** + */ +const ISOToDate = (str) => { + let + [year, month, day] = str.split('-'); + + return new Date(year, month-1, day); +} + +/** + * Return a date object from iso string formatted as YYYY-mm-dd:HH:MM:ss+01:00 + * + * **Experimental** + */ +const ISOToDatetime = (str) => { + console.log(str); + let + [cal, times] = str.split('T'), + [year, month, date] = cal.split('-'), + [time, timezone] = cal.split(times.charAt(9)), + [hours, minutes, seconds] = cal.split(':') + ; + + return new Date(year, month-1, date, hours, minutes, seconds); +} + +/** + * Convert a date to ISO8601, valid for usage in api + * + */ +const datetimeToISO = (date) => { + let cal, time, offset; + cal = [ + date.getFullYear(), + (date.getMonth() + 1).toString().padStart(2, '0'), + date.getDate().toString().padStart(2, '0') + ].join('-'); + + time = [ + date.getHours().toString().padStart(2, '0'), + date.getMinutes().toString().padStart(2, '0'), + date.getSeconds().toString().padStart(2, '0') + ].join(':'); + + offset = [ + date.getTimezoneOffset() <= 0 ? '+' : '-', + Math.abs(Math.floor(date.getTimezoneOffset() / 60)).toString().padStart(2, '0'), + ':', + Math.abs(date.getTimezoneOffset() % 60).toString().padStart(2, '0'), + ].join(''); + + let x = cal + 'T' + time + offset; + + return x; +}; + +export { + dateToISO, + ISOToDate, + ISOToDatetime, + datetimeToISO +}; diff --git a/src/Bundle/ChillMainBundle/Resources/public/js/moment.js b/src/Bundle/ChillMainBundle/Resources/public/js/moment.js deleted file mode 100644 index 85e190d4a..000000000 --- a/src/Bundle/ChillMainBundle/Resources/public/js/moment.js +++ /dev/null @@ -1,2936 +0,0 @@ -//! moment.js -//! version : 2.8.4 -//! authors : Tim Wood, Iskren Chernev, Moment.js contributors -//! license : MIT -//! momentjs.com - -(function (undefined) { - /************************************ - Constants - ************************************/ - - var moment, - VERSION = '2.8.4', - // the global-scope this is NOT the global object in Node.js - globalScope = typeof global !== 'undefined' ? global : this, - oldGlobalMoment, - round = Math.round, - hasOwnProperty = Object.prototype.hasOwnProperty, - i, - - YEAR = 0, - MONTH = 1, - DATE = 2, - HOUR = 3, - MINUTE = 4, - SECOND = 5, - MILLISECOND = 6, - - // internal storage for locale config files - locales = {}, - - // extra moment internal properties (plugins register props here) - momentProperties = [], - - // check for nodeJS - hasModule = (typeof module !== 'undefined' && module && module.exports), - - // ASP.NET json date format regex - aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, - aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, - - // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html - // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere - isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, - - // format tokens - formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g, - localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, - - // parsing token regexes - parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 - parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 - parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 - parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 - parseTokenDigits = /\d+/, // nonzero number of digits - parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. - parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z - parseTokenT = /T/i, // T (ISO separator) - parseTokenOffsetMs = /[\+\-]?\d+/, // 1234567890123 - parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 - - //strict parsing regexes - parseTokenOneDigit = /\d/, // 0 - 9 - parseTokenTwoDigits = /\d\d/, // 00 - 99 - parseTokenThreeDigits = /\d{3}/, // 000 - 999 - parseTokenFourDigits = /\d{4}/, // 0000 - 9999 - parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999 - parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf - - // iso 8601 regex - // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) - isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, - - isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', - - isoDates = [ - ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], - ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], - ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], - ['GGGG-[W]WW', /\d{4}-W\d{2}/], - ['YYYY-DDD', /\d{4}-\d{3}/] - ], - - // iso time formats and regexes - isoTimes = [ - ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/], - ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], - ['HH:mm', /(T| )\d\d:\d\d/], - ['HH', /(T| )\d\d/] - ], - - // timezone chunker '+10:00' > ['10', '00'] or '-1530' > ['-15', '30'] - parseTimezoneChunker = /([\+\-]|\d\d)/gi, - - // getter and setter names - proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), - unitMillisecondFactors = { - 'Milliseconds' : 1, - 'Seconds' : 1e3, - 'Minutes' : 6e4, - 'Hours' : 36e5, - 'Days' : 864e5, - 'Months' : 2592e6, - 'Years' : 31536e6 - }, - - unitAliases = { - ms : 'millisecond', - s : 'second', - m : 'minute', - h : 'hour', - d : 'day', - D : 'date', - w : 'week', - W : 'isoWeek', - M : 'month', - Q : 'quarter', - y : 'year', - DDD : 'dayOfYear', - e : 'weekday', - E : 'isoWeekday', - gg: 'weekYear', - GG: 'isoWeekYear' - }, - - camelFunctions = { - dayofyear : 'dayOfYear', - isoweekday : 'isoWeekday', - isoweek : 'isoWeek', - weekyear : 'weekYear', - isoweekyear : 'isoWeekYear' - }, - - // format function strings - formatFunctions = {}, - - // default relative time thresholds - relativeTimeThresholds = { - s: 45, // seconds to minute - m: 45, // minutes to hour - h: 22, // hours to day - d: 26, // days to month - M: 11 // months to year - }, - - // tokens to ordinalize and pad - ordinalizeTokens = 'DDD w W M D d'.split(' '), - paddedTokens = 'M D H h m s w W'.split(' '), - - formatTokenFunctions = { - M : function () { - return this.month() + 1; - }, - MMM : function (format) { - return this.localeData().monthsShort(this, format); - }, - MMMM : function (format) { - return this.localeData().months(this, format); - }, - D : function () { - return this.date(); - }, - DDD : function () { - return this.dayOfYear(); - }, - d : function () { - return this.day(); - }, - dd : function (format) { - return this.localeData().weekdaysMin(this, format); - }, - ddd : function (format) { - return this.localeData().weekdaysShort(this, format); - }, - dddd : function (format) { - return this.localeData().weekdays(this, format); - }, - w : function () { - return this.week(); - }, - W : function () { - return this.isoWeek(); - }, - YY : function () { - return leftZeroFill(this.year() % 100, 2); - }, - YYYY : function () { - return leftZeroFill(this.year(), 4); - }, - YYYYY : function () { - return leftZeroFill(this.year(), 5); - }, - YYYYYY : function () { - var y = this.year(), sign = y >= 0 ? '+' : '-'; - return sign + leftZeroFill(Math.abs(y), 6); - }, - gg : function () { - return leftZeroFill(this.weekYear() % 100, 2); - }, - gggg : function () { - return leftZeroFill(this.weekYear(), 4); - }, - ggggg : function () { - return leftZeroFill(this.weekYear(), 5); - }, - GG : function () { - return leftZeroFill(this.isoWeekYear() % 100, 2); - }, - GGGG : function () { - return leftZeroFill(this.isoWeekYear(), 4); - }, - GGGGG : function () { - return leftZeroFill(this.isoWeekYear(), 5); - }, - e : function () { - return this.weekday(); - }, - E : function () { - return this.isoWeekday(); - }, - a : function () { - return this.localeData().meridiem(this.hours(), this.minutes(), true); - }, - A : function () { - return this.localeData().meridiem(this.hours(), this.minutes(), false); - }, - H : function () { - return this.hours(); - }, - h : function () { - return this.hours() % 12 || 12; - }, - m : function () { - return this.minutes(); - }, - s : function () { - return this.seconds(); - }, - S : function () { - return toInt(this.milliseconds() / 100); - }, - SS : function () { - return leftZeroFill(toInt(this.milliseconds() / 10), 2); - }, - SSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - SSSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - Z : function () { - var a = -this.zone(), - b = '+'; - if (a < 0) { - a = -a; - b = '-'; - } - return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2); - }, - ZZ : function () { - var a = -this.zone(), - b = '+'; - if (a < 0) { - a = -a; - b = '-'; - } - return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); - }, - z : function () { - return this.zoneAbbr(); - }, - zz : function () { - return this.zoneName(); - }, - x : function () { - return this.valueOf(); - }, - X : function () { - return this.unix(); - }, - Q : function () { - return this.quarter(); - } - }, - - deprecations = {}, - - lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin']; - - // Pick the first defined of two or three arguments. dfl comes from - // default. - function dfl(a, b, c) { - switch (arguments.length) { - case 2: return a != null ? a : b; - case 3: return a != null ? a : b != null ? b : c; - default: throw new Error('Implement me'); - } - } - - function hasOwnProp(a, b) { - return hasOwnProperty.call(a, b); - } - - function defaultParsingFlags() { - // We need to deep clone this object, and es5 standard is not very - // helpful. - return { - empty : false, - unusedTokens : [], - unusedInput : [], - overflow : -2, - charsLeftOver : 0, - nullInput : false, - invalidMonth : null, - invalidFormat : false, - userInvalidated : false, - iso: false - }; - } - - function printMsg(msg) { - if (moment.suppressDeprecationWarnings === false && - typeof console !== 'undefined' && console.warn) { - console.warn('Deprecation warning: ' + msg); - } - } - - function deprecate(msg, fn) { - var firstTime = true; - return extend(function () { - if (firstTime) { - printMsg(msg); - firstTime = false; - } - return fn.apply(this, arguments); - }, fn); - } - - function deprecateSimple(name, msg) { - if (!deprecations[name]) { - printMsg(msg); - deprecations[name] = true; - } - } - - function padToken(func, count) { - return function (a) { - return leftZeroFill(func.call(this, a), count); - }; - } - function ordinalizeToken(func, period) { - return function (a) { - return this.localeData().ordinal(func.call(this, a), period); - }; - } - - while (ordinalizeTokens.length) { - i = ordinalizeTokens.pop(); - formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); - } - while (paddedTokens.length) { - i = paddedTokens.pop(); - formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); - } - formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); - - - /************************************ - Constructors - ************************************/ - - function Locale() { - } - - // Moment prototype object - function Moment(config, skipOverflow) { - if (skipOverflow !== false) { - checkOverflow(config); - } - copyConfig(this, config); - this._d = new Date(+config._d); - } - - // Duration Constructor - function Duration(duration) { - var normalizedInput = normalizeObjectUnits(duration), - years = normalizedInput.year || 0, - quarters = normalizedInput.quarter || 0, - months = normalizedInput.month || 0, - weeks = normalizedInput.week || 0, - days = normalizedInput.day || 0, - hours = normalizedInput.hour || 0, - minutes = normalizedInput.minute || 0, - seconds = normalizedInput.second || 0, - milliseconds = normalizedInput.millisecond || 0; - - // representation for dateAddRemove - this._milliseconds = +milliseconds + - seconds * 1e3 + // 1000 - minutes * 6e4 + // 1000 * 60 - hours * 36e5; // 1000 * 60 * 60 - // Because of dateAddRemove treats 24 hours as different from a - // day when working around DST, we need to store them separately - this._days = +days + - weeks * 7; - // It is impossible translate months into days without knowing - // which months you are are talking about, so we have to store - // it separately. - this._months = +months + - quarters * 3 + - years * 12; - - this._data = {}; - - this._locale = moment.localeData(); - - this._bubble(); - } - - /************************************ - Helpers - ************************************/ - - - function extend(a, b) { - for (var i in b) { - if (hasOwnProp(b, i)) { - a[i] = b[i]; - } - } - - if (hasOwnProp(b, 'toString')) { - a.toString = b.toString; - } - - if (hasOwnProp(b, 'valueOf')) { - a.valueOf = b.valueOf; - } - - return a; - } - - function copyConfig(to, from) { - var i, prop, val; - - if (typeof from._isAMomentObject !== 'undefined') { - to._isAMomentObject = from._isAMomentObject; - } - if (typeof from._i !== 'undefined') { - to._i = from._i; - } - if (typeof from._f !== 'undefined') { - to._f = from._f; - } - if (typeof from._l !== 'undefined') { - to._l = from._l; - } - if (typeof from._strict !== 'undefined') { - to._strict = from._strict; - } - if (typeof from._tzm !== 'undefined') { - to._tzm = from._tzm; - } - if (typeof from._isUTC !== 'undefined') { - to._isUTC = from._isUTC; - } - if (typeof from._offset !== 'undefined') { - to._offset = from._offset; - } - if (typeof from._pf !== 'undefined') { - to._pf = from._pf; - } - if (typeof from._locale !== 'undefined') { - to._locale = from._locale; - } - - if (momentProperties.length > 0) { - for (i in momentProperties) { - prop = momentProperties[i]; - val = from[prop]; - if (typeof val !== 'undefined') { - to[prop] = val; - } - } - } - - return to; - } - - function absRound(number) { - if (number < 0) { - return Math.ceil(number); - } else { - return Math.floor(number); - } - } - - // left zero fill a number - // see http://jsperf.com/left-zero-filling for performance comparison - function leftZeroFill(number, targetLength, forceSign) { - var output = '' + Math.abs(number), - sign = number >= 0; - - while (output.length < targetLength) { - output = '0' + output; - } - return (sign ? (forceSign ? '+' : '') : '-') + output; - } - - function positiveMomentsDifference(base, other) { - var res = {milliseconds: 0, months: 0}; - - res.months = other.month() - base.month() + - (other.year() - base.year()) * 12; - if (base.clone().add(res.months, 'M').isAfter(other)) { - --res.months; - } - - res.milliseconds = +other - +(base.clone().add(res.months, 'M')); - - return res; - } - - function momentsDifference(base, other) { - var res; - other = makeAs(other, base); - if (base.isBefore(other)) { - res = positiveMomentsDifference(base, other); - } else { - res = positiveMomentsDifference(other, base); - res.milliseconds = -res.milliseconds; - res.months = -res.months; - } - - return res; - } - - // TODO: remove 'name' arg after deprecation is removed - function createAdder(direction, name) { - return function (val, period) { - var dur, tmp; - //invert the arguments, but complain about it - if (period !== null && !isNaN(+period)) { - deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).'); - tmp = val; val = period; period = tmp; - } - - val = typeof val === 'string' ? +val : val; - dur = moment.duration(val, period); - addOrSubtractDurationFromMoment(this, dur, direction); - return this; - }; - } - - function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) { - var milliseconds = duration._milliseconds, - days = duration._days, - months = duration._months; - updateOffset = updateOffset == null ? true : updateOffset; - - if (milliseconds) { - mom._d.setTime(+mom._d + milliseconds * isAdding); - } - if (days) { - rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding); - } - if (months) { - rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding); - } - if (updateOffset) { - moment.updateOffset(mom, days || months); - } - } - - // check if is an array - function isArray(input) { - return Object.prototype.toString.call(input) === '[object Array]'; - } - - function isDate(input) { - return Object.prototype.toString.call(input) === '[object Date]' || - input instanceof Date; - } - - // compare two arrays, return the number of differences - function compareArrays(array1, array2, dontConvert) { - var len = Math.min(array1.length, array2.length), - lengthDiff = Math.abs(array1.length - array2.length), - diffs = 0, - i; - for (i = 0; i < len; i++) { - if ((dontConvert && array1[i] !== array2[i]) || - (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { - diffs++; - } - } - return diffs + lengthDiff; - } - - function normalizeUnits(units) { - if (units) { - var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); - units = unitAliases[units] || camelFunctions[lowered] || lowered; - } - return units; - } - - function normalizeObjectUnits(inputObject) { - var normalizedInput = {}, - normalizedProp, - prop; - - for (prop in inputObject) { - if (hasOwnProp(inputObject, prop)) { - normalizedProp = normalizeUnits(prop); - if (normalizedProp) { - normalizedInput[normalizedProp] = inputObject[prop]; - } - } - } - - return normalizedInput; - } - - function makeList(field) { - var count, setter; - - if (field.indexOf('week') === 0) { - count = 7; - setter = 'day'; - } - else if (field.indexOf('month') === 0) { - count = 12; - setter = 'month'; - } - else { - return; - } - - moment[field] = function (format, index) { - var i, getter, - method = moment._locale[field], - results = []; - - if (typeof format === 'number') { - index = format; - format = undefined; - } - - getter = function (i) { - var m = moment().utc().set(setter, i); - return method.call(moment._locale, m, format || ''); - }; - - if (index != null) { - return getter(index); - } - else { - for (i = 0; i < count; i++) { - results.push(getter(i)); - } - return results; - } - }; - } - - function toInt(argumentForCoercion) { - var coercedNumber = +argumentForCoercion, - value = 0; - - if (coercedNumber !== 0 && isFinite(coercedNumber)) { - if (coercedNumber >= 0) { - value = Math.floor(coercedNumber); - } else { - value = Math.ceil(coercedNumber); - } - } - - return value; - } - - function daysInMonth(year, month) { - return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); - } - - function weeksInYear(year, dow, doy) { - return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week; - } - - function daysInYear(year) { - return isLeapYear(year) ? 366 : 365; - } - - function isLeapYear(year) { - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - } - - function checkOverflow(m) { - var overflow; - if (m._a && m._pf.overflow === -2) { - overflow = - m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : - m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : - m._a[HOUR] < 0 || m._a[HOUR] > 24 || - (m._a[HOUR] === 24 && (m._a[MINUTE] !== 0 || - m._a[SECOND] !== 0 || - m._a[MILLISECOND] !== 0)) ? HOUR : - m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : - m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : - m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : - -1; - - if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { - overflow = DATE; - } - - m._pf.overflow = overflow; - } - } - - function isValid(m) { - if (m._isValid == null) { - m._isValid = !isNaN(m._d.getTime()) && - m._pf.overflow < 0 && - !m._pf.empty && - !m._pf.invalidMonth && - !m._pf.nullInput && - !m._pf.invalidFormat && - !m._pf.userInvalidated; - - if (m._strict) { - m._isValid = m._isValid && - m._pf.charsLeftOver === 0 && - m._pf.unusedTokens.length === 0 && - m._pf.bigHour === undefined; - } - } - return m._isValid; - } - - function normalizeLocale(key) { - return key ? key.toLowerCase().replace('_', '-') : key; - } - - // pick the locale from the array - // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each - // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root - function chooseLocale(names) { - var i = 0, j, next, locale, split; - - while (i < names.length) { - split = normalizeLocale(names[i]).split('-'); - j = split.length; - next = normalizeLocale(names[i + 1]); - next = next ? next.split('-') : null; - while (j > 0) { - locale = loadLocale(split.slice(0, j).join('-')); - if (locale) { - return locale; - } - if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { - //the next array item is better than a shallower substring of this one - break; - } - j--; - } - i++; - } - return null; - } - - function loadLocale(name) { - var oldLocale = null; - if (!locales[name] && hasModule) { - try { - oldLocale = moment.locale(); - require('./locale/' + name); - // because defineLocale currently also sets the global locale, we want to undo that for lazy loaded locales - moment.locale(oldLocale); - } catch (e) { } - } - return locales[name]; - } - - // Return a moment from input, that is local/utc/zone equivalent to model. - function makeAs(input, model) { - var res, diff; - if (model._isUTC) { - res = model.clone(); - diff = (moment.isMoment(input) || isDate(input) ? - +input : +moment(input)) - (+res); - // Use low-level api, because this fn is low-level api. - res._d.setTime(+res._d + diff); - moment.updateOffset(res, false); - return res; - } else { - return moment(input).local(); - } - } - - /************************************ - Locale - ************************************/ - - - extend(Locale.prototype, { - - set : function (config) { - var prop, i; - for (i in config) { - prop = config[i]; - if (typeof prop === 'function') { - this[i] = prop; - } else { - this['_' + i] = prop; - } - } - // Lenient ordinal parsing accepts just a number in addition to - // number + (possibly) stuff coming from _ordinalParseLenient. - this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + /\d{1,2}/.source); - }, - - _months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), - months : function (m) { - return this._months[m.month()]; - }, - - _monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), - monthsShort : function (m) { - return this._monthsShort[m.month()]; - }, - - monthsParse : function (monthName, format, strict) { - var i, mom, regex; - - if (!this._monthsParse) { - this._monthsParse = []; - this._longMonthsParse = []; - this._shortMonthsParse = []; - } - - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - mom = moment.utc([2000, i]); - if (strict && !this._longMonthsParse[i]) { - this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); - this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); - } - if (!strict && !this._monthsParse[i]) { - regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); - this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { - return i; - } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { - return i; - } else if (!strict && this._monthsParse[i].test(monthName)) { - return i; - } - } - }, - - _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), - weekdays : function (m) { - return this._weekdays[m.day()]; - }, - - _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), - weekdaysShort : function (m) { - return this._weekdaysShort[m.day()]; - }, - - _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), - weekdaysMin : function (m) { - return this._weekdaysMin[m.day()]; - }, - - weekdaysParse : function (weekdayName) { - var i, mom, regex; - - if (!this._weekdaysParse) { - this._weekdaysParse = []; - } - - for (i = 0; i < 7; i++) { - // make the regex if we don't have it already - if (!this._weekdaysParse[i]) { - mom = moment([2000, 1]).day(i); - regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); - this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._weekdaysParse[i].test(weekdayName)) { - return i; - } - } - }, - - _longDateFormat : { - LTS : 'h:mm:ss A', - LT : 'h:mm A', - L : 'MM/DD/YYYY', - LL : 'MMMM D, YYYY', - LLL : 'MMMM D, YYYY LT', - LLLL : 'dddd, MMMM D, YYYY LT' - }, - longDateFormat : function (key) { - var output = this._longDateFormat[key]; - if (!output && this._longDateFormat[key.toUpperCase()]) { - output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { - return val.slice(1); - }); - this._longDateFormat[key] = output; - } - return output; - }, - - isPM : function (input) { - // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays - // Using charAt should be more compatible. - return ((input + '').toLowerCase().charAt(0) === 'p'); - }, - - _meridiemParse : /[ap]\.?m?\.?/i, - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'pm' : 'PM'; - } else { - return isLower ? 'am' : 'AM'; - } - }, - - _calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - calendar : function (key, mom, now) { - var output = this._calendar[key]; - return typeof output === 'function' ? output.apply(mom, [now]) : output; - }, - - _relativeTime : { - future : 'in %s', - past : '%s ago', - s : 'a few seconds', - m : 'a minute', - mm : '%d minutes', - h : 'an hour', - hh : '%d hours', - d : 'a day', - dd : '%d days', - M : 'a month', - MM : '%d months', - y : 'a year', - yy : '%d years' - }, - - relativeTime : function (number, withoutSuffix, string, isFuture) { - var output = this._relativeTime[string]; - return (typeof output === 'function') ? - output(number, withoutSuffix, string, isFuture) : - output.replace(/%d/i, number); - }, - - pastFuture : function (diff, output) { - var format = this._relativeTime[diff > 0 ? 'future' : 'past']; - return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); - }, - - ordinal : function (number) { - return this._ordinal.replace('%d', number); - }, - _ordinal : '%d', - _ordinalParse : /\d{1,2}/, - - preparse : function (string) { - return string; - }, - - postformat : function (string) { - return string; - }, - - week : function (mom) { - return weekOfYear(mom, this._week.dow, this._week.doy).week; - }, - - _week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - }, - - _invalidDate: 'Invalid date', - invalidDate: function () { - return this._invalidDate; - } - }); - - /************************************ - Formatting - ************************************/ - - - function removeFormattingTokens(input) { - if (input.match(/\[[\s\S]/)) { - return input.replace(/^\[|\]$/g, ''); - } - return input.replace(/\\/g, ''); - } - - function makeFormatFunction(format) { - var array = format.match(formattingTokens), i, length; - - for (i = 0, length = array.length; i < length; i++) { - if (formatTokenFunctions[array[i]]) { - array[i] = formatTokenFunctions[array[i]]; - } else { - array[i] = removeFormattingTokens(array[i]); - } - } - - return function (mom) { - var output = ''; - for (i = 0; i < length; i++) { - output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; - } - return output; - }; - } - - // format date using native date object - function formatMoment(m, format) { - if (!m.isValid()) { - return m.localeData().invalidDate(); - } - - format = expandFormat(format, m.localeData()); - - if (!formatFunctions[format]) { - formatFunctions[format] = makeFormatFunction(format); - } - - return formatFunctions[format](m); - } - - function expandFormat(format, locale) { - var i = 5; - - function replaceLongDateFormatTokens(input) { - return locale.longDateFormat(input) || input; - } - - localFormattingTokens.lastIndex = 0; - while (i >= 0 && localFormattingTokens.test(format)) { - format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); - localFormattingTokens.lastIndex = 0; - i -= 1; - } - - return format; - } - - - /************************************ - Parsing - ************************************/ - - - // get the regex to find the next token - function getParseRegexForToken(token, config) { - var a, strict = config._strict; - switch (token) { - case 'Q': - return parseTokenOneDigit; - case 'DDDD': - return parseTokenThreeDigits; - case 'YYYY': - case 'GGGG': - case 'gggg': - return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; - case 'Y': - case 'G': - case 'g': - return parseTokenSignedNumber; - case 'YYYYYY': - case 'YYYYY': - case 'GGGGG': - case 'ggggg': - return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; - case 'S': - if (strict) { - return parseTokenOneDigit; - } - /* falls through */ - case 'SS': - if (strict) { - return parseTokenTwoDigits; - } - /* falls through */ - case 'SSS': - if (strict) { - return parseTokenThreeDigits; - } - /* falls through */ - case 'DDD': - return parseTokenOneToThreeDigits; - case 'MMM': - case 'MMMM': - case 'dd': - case 'ddd': - case 'dddd': - return parseTokenWord; - case 'a': - case 'A': - return config._locale._meridiemParse; - case 'x': - return parseTokenOffsetMs; - case 'X': - return parseTokenTimestampMs; - case 'Z': - case 'ZZ': - return parseTokenTimezone; - case 'T': - return parseTokenT; - case 'SSSS': - return parseTokenDigits; - case 'MM': - case 'DD': - case 'YY': - case 'GG': - case 'gg': - case 'HH': - case 'hh': - case 'mm': - case 'ss': - case 'ww': - case 'WW': - return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; - case 'M': - case 'D': - case 'd': - case 'H': - case 'h': - case 'm': - case 's': - case 'w': - case 'W': - case 'e': - case 'E': - return parseTokenOneOrTwoDigits; - case 'Do': - return strict ? config._locale._ordinalParse : config._locale._ordinalParseLenient; - default : - a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); - return a; - } - } - - function timezoneMinutesFromString(string) { - string = string || ''; - var possibleTzMatches = (string.match(parseTokenTimezone) || []), - tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], - parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], - minutes = +(parts[1] * 60) + toInt(parts[2]); - - return parts[0] === '+' ? -minutes : minutes; - } - - // function to convert string input to date - function addTimeToArrayFromToken(token, input, config) { - var a, datePartArray = config._a; - - switch (token) { - // QUARTER - case 'Q': - if (input != null) { - datePartArray[MONTH] = (toInt(input) - 1) * 3; - } - break; - // MONTH - case 'M' : // fall through to MM - case 'MM' : - if (input != null) { - datePartArray[MONTH] = toInt(input) - 1; - } - break; - case 'MMM' : // fall through to MMMM - case 'MMMM' : - a = config._locale.monthsParse(input, token, config._strict); - // if we didn't find a month name, mark the date as invalid. - if (a != null) { - datePartArray[MONTH] = a; - } else { - config._pf.invalidMonth = input; - } - break; - // DAY OF MONTH - case 'D' : // fall through to DD - case 'DD' : - if (input != null) { - datePartArray[DATE] = toInt(input); - } - break; - case 'Do' : - if (input != null) { - datePartArray[DATE] = toInt(parseInt( - input.match(/\d{1,2}/)[0], 10)); - } - break; - // DAY OF YEAR - case 'DDD' : // fall through to DDDD - case 'DDDD' : - if (input != null) { - config._dayOfYear = toInt(input); - } - - break; - // YEAR - case 'YY' : - datePartArray[YEAR] = moment.parseTwoDigitYear(input); - break; - case 'YYYY' : - case 'YYYYY' : - case 'YYYYYY' : - datePartArray[YEAR] = toInt(input); - break; - // AM / PM - case 'a' : // fall through to A - case 'A' : - config._isPm = config._locale.isPM(input); - break; - // HOUR - case 'h' : // fall through to hh - case 'hh' : - config._pf.bigHour = true; - /* falls through */ - case 'H' : // fall through to HH - case 'HH' : - datePartArray[HOUR] = toInt(input); - break; - // MINUTE - case 'm' : // fall through to mm - case 'mm' : - datePartArray[MINUTE] = toInt(input); - break; - // SECOND - case 's' : // fall through to ss - case 'ss' : - datePartArray[SECOND] = toInt(input); - break; - // MILLISECOND - case 'S' : - case 'SS' : - case 'SSS' : - case 'SSSS' : - datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); - break; - // UNIX OFFSET (MILLISECONDS) - case 'x': - config._d = new Date(toInt(input)); - break; - // UNIX TIMESTAMP WITH MS - case 'X': - config._d = new Date(parseFloat(input) * 1000); - break; - // TIMEZONE - case 'Z' : // fall through to ZZ - case 'ZZ' : - config._useUTC = true; - config._tzm = timezoneMinutesFromString(input); - break; - // WEEKDAY - human - case 'dd': - case 'ddd': - case 'dddd': - a = config._locale.weekdaysParse(input); - // if we didn't get a weekday name, mark the date as invalid - if (a != null) { - config._w = config._w || {}; - config._w['d'] = a; - } else { - config._pf.invalidWeekday = input; - } - break; - // WEEK, WEEK DAY - numeric - case 'w': - case 'ww': - case 'W': - case 'WW': - case 'd': - case 'e': - case 'E': - token = token.substr(0, 1); - /* falls through */ - case 'gggg': - case 'GGGG': - case 'GGGGG': - token = token.substr(0, 2); - if (input) { - config._w = config._w || {}; - config._w[token] = toInt(input); - } - break; - case 'gg': - case 'GG': - config._w = config._w || {}; - config._w[token] = moment.parseTwoDigitYear(input); - } - } - - function dayOfYearFromWeekInfo(config) { - var w, weekYear, week, weekday, dow, doy, temp; - - w = config._w; - if (w.GG != null || w.W != null || w.E != null) { - dow = 1; - doy = 4; - - // TODO: We need to take the current isoWeekYear, but that depends on - // how we interpret now (local, utc, fixed offset). So create - // a now version of current config (take local/utc/offset flags, and - // create now). - weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year); - week = dfl(w.W, 1); - weekday = dfl(w.E, 1); - } else { - dow = config._locale._week.dow; - doy = config._locale._week.doy; - - weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); - week = dfl(w.w, 1); - - if (w.d != null) { - // weekday -- low day numbers are considered next week - weekday = w.d; - if (weekday < dow) { - ++week; - } - } else if (w.e != null) { - // local weekday -- counting starts from begining of week - weekday = w.e + dow; - } else { - // default to begining of week - weekday = dow; - } - } - temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); - - config._a[YEAR] = temp.year; - config._dayOfYear = temp.dayOfYear; - } - - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function dateFromConfig(config) { - var i, date, input = [], currentDate, yearToUse; - - if (config._d) { - return; - } - - currentDate = currentDateArray(config); - - //compute day of the year from weeks and weekdays - if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { - dayOfYearFromWeekInfo(config); - } - - //if the day of the year is set, figure out what it is - if (config._dayOfYear) { - yearToUse = dfl(config._a[YEAR], currentDate[YEAR]); - - if (config._dayOfYear > daysInYear(yearToUse)) { - config._pf._overflowDayOfYear = true; - } - - date = makeUTCDate(yearToUse, 0, config._dayOfYear); - config._a[MONTH] = date.getUTCMonth(); - config._a[DATE] = date.getUTCDate(); - } - - // Default to current date. - // * if no year, month, day of month are given, default to today - // * if day of month is given, default month and year - // * if month is given, default only year - // * if year is given, don't default anything - for (i = 0; i < 3 && config._a[i] == null; ++i) { - config._a[i] = input[i] = currentDate[i]; - } - - // Zero out whatever was not defaulted, including time - for (; i < 7; i++) { - config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; - } - - // Check for 24:00:00.000 - if (config._a[HOUR] === 24 && - config._a[MINUTE] === 0 && - config._a[SECOND] === 0 && - config._a[MILLISECOND] === 0) { - config._nextDay = true; - config._a[HOUR] = 0; - } - - config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); - // Apply timezone offset from input. The actual zone can be changed - // with parseZone. - if (config._tzm != null) { - config._d.setUTCMinutes(config._d.getUTCMinutes() + config._tzm); - } - - if (config._nextDay) { - config._a[HOUR] = 24; - } - } - - function dateFromObject(config) { - var normalizedInput; - - if (config._d) { - return; - } - - normalizedInput = normalizeObjectUnits(config._i); - config._a = [ - normalizedInput.year, - normalizedInput.month, - normalizedInput.day || normalizedInput.date, - normalizedInput.hour, - normalizedInput.minute, - normalizedInput.second, - normalizedInput.millisecond - ]; - - dateFromConfig(config); - } - - function currentDateArray(config) { - var now = new Date(); - if (config._useUTC) { - return [ - now.getUTCFullYear(), - now.getUTCMonth(), - now.getUTCDate() - ]; - } else { - return [now.getFullYear(), now.getMonth(), now.getDate()]; - } - } - - // date from string and format string - function makeDateFromStringAndFormat(config) { - if (config._f === moment.ISO_8601) { - parseISO(config); - return; - } - - config._a = []; - config._pf.empty = true; - - // This array is used to make a Date, either with `new Date` or `Date.UTC` - var string = '' + config._i, - i, parsedInput, tokens, token, skipped, - stringLength = string.length, - totalParsedInputLength = 0; - - tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; - - for (i = 0; i < tokens.length; i++) { - token = tokens[i]; - parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; - if (parsedInput) { - skipped = string.substr(0, string.indexOf(parsedInput)); - if (skipped.length > 0) { - config._pf.unusedInput.push(skipped); - } - string = string.slice(string.indexOf(parsedInput) + parsedInput.length); - totalParsedInputLength += parsedInput.length; - } - // don't parse if it's not a known token - if (formatTokenFunctions[token]) { - if (parsedInput) { - config._pf.empty = false; - } - else { - config._pf.unusedTokens.push(token); - } - addTimeToArrayFromToken(token, parsedInput, config); - } - else if (config._strict && !parsedInput) { - config._pf.unusedTokens.push(token); - } - } - - // add remaining unparsed input length to the string - config._pf.charsLeftOver = stringLength - totalParsedInputLength; - if (string.length > 0) { - config._pf.unusedInput.push(string); - } - - // clear _12h flag if hour is <= 12 - if (config._pf.bigHour === true && config._a[HOUR] <= 12) { - config._pf.bigHour = undefined; - } - // handle am pm - if (config._isPm && config._a[HOUR] < 12) { - config._a[HOUR] += 12; - } - // if is 12 am, change hours to 0 - if (config._isPm === false && config._a[HOUR] === 12) { - config._a[HOUR] = 0; - } - dateFromConfig(config); - checkOverflow(config); - } - - function unescapeFormat(s) { - return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { - return p1 || p2 || p3 || p4; - }); - } - - // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript - function regexpEscape(s) { - return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - } - - // date from string and array of format strings - function makeDateFromStringAndArray(config) { - var tempConfig, - bestMoment, - - scoreToBeat, - i, - currentScore; - - if (config._f.length === 0) { - config._pf.invalidFormat = true; - config._d = new Date(NaN); - return; - } - - for (i = 0; i < config._f.length; i++) { - currentScore = 0; - tempConfig = copyConfig({}, config); - if (config._useUTC != null) { - tempConfig._useUTC = config._useUTC; - } - tempConfig._pf = defaultParsingFlags(); - tempConfig._f = config._f[i]; - makeDateFromStringAndFormat(tempConfig); - - if (!isValid(tempConfig)) { - continue; - } - - // if there is any input that was not parsed add a penalty for that format - currentScore += tempConfig._pf.charsLeftOver; - - //or tokens - currentScore += tempConfig._pf.unusedTokens.length * 10; - - tempConfig._pf.score = currentScore; - - if (scoreToBeat == null || currentScore < scoreToBeat) { - scoreToBeat = currentScore; - bestMoment = tempConfig; - } - } - - extend(config, bestMoment || tempConfig); - } - - // date from iso format - function parseISO(config) { - var i, l, - string = config._i, - match = isoRegex.exec(string); - - if (match) { - config._pf.iso = true; - for (i = 0, l = isoDates.length; i < l; i++) { - if (isoDates[i][1].exec(string)) { - // match[5] should be 'T' or undefined - config._f = isoDates[i][0] + (match[6] || ' '); - break; - } - } - for (i = 0, l = isoTimes.length; i < l; i++) { - if (isoTimes[i][1].exec(string)) { - config._f += isoTimes[i][0]; - break; - } - } - if (string.match(parseTokenTimezone)) { - config._f += 'Z'; - } - makeDateFromStringAndFormat(config); - } else { - config._isValid = false; - } - } - - // date from iso format or fallback - function makeDateFromString(config) { - parseISO(config); - if (config._isValid === false) { - delete config._isValid; - moment.createFromInputFallback(config); - } - } - - function map(arr, fn) { - var res = [], i; - for (i = 0; i < arr.length; ++i) { - res.push(fn(arr[i], i)); - } - return res; - } - - function makeDateFromInput(config) { - var input = config._i, matched; - if (input === undefined) { - config._d = new Date(); - } else if (isDate(input)) { - config._d = new Date(+input); - } else if ((matched = aspNetJsonRegex.exec(input)) !== null) { - config._d = new Date(+matched[1]); - } else if (typeof input === 'string') { - makeDateFromString(config); - } else if (isArray(input)) { - config._a = map(input.slice(0), function (obj) { - return parseInt(obj, 10); - }); - dateFromConfig(config); - } else if (typeof(input) === 'object') { - dateFromObject(config); - } else if (typeof(input) === 'number') { - // from milliseconds - config._d = new Date(input); - } else { - moment.createFromInputFallback(config); - } - } - - function makeDate(y, m, d, h, M, s, ms) { - //can't just apply() to create a date: - //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply - var date = new Date(y, m, d, h, M, s, ms); - - //the date constructor doesn't accept years < 1970 - if (y < 1970) { - date.setFullYear(y); - } - return date; - } - - function makeUTCDate(y) { - var date = new Date(Date.UTC.apply(null, arguments)); - if (y < 1970) { - date.setUTCFullYear(y); - } - return date; - } - - function parseWeekday(input, locale) { - if (typeof input === 'string') { - if (!isNaN(input)) { - input = parseInt(input, 10); - } - else { - input = locale.weekdaysParse(input); - if (typeof input !== 'number') { - return null; - } - } - } - return input; - } - - /************************************ - Relative Time - ************************************/ - - - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { - return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); - } - - function relativeTime(posNegDuration, withoutSuffix, locale) { - var duration = moment.duration(posNegDuration).abs(), - seconds = round(duration.as('s')), - minutes = round(duration.as('m')), - hours = round(duration.as('h')), - days = round(duration.as('d')), - months = round(duration.as('M')), - years = round(duration.as('y')), - - args = seconds < relativeTimeThresholds.s && ['s', seconds] || - minutes === 1 && ['m'] || - minutes < relativeTimeThresholds.m && ['mm', minutes] || - hours === 1 && ['h'] || - hours < relativeTimeThresholds.h && ['hh', hours] || - days === 1 && ['d'] || - days < relativeTimeThresholds.d && ['dd', days] || - months === 1 && ['M'] || - months < relativeTimeThresholds.M && ['MM', months] || - years === 1 && ['y'] || ['yy', years]; - - args[2] = withoutSuffix; - args[3] = +posNegDuration > 0; - args[4] = locale; - return substituteTimeAgo.apply({}, args); - } - - - /************************************ - Week of Year - ************************************/ - - - // firstDayOfWeek 0 = sun, 6 = sat - // the day of the week that starts the week - // (usually sunday or monday) - // firstDayOfWeekOfYear 0 = sun, 6 = sat - // the first week is the week that contains the first - // of this day of the week - // (eg. ISO weeks use thursday (4)) - function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { - var end = firstDayOfWeekOfYear - firstDayOfWeek, - daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), - adjustedMoment; - - - if (daysToDayOfWeek > end) { - daysToDayOfWeek -= 7; - } - - if (daysToDayOfWeek < end - 7) { - daysToDayOfWeek += 7; - } - - adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); - return { - week: Math.ceil(adjustedMoment.dayOfYear() / 7), - year: adjustedMoment.year() - }; - } - - //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday - function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { - var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; - - d = d === 0 ? 7 : d; - weekday = weekday != null ? weekday : firstDayOfWeek; - daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); - dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; - - return { - year: dayOfYear > 0 ? year : year - 1, - dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear - }; - } - - /************************************ - Top Level Functions - ************************************/ - - function makeMoment(config) { - var input = config._i, - format = config._f, - res; - - config._locale = config._locale || moment.localeData(config._l); - - if (input === null || (format === undefined && input === '')) { - return moment.invalid({nullInput: true}); - } - - if (typeof input === 'string') { - config._i = input = config._locale.preparse(input); - } - - if (moment.isMoment(input)) { - return new Moment(input, true); - } else if (format) { - if (isArray(format)) { - makeDateFromStringAndArray(config); - } else { - makeDateFromStringAndFormat(config); - } - } else { - makeDateFromInput(config); - } - - res = new Moment(config); - if (res._nextDay) { - // Adding is smart enough around DST - res.add(1, 'd'); - res._nextDay = undefined; - } - - return res; - } - - moment = function (input, format, locale, strict) { - var c; - - if (typeof(locale) === 'boolean') { - strict = locale; - locale = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c = {}; - c._isAMomentObject = true; - c._i = input; - c._f = format; - c._l = locale; - c._strict = strict; - c._isUTC = false; - c._pf = defaultParsingFlags(); - - return makeMoment(c); - }; - - moment.suppressDeprecationWarnings = false; - - moment.createFromInputFallback = deprecate( - 'moment construction falls back to js Date. This is ' + - 'discouraged and will be removed in upcoming major ' + - 'release. Please refer to ' + - 'https://github.com/moment/moment/issues/1407 for more info.', - function (config) { - config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); - } - ); - - // Pick a moment m from moments so that m[fn](other) is true for all - // other. This relies on the function fn to be transitive. - // - // moments should either be an array of moment objects or an array, whose - // first element is an array of moment objects. - function pickBy(fn, moments) { - var res, i; - if (moments.length === 1 && isArray(moments[0])) { - moments = moments[0]; - } - if (!moments.length) { - return moment(); - } - res = moments[0]; - for (i = 1; i < moments.length; ++i) { - if (moments[i][fn](res)) { - res = moments[i]; - } - } - return res; - } - - moment.min = function () { - var args = [].slice.call(arguments, 0); - - return pickBy('isBefore', args); - }; - - moment.max = function () { - var args = [].slice.call(arguments, 0); - - return pickBy('isAfter', args); - }; - - // creating with utc - moment.utc = function (input, format, locale, strict) { - var c; - - if (typeof(locale) === 'boolean') { - strict = locale; - locale = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c = {}; - c._isAMomentObject = true; - c._useUTC = true; - c._isUTC = true; - c._l = locale; - c._i = input; - c._f = format; - c._strict = strict; - c._pf = defaultParsingFlags(); - - return makeMoment(c).utc(); - }; - - // creating with unix timestamp (in seconds) - moment.unix = function (input) { - return moment(input * 1000); - }; - - // duration - moment.duration = function (input, key) { - var duration = input, - // matching against regexp is expensive, do it on demand - match = null, - sign, - ret, - parseIso, - diffRes; - - if (moment.isDuration(input)) { - duration = { - ms: input._milliseconds, - d: input._days, - M: input._months - }; - } else if (typeof input === 'number') { - duration = {}; - if (key) { - duration[key] = input; - } else { - duration.milliseconds = input; - } - } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - duration = { - y: 0, - d: toInt(match[DATE]) * sign, - h: toInt(match[HOUR]) * sign, - m: toInt(match[MINUTE]) * sign, - s: toInt(match[SECOND]) * sign, - ms: toInt(match[MILLISECOND]) * sign - }; - } else if (!!(match = isoDurationRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - parseIso = function (inp) { - // We'd normally use ~~inp for this, but unfortunately it also - // converts floats to ints. - // inp may be undefined, so careful calling replace on it. - var res = inp && parseFloat(inp.replace(',', '.')); - // apply sign while we're at it - return (isNaN(res) ? 0 : res) * sign; - }; - duration = { - y: parseIso(match[2]), - M: parseIso(match[3]), - d: parseIso(match[4]), - h: parseIso(match[5]), - m: parseIso(match[6]), - s: parseIso(match[7]), - w: parseIso(match[8]) - }; - } else if (typeof duration === 'object' && - ('from' in duration || 'to' in duration)) { - diffRes = momentsDifference(moment(duration.from), moment(duration.to)); - - duration = {}; - duration.ms = diffRes.milliseconds; - duration.M = diffRes.months; - } - - ret = new Duration(duration); - - if (moment.isDuration(input) && hasOwnProp(input, '_locale')) { - ret._locale = input._locale; - } - - return ret; - }; - - // version number - moment.version = VERSION; - - // default format - moment.defaultFormat = isoFormat; - - // constant that refers to the ISO standard - moment.ISO_8601 = function () {}; - - // Plugins that add properties should also add the key here (null value), - // so we can properly clone ourselves. - moment.momentProperties = momentProperties; - - // This function will be called whenever a moment is mutated. - // It is intended to keep the offset in sync with the timezone. - moment.updateOffset = function () {}; - - // This function allows you to set a threshold for relative time strings - moment.relativeTimeThreshold = function (threshold, limit) { - if (relativeTimeThresholds[threshold] === undefined) { - return false; - } - if (limit === undefined) { - return relativeTimeThresholds[threshold]; - } - relativeTimeThresholds[threshold] = limit; - return true; - }; - - moment.lang = deprecate( - 'moment.lang is deprecated. Use moment.locale instead.', - function (key, value) { - return moment.locale(key, value); - } - ); - - // This function will load locale and then set the global locale. If - // no arguments are passed in, it will simply return the current global - // locale key. - moment.locale = function (key, values) { - var data; - if (key) { - if (typeof(values) !== 'undefined') { - data = moment.defineLocale(key, values); - } - else { - data = moment.localeData(key); - } - - if (data) { - moment.duration._locale = moment._locale = data; - } - } - - return moment._locale._abbr; - }; - - moment.defineLocale = function (name, values) { - if (values !== null) { - values.abbr = name; - if (!locales[name]) { - locales[name] = new Locale(); - } - locales[name].set(values); - - // backwards compat for now: also set the locale - moment.locale(name); - - return locales[name]; - } else { - // useful for testing - delete locales[name]; - return null; - } - }; - - moment.langData = deprecate( - 'moment.langData is deprecated. Use moment.localeData instead.', - function (key) { - return moment.localeData(key); - } - ); - - // returns locale data - moment.localeData = function (key) { - var locale; - - if (key && key._locale && key._locale._abbr) { - key = key._locale._abbr; - } - - if (!key) { - return moment._locale; - } - - if (!isArray(key)) { - //short-circuit everything else - locale = loadLocale(key); - if (locale) { - return locale; - } - key = [key]; - } - - return chooseLocale(key); - }; - - // compare moment object - moment.isMoment = function (obj) { - return obj instanceof Moment || - (obj != null && hasOwnProp(obj, '_isAMomentObject')); - }; - - // for typechecking Duration objects - moment.isDuration = function (obj) { - return obj instanceof Duration; - }; - - for (i = lists.length - 1; i >= 0; --i) { - makeList(lists[i]); - } - - moment.normalizeUnits = function (units) { - return normalizeUnits(units); - }; - - moment.invalid = function (flags) { - var m = moment.utc(NaN); - if (flags != null) { - extend(m._pf, flags); - } - else { - m._pf.userInvalidated = true; - } - - return m; - }; - - moment.parseZone = function () { - return moment.apply(null, arguments).parseZone(); - }; - - moment.parseTwoDigitYear = function (input) { - return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); - }; - - /************************************ - Moment Prototype - ************************************/ - - - extend(moment.fn = Moment.prototype, { - - clone : function () { - return moment(this); - }, - - valueOf : function () { - return +this._d + ((this._offset || 0) * 60000); - }, - - unix : function () { - return Math.floor(+this / 1000); - }, - - toString : function () { - return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); - }, - - toDate : function () { - return this._offset ? new Date(+this) : this._d; - }, - - toISOString : function () { - var m = moment(this).utc(); - if (0 < m.year() && m.year() <= 9999) { - if ('function' === typeof Date.prototype.toISOString) { - // native implementation is ~50x faster, use it when we can - return this.toDate().toISOString(); - } else { - return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } - } else { - return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } - }, - - toArray : function () { - var m = this; - return [ - m.year(), - m.month(), - m.date(), - m.hours(), - m.minutes(), - m.seconds(), - m.milliseconds() - ]; - }, - - isValid : function () { - return isValid(this); - }, - - isDSTShifted : function () { - if (this._a) { - return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; - } - - return false; - }, - - parsingFlags : function () { - return extend({}, this._pf); - }, - - invalidAt: function () { - return this._pf.overflow; - }, - - utc : function (keepLocalTime) { - return this.zone(0, keepLocalTime); - }, - - local : function (keepLocalTime) { - if (this._isUTC) { - this.zone(0, keepLocalTime); - this._isUTC = false; - - if (keepLocalTime) { - this.add(this._dateTzOffset(), 'm'); - } - } - return this; - }, - - format : function (inputString) { - var output = formatMoment(this, inputString || moment.defaultFormat); - return this.localeData().postformat(output); - }, - - add : createAdder(1, 'add'), - - subtract : createAdder(-1, 'subtract'), - - diff : function (input, units, asFloat) { - var that = makeAs(input, this), - zoneDiff = (this.zone() - that.zone()) * 6e4, - diff, output, daysAdjust; - - units = normalizeUnits(units); - - if (units === 'year' || units === 'month') { - // average number of days in the months in the given dates - diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 - // difference in months - output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); - // adjust by taking difference in days, average number of days - // and dst in the given months. - daysAdjust = (this - moment(this).startOf('month')) - - (that - moment(that).startOf('month')); - // same as above but with zones, to negate all dst - daysAdjust -= ((this.zone() - moment(this).startOf('month').zone()) - - (that.zone() - moment(that).startOf('month').zone())) * 6e4; - output += daysAdjust / diff; - if (units === 'year') { - output = output / 12; - } - } else { - diff = (this - that); - output = units === 'second' ? diff / 1e3 : // 1000 - units === 'minute' ? diff / 6e4 : // 1000 * 60 - units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 - units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst - units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst - diff; - } - return asFloat ? output : absRound(output); - }, - - from : function (time, withoutSuffix) { - return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); - }, - - fromNow : function (withoutSuffix) { - return this.from(moment(), withoutSuffix); - }, - - calendar : function (time) { - // We want to compare the start of today, vs this. - // Getting start-of-today depends on whether we're zone'd or not. - var now = time || moment(), - sod = makeAs(now, this).startOf('day'), - diff = this.diff(sod, 'days', true), - format = diff < -6 ? 'sameElse' : - diff < -1 ? 'lastWeek' : - diff < 0 ? 'lastDay' : - diff < 1 ? 'sameDay' : - diff < 2 ? 'nextDay' : - diff < 7 ? 'nextWeek' : 'sameElse'; - return this.format(this.localeData().calendar(format, this, moment(now))); - }, - - isLeapYear : function () { - return isLeapYear(this.year()); - }, - - isDST : function () { - return (this.zone() < this.clone().month(0).zone() || - this.zone() < this.clone().month(5).zone()); - }, - - day : function (input) { - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - if (input != null) { - input = parseWeekday(input, this.localeData()); - return this.add(input - day, 'd'); - } else { - return day; - } - }, - - month : makeAccessor('Month', true), - - startOf : function (units) { - units = normalizeUnits(units); - // the following switch intentionally omits break keywords - // to utilize falling through the cases. - switch (units) { - case 'year': - this.month(0); - /* falls through */ - case 'quarter': - case 'month': - this.date(1); - /* falls through */ - case 'week': - case 'isoWeek': - case 'day': - this.hours(0); - /* falls through */ - case 'hour': - this.minutes(0); - /* falls through */ - case 'minute': - this.seconds(0); - /* falls through */ - case 'second': - this.milliseconds(0); - /* falls through */ - } - - // weeks are a special case - if (units === 'week') { - this.weekday(0); - } else if (units === 'isoWeek') { - this.isoWeekday(1); - } - - // quarters are also special - if (units === 'quarter') { - this.month(Math.floor(this.month() / 3) * 3); - } - - return this; - }, - - endOf: function (units) { - units = normalizeUnits(units); - if (units === undefined || units === 'millisecond') { - return this; - } - return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); - }, - - isAfter: function (input, units) { - var inputMs; - units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this > +input; - } else { - inputMs = moment.isMoment(input) ? +input : +moment(input); - return inputMs < +this.clone().startOf(units); - } - }, - - isBefore: function (input, units) { - var inputMs; - units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this < +input; - } else { - inputMs = moment.isMoment(input) ? +input : +moment(input); - return +this.clone().endOf(units) < inputMs; - } - }, - - isSame: function (input, units) { - var inputMs; - units = normalizeUnits(units || 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this === +input; - } else { - inputMs = +moment(input); - return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); - } - }, - - min: deprecate( - 'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548', - function (other) { - other = moment.apply(null, arguments); - return other < this ? this : other; - } - ), - - max: deprecate( - 'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548', - function (other) { - other = moment.apply(null, arguments); - return other > this ? this : other; - } - ), - - // keepLocalTime = true means only change the timezone, without - // affecting the local hour. So 5:31:26 +0300 --[zone(2, true)]--> - // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist int zone - // +0200, so we adjust the time as needed, to be valid. - // - // Keeping the time actually adds/subtracts (one hour) - // from the actual represented time. That is why we call updateOffset - // a second time. In case it wants us to change the offset again - // _changeInProgress == true case, then we have to adjust, because - // there is no such time in the given timezone. - zone : function (input, keepLocalTime) { - var offset = this._offset || 0, - localAdjust; - if (input != null) { - if (typeof input === 'string') { - input = timezoneMinutesFromString(input); - } - if (Math.abs(input) < 16) { - input = input * 60; - } - if (!this._isUTC && keepLocalTime) { - localAdjust = this._dateTzOffset(); - } - this._offset = input; - this._isUTC = true; - if (localAdjust != null) { - this.subtract(localAdjust, 'm'); - } - if (offset !== input) { - if (!keepLocalTime || this._changeInProgress) { - addOrSubtractDurationFromMoment(this, - moment.duration(offset - input, 'm'), 1, false); - } else if (!this._changeInProgress) { - this._changeInProgress = true; - moment.updateOffset(this, true); - this._changeInProgress = null; - } - } - } else { - return this._isUTC ? offset : this._dateTzOffset(); - } - return this; - }, - - zoneAbbr : function () { - return this._isUTC ? 'UTC' : ''; - }, - - zoneName : function () { - return this._isUTC ? 'Coordinated Universal Time' : ''; - }, - - parseZone : function () { - if (this._tzm) { - this.zone(this._tzm); - } else if (typeof this._i === 'string') { - this.zone(this._i); - } - return this; - }, - - hasAlignedHourOffset : function (input) { - if (!input) { - input = 0; - } - else { - input = moment(input).zone(); - } - - return (this.zone() - input) % 60 === 0; - }, - - daysInMonth : function () { - return daysInMonth(this.year(), this.month()); - }, - - dayOfYear : function (input) { - var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; - return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); - }, - - quarter : function (input) { - return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); - }, - - weekYear : function (input) { - var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; - return input == null ? year : this.add((input - year), 'y'); - }, - - isoWeekYear : function (input) { - var year = weekOfYear(this, 1, 4).year; - return input == null ? year : this.add((input - year), 'y'); - }, - - week : function (input) { - var week = this.localeData().week(this); - return input == null ? week : this.add((input - week) * 7, 'd'); - }, - - isoWeek : function (input) { - var week = weekOfYear(this, 1, 4).week; - return input == null ? week : this.add((input - week) * 7, 'd'); - }, - - weekday : function (input) { - var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; - return input == null ? weekday : this.add(input - weekday, 'd'); - }, - - isoWeekday : function (input) { - // behaves the same as moment#day except - // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) - // as a setter, sunday should belong to the previous week. - return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); - }, - - isoWeeksInYear : function () { - return weeksInYear(this.year(), 1, 4); - }, - - weeksInYear : function () { - var weekInfo = this.localeData()._week; - return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); - }, - - get : function (units) { - units = normalizeUnits(units); - return this[units](); - }, - - set : function (units, value) { - units = normalizeUnits(units); - if (typeof this[units] === 'function') { - this[units](value); - } - return this; - }, - - // If passed a locale key, it will set the locale for this - // instance. Otherwise, it will return the locale configuration - // variables for this instance. - locale : function (key) { - var newLocaleData; - - if (key === undefined) { - return this._locale._abbr; - } else { - newLocaleData = moment.localeData(key); - if (newLocaleData != null) { - this._locale = newLocaleData; - } - return this; - } - }, - - lang : deprecate( - 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', - function (key) { - if (key === undefined) { - return this.localeData(); - } else { - return this.locale(key); - } - } - ), - - localeData : function () { - return this._locale; - }, - - _dateTzOffset : function () { - // On Firefox.24 Date#getTimezoneOffset returns a floating point. - // https://github.com/moment/moment/pull/1871 - return Math.round(this._d.getTimezoneOffset() / 15) * 15; - } - }); - - function rawMonthSetter(mom, value) { - var dayOfMonth; - - // TODO: Move this out of here! - if (typeof value === 'string') { - value = mom.localeData().monthsParse(value); - // TODO: Another silent failure? - if (typeof value !== 'number') { - return mom; - } - } - - dayOfMonth = Math.min(mom.date(), - daysInMonth(mom.year(), value)); - mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); - return mom; - } - - function rawGetter(mom, unit) { - return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); - } - - function rawSetter(mom, unit, value) { - if (unit === 'Month') { - return rawMonthSetter(mom, value); - } else { - return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); - } - } - - function makeAccessor(unit, keepTime) { - return function (value) { - if (value != null) { - rawSetter(this, unit, value); - moment.updateOffset(this, keepTime); - return this; - } else { - return rawGetter(this, unit); - } - }; - } - - moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false); - moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false); - moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false); - // Setting the hour should keep the time, because the user explicitly - // specified which hour he wants. So trying to maintain the same hour (in - // a new timezone) makes sense. Adding/subtracting hours does not follow - // this rule. - moment.fn.hour = moment.fn.hours = makeAccessor('Hours', true); - // moment.fn.month is defined separately - moment.fn.date = makeAccessor('Date', true); - moment.fn.dates = deprecate('dates accessor is deprecated. Use date instead.', makeAccessor('Date', true)); - moment.fn.year = makeAccessor('FullYear', true); - moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true)); - - // add plural methods - moment.fn.days = moment.fn.day; - moment.fn.months = moment.fn.month; - moment.fn.weeks = moment.fn.week; - moment.fn.isoWeeks = moment.fn.isoWeek; - moment.fn.quarters = moment.fn.quarter; - - // add aliased format methods - moment.fn.toJSON = moment.fn.toISOString; - - /************************************ - Duration Prototype - ************************************/ - - - function daysToYears (days) { - // 400 years have 146097 days (taking into account leap year rules) - return days * 400 / 146097; - } - - function yearsToDays (years) { - // years * 365 + absRound(years / 4) - - // absRound(years / 100) + absRound(years / 400); - return years * 146097 / 400; - } - - extend(moment.duration.fn = Duration.prototype, { - - _bubble : function () { - var milliseconds = this._milliseconds, - days = this._days, - months = this._months, - data = this._data, - seconds, minutes, hours, years = 0; - - // The following code bubbles up values, see the tests for - // examples of what that means. - data.milliseconds = milliseconds % 1000; - - seconds = absRound(milliseconds / 1000); - data.seconds = seconds % 60; - - minutes = absRound(seconds / 60); - data.minutes = minutes % 60; - - hours = absRound(minutes / 60); - data.hours = hours % 24; - - days += absRound(hours / 24); - - // Accurately convert days to years, assume start from year 0. - years = absRound(daysToYears(days)); - days -= absRound(yearsToDays(years)); - - // 30 days to a month - // TODO (iskren): Use anchor date (like 1st Jan) to compute this. - months += absRound(days / 30); - days %= 30; - - // 12 months -> 1 year - years += absRound(months / 12); - months %= 12; - - data.days = days; - data.months = months; - data.years = years; - }, - - abs : function () { - this._milliseconds = Math.abs(this._milliseconds); - this._days = Math.abs(this._days); - this._months = Math.abs(this._months); - - this._data.milliseconds = Math.abs(this._data.milliseconds); - this._data.seconds = Math.abs(this._data.seconds); - this._data.minutes = Math.abs(this._data.minutes); - this._data.hours = Math.abs(this._data.hours); - this._data.months = Math.abs(this._data.months); - this._data.years = Math.abs(this._data.years); - - return this; - }, - - weeks : function () { - return absRound(this.days() / 7); - }, - - valueOf : function () { - return this._milliseconds + - this._days * 864e5 + - (this._months % 12) * 2592e6 + - toInt(this._months / 12) * 31536e6; - }, - - humanize : function (withSuffix) { - var output = relativeTime(this, !withSuffix, this.localeData()); - - if (withSuffix) { - output = this.localeData().pastFuture(+this, output); - } - - return this.localeData().postformat(output); - }, - - add : function (input, val) { - // supports only 2.0-style add(1, 's') or add(moment) - var dur = moment.duration(input, val); - - this._milliseconds += dur._milliseconds; - this._days += dur._days; - this._months += dur._months; - - this._bubble(); - - return this; - }, - - subtract : function (input, val) { - var dur = moment.duration(input, val); - - this._milliseconds -= dur._milliseconds; - this._days -= dur._days; - this._months -= dur._months; - - this._bubble(); - - return this; - }, - - get : function (units) { - units = normalizeUnits(units); - return this[units.toLowerCase() + 's'](); - }, - - as : function (units) { - var days, months; - units = normalizeUnits(units); - - if (units === 'month' || units === 'year') { - days = this._days + this._milliseconds / 864e5; - months = this._months + daysToYears(days) * 12; - return units === 'month' ? months : months / 12; - } else { - // handle milliseconds separately because of floating point math errors (issue #1867) - days = this._days + Math.round(yearsToDays(this._months / 12)); - switch (units) { - case 'week': return days / 7 + this._milliseconds / 6048e5; - case 'day': return days + this._milliseconds / 864e5; - case 'hour': return days * 24 + this._milliseconds / 36e5; - case 'minute': return days * 24 * 60 + this._milliseconds / 6e4; - case 'second': return days * 24 * 60 * 60 + this._milliseconds / 1000; - // Math.floor prevents floating point math errors here - case 'millisecond': return Math.floor(days * 24 * 60 * 60 * 1000) + this._milliseconds; - default: throw new Error('Unknown unit ' + units); - } - } - }, - - lang : moment.fn.lang, - locale : moment.fn.locale, - - toIsoString : deprecate( - 'toIsoString() is deprecated. Please use toISOString() instead ' + - '(notice the capitals)', - function () { - return this.toISOString(); - } - ), - - toISOString : function () { - // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js - var years = Math.abs(this.years()), - months = Math.abs(this.months()), - days = Math.abs(this.days()), - hours = Math.abs(this.hours()), - minutes = Math.abs(this.minutes()), - seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); - - if (!this.asSeconds()) { - // this is the same as C#'s (Noda) and python (isodate)... - // but not other JS (goog.date) - return 'P0D'; - } - - return (this.asSeconds() < 0 ? '-' : '') + - 'P' + - (years ? years + 'Y' : '') + - (months ? months + 'M' : '') + - (days ? days + 'D' : '') + - ((hours || minutes || seconds) ? 'T' : '') + - (hours ? hours + 'H' : '') + - (minutes ? minutes + 'M' : '') + - (seconds ? seconds + 'S' : ''); - }, - - localeData : function () { - return this._locale; - } - }); - - moment.duration.fn.toString = moment.duration.fn.toISOString; - - function makeDurationGetter(name) { - moment.duration.fn[name] = function () { - return this._data[name]; - }; - } - - for (i in unitMillisecondFactors) { - if (hasOwnProp(unitMillisecondFactors, i)) { - makeDurationGetter(i.toLowerCase()); - } - } - - moment.duration.fn.asMilliseconds = function () { - return this.as('ms'); - }; - moment.duration.fn.asSeconds = function () { - return this.as('s'); - }; - moment.duration.fn.asMinutes = function () { - return this.as('m'); - }; - moment.duration.fn.asHours = function () { - return this.as('h'); - }; - moment.duration.fn.asDays = function () { - return this.as('d'); - }; - moment.duration.fn.asWeeks = function () { - return this.as('weeks'); - }; - moment.duration.fn.asMonths = function () { - return this.as('M'); - }; - moment.duration.fn.asYears = function () { - return this.as('y'); - }; - - /************************************ - Default Locale - ************************************/ - - - // Set default locale, other locale will inherit from English. - moment.locale('en', { - ordinalParse: /\d{1,2}(th|st|nd|rd)/, - ordinal : function (number) { - var b = number % 10, - output = (toInt(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); - - /* EMBED_LOCALES */ - - /************************************ - Exposing Moment - ************************************/ - - function makeGlobal(shouldDeprecate) { - /*global ender:false */ - if (typeof ender !== 'undefined') { - return; - } - oldGlobalMoment = globalScope.moment; - if (shouldDeprecate) { - globalScope.moment = deprecate( - 'Accessing Moment through the global scope is ' + - 'deprecated, and will be removed in an upcoming ' + - 'release.', - moment); - } else { - globalScope.moment = moment; - } - } - - // CommonJS module is defined - if (hasModule) { - module.exports = moment; - } else if (typeof define === 'function' && define.amd) { - define('moment', function (require, exports, module) { - if (module.config && module.config() && module.config().noGlobal === true) { - // release the global variable - globalScope.moment = oldGlobalMoment; - } - - return moment; - }); - makeGlobal(true); - } else { - makeGlobal(); - } -}).call(this); diff --git a/src/Bundle/ChillMainBundle/Resources/public/js/pikaday/pikaday.js b/src/Bundle/ChillMainBundle/Resources/public/js/pikaday/pikaday.js deleted file mode 100644 index 4d74cebfa..000000000 --- a/src/Bundle/ChillMainBundle/Resources/public/js/pikaday/pikaday.js +++ /dev/null @@ -1,920 +0,0 @@ -/*! - * Pikaday - * - * Copyright © 2014 David Bushell | BSD & MIT license | https://github.com/dbushell/Pikaday - */ - -(function (root, factory) -{ - 'use strict'; - - var moment; - if (typeof exports === 'object') { - // CommonJS module - // Load moment.js as an optional dependency - try { moment = require('moment'); } catch (e) {} - module.exports = factory(moment); - } else if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - define(function (req) - { - // Load moment.js as an optional dependency - var id = 'moment'; - moment = req.defined && req.defined(id) ? req(id) : undefined; - return factory(moment); - }); - } else { - root.Pikaday = factory(root.moment); - } -}(this, function (moment) -{ - 'use strict'; - - /** - * feature detection and helper functions - */ - var hasMoment = typeof moment === 'function', - - hasEventListeners = !!window.addEventListener, - - document = window.document, - - sto = window.setTimeout, - - addEvent = function(el, e, callback, capture) - { - if (hasEventListeners) { - el.addEventListener(e, callback, !!capture); - } else { - el.attachEvent('on' + e, callback); - } - }, - - removeEvent = function(el, e, callback, capture) - { - if (hasEventListeners) { - el.removeEventListener(e, callback, !!capture); - } else { - el.detachEvent('on' + e, callback); - } - }, - - fireEvent = function(el, eventName, data) - { - var ev; - - if (document.createEvent) { - ev = document.createEvent('HTMLEvents'); - ev.initEvent(eventName, true, false); - ev = extend(ev, data); - el.dispatchEvent(ev); - } else if (document.createEventObject) { - ev = document.createEventObject(); - ev = extend(ev, data); - el.fireEvent('on' + eventName, ev); - } - }, - - trim = function(str) - { - return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g,''); - }, - - hasClass = function(el, cn) - { - return (' ' + el.className + ' ').indexOf(' ' + cn + ' ') !== -1; - }, - - addClass = function(el, cn) - { - if (!hasClass(el, cn)) { - el.className = (el.className === '') ? cn : el.className + ' ' + cn; - } - }, - - removeClass = function(el, cn) - { - el.className = trim((' ' + el.className + ' ').replace(' ' + cn + ' ', ' ')); - }, - - isArray = function(obj) - { - return (/Array/).test(Object.prototype.toString.call(obj)); - }, - - isDate = function(obj) - { - return (/Date/).test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime()); - }, - - isLeapYear = function(year) - { - // solution by Matti Virkkunen: http://stackoverflow.com/a/4881951 - return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0; - }, - - getDaysInMonth = function(year, month) - { - return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; - }, - - setToStartOfDay = function(date) - { - if (isDate(date)) date.setHours(0,0,0,0); - }, - - compareDates = function(a,b) - { - // weak date comparison (use setToStartOfDay(date) to ensure correct result) - return a.getTime() === b.getTime(); - }, - - extend = function(to, from, overwrite) - { - var prop, hasProp; - for (prop in from) { - hasProp = to[prop] !== undefined; - if (hasProp && typeof from[prop] === 'object' && from[prop].nodeName === undefined) { - if (isDate(from[prop])) { - if (overwrite) { - to[prop] = new Date(from[prop].getTime()); - } - } - else if (isArray(from[prop])) { - if (overwrite) { - to[prop] = from[prop].slice(0); - } - } else { - to[prop] = extend({}, from[prop], overwrite); - } - } else if (overwrite || !hasProp) { - to[prop] = from[prop]; - } - } - return to; - }, - - - /** - * defaults and localisation - */ - defaults = { - - // bind the picker to a form field - field: null, - - // automatically show/hide the picker on `field` focus (default `true` if `field` is set) - bound: undefined, - - // position of the datepicker, relative to the field (default to bottom & left) - // ('bottom' & 'left' keywords are not used, 'top' & 'right' are modifier on the bottom/left position) - position: 'bottom left', - - // the default output format for `.toString()` and `field` value - format: 'YYYY-MM-DD', - - // the initial date to view when first opened - defaultDate: null, - - // make the `defaultDate` the initial selected value - setDefaultDate: false, - - // first day of week (0: Sunday, 1: Monday etc) - firstDay: 0, - - // the minimum/earliest date that can be selected - minDate: null, - // the maximum/latest date that can be selected - maxDate: null, - - // number of years either side, or array of upper/lower range - yearRange: 10, - - // used internally (don't config outside) - minYear: 0, - maxYear: 9999, - minMonth: undefined, - maxMonth: undefined, - - isRTL: false, - - // Additional text to append to the year in the calendar title - yearSuffix: '', - - // Render the month after year in the calendar title - showMonthAfterYear: false, - - // how many months are visible (not implemented yet) - numberOfMonths: 1, - - // internationalization - i18n: { - previousMonth : 'Previous Month', - nextMonth : 'Next Month', - months : ['January','February','March','April','May','June','July','August','September','October','November','December'], - weekdays : ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'], - weekdaysShort : ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'] - }, - - // callback function - onSelect: null, - onOpen: null, - onClose: null, - onDraw: null - }, - - - /** - * templating functions to abstract HTML rendering - */ - renderDayName = function(opts, day, abbr) - { - day += opts.firstDay; - while (day >= 7) { - day -= 7; - } - return abbr ? opts.i18n.weekdaysShort[day] : opts.i18n.weekdays[day]; - }, - - renderDay = function(i, isSelected, isToday, isDisabled, isEmpty) - { - if (isEmpty) { - return ''; - } - var arr = []; - if (isDisabled) { - arr.push('is-disabled'); - } - if (isToday) { - arr.push('is-today'); - } - if (isSelected) { - arr.push('is-selected'); - } - return '' + ''; - }, - - renderRow = function(days, isRTL) - { - return '' + (isRTL ? days.reverse() : days).join('') + ''; - }, - - renderBody = function(rows) - { - return '' + rows.join('') + ''; - }, - - renderHead = function(opts) - { - var i, arr = []; - for (i = 0; i < 7; i++) { - arr.push('' + renderDayName(opts, i, true) + ''); - } - return '' + (opts.isRTL ? arr.reverse() : arr).join('') + ''; - }, - - renderTitle = function(instance) - { - var i, j, arr, - opts = instance._o, - month = instance._m, - year = instance._y, - isMinYear = year === opts.minYear, - isMaxYear = year === opts.maxYear, - html = '
    ', - monthHtml, - yearHtml, - prev = true, - next = true; - - for (arr = [], i = 0; i < 12; i++) { - arr.push(''); - } - monthHtml = '
    ' + opts.i18n.months[month] + '
    '; - - if (isArray(opts.yearRange)) { - i = opts.yearRange[0]; - j = opts.yearRange[1] + 1; - } else { - i = year - opts.yearRange; - j = 1 + year + opts.yearRange; - } - - for (arr = []; i < j && i <= opts.maxYear; i++) { - if (i >= opts.minYear) { - arr.push(''); - } - } - yearHtml = '
    ' + year + opts.yearSuffix + '
    '; - - if (opts.showMonthAfterYear) { - html += yearHtml + monthHtml; - } else { - html += monthHtml + yearHtml; - } - - if (isMinYear && (month === 0 || opts.minMonth >= month)) { - prev = false; - } - - if (isMaxYear && (month === 11 || opts.maxMonth <= month)) { - next = false; - } - - html += ''; - html += ''; - - return html += '
    '; - }, - - renderTable = function(opts, data) - { - return '' + renderHead(opts) + renderBody(data) + '
    '; - }, - - - /** - * Pikaday constructor - */ - Pikaday = function(options) - { - var self = this, - opts = self.config(options); - - self._onMouseDown = function(e) - { - if (!self._v) { - return; - } - e = e || window.event; - var target = e.target || e.srcElement; - if (!target) { - return; - } - - if (!hasClass(target, 'is-disabled')) { - if (hasClass(target, 'pika-button') && !hasClass(target, 'is-empty')) { - self.setDate(new Date(self._y, self._m, parseInt(target.innerHTML, 10))); - if (opts.bound) { - sto(function() { - self.hide(); - }, 100); - } - return; - } - else if (hasClass(target, 'pika-prev')) { - self.prevMonth(); - } - else if (hasClass(target, 'pika-next')) { - self.nextMonth(); - } - } - if (!hasClass(target, 'pika-select')) { - if (e.preventDefault) { - e.preventDefault(); - } else { - e.returnValue = false; - return false; - } - } else { - self._c = true; - } - }; - - self._onChange = function(e) - { - e = e || window.event; - var target = e.target || e.srcElement; - if (!target) { - return; - } - if (hasClass(target, 'pika-select-month')) { - self.gotoMonth(target.value); - } - else if (hasClass(target, 'pika-select-year')) { - self.gotoYear(target.value); - } - }; - - self._onInputChange = function(e) - { - var date; - - if (e.firedBy === self) { - return; - } - if (hasMoment) { - date = moment(opts.field.value, opts.format); - date = (date && date.isValid()) ? date.toDate() : null; - } - else { - date = new Date(Date.parse(opts.field.value)); - } - self.setDate(isDate(date) ? date : null); - if (!self._v) { - self.show(); - } - }; - - self._onInputFocus = function() - { - self.show(); - }; - - self._onInputClick = function() - { - self.show(); - }; - - self._onInputBlur = function() - { - if (!self._c) { - self._b = sto(function() { - self.hide(); - }, 50); - } - self._c = false; - }; - - self._onClick = function(e) - { - e = e || window.event; - var target = e.target || e.srcElement, - pEl = target; - if (!target) { - return; - } - if (!hasEventListeners && hasClass(target, 'pika-select')) { - if (!target.onchange) { - target.setAttribute('onchange', 'return;'); - addEvent(target, 'change', self._onChange); - } - } - do { - if (hasClass(pEl, 'pika-single')) { - return; - } - } - while ((pEl = pEl.parentNode)); - if (self._v && target !== opts.trigger) { - self.hide(); - } - }; - - self.el = document.createElement('div'); - self.el.className = 'pika-single' + (opts.isRTL ? ' is-rtl' : ''); - - addEvent(self.el, 'mousedown', self._onMouseDown, true); - addEvent(self.el, 'change', self._onChange); - - if (opts.field) { - if (opts.bound) { - document.body.appendChild(self.el); - } else { - opts.field.parentNode.insertBefore(self.el, opts.field.nextSibling); - } - addEvent(opts.field, 'change', self._onInputChange); - - if (!opts.defaultDate) { - if (hasMoment && opts.field.value) { - opts.defaultDate = moment(opts.field.value, opts.format).toDate(); - } else { - opts.defaultDate = new Date(Date.parse(opts.field.value)); - } - opts.setDefaultDate = true; - } - } - - var defDate = opts.defaultDate; - - if (isDate(defDate)) { - if (opts.setDefaultDate) { - self.setDate(defDate, true); - } else { - self.gotoDate(defDate); - } - } else { - self.gotoDate(new Date()); - } - - if (opts.bound) { - this.hide(); - self.el.className += ' is-bound'; - addEvent(opts.trigger, 'click', self._onInputClick); - addEvent(opts.trigger, 'focus', self._onInputFocus); - addEvent(opts.trigger, 'blur', self._onInputBlur); - } else { - this.show(); - } - - }; - - - /** - * public Pikaday API - */ - Pikaday.prototype = { - - - /** - * configure functionality - */ - config: function(options) - { - if (!this._o) { - this._o = extend({}, defaults, true); - } - - var opts = extend(this._o, options, true); - - opts.isRTL = !!opts.isRTL; - - opts.field = (opts.field && opts.field.nodeName) ? opts.field : null; - - opts.bound = !!(opts.bound !== undefined ? opts.field && opts.bound : opts.field); - - opts.trigger = (opts.trigger && opts.trigger.nodeName) ? opts.trigger : opts.field; - - var nom = parseInt(opts.numberOfMonths, 10) || 1; - opts.numberOfMonths = nom > 4 ? 4 : nom; - - if (!isDate(opts.minDate)) { - opts.minDate = false; - } - if (!isDate(opts.maxDate)) { - opts.maxDate = false; - } - if ((opts.minDate && opts.maxDate) && opts.maxDate < opts.minDate) { - opts.maxDate = opts.minDate = false; - } - if (opts.minDate) { - setToStartOfDay(opts.minDate); - opts.minYear = opts.minDate.getFullYear(); - opts.minMonth = opts.minDate.getMonth(); - } - if (opts.maxDate) { - setToStartOfDay(opts.maxDate); - opts.maxYear = opts.maxDate.getFullYear(); - opts.maxMonth = opts.maxDate.getMonth(); - } - - if (isArray(opts.yearRange)) { - var fallback = new Date().getFullYear() - 10; - opts.yearRange[0] = parseInt(opts.yearRange[0], 10) || fallback; - opts.yearRange[1] = parseInt(opts.yearRange[1], 10) || fallback; - } else { - opts.yearRange = Math.abs(parseInt(opts.yearRange, 10)) || defaults.yearRange; - if (opts.yearRange > 100) { - opts.yearRange = 100; - } - } - - return opts; - }, - - /** - * return a formatted string of the current selection (using Moment.js if available) - */ - toString: function(format) - { - return !isDate(this._d) ? '' : hasMoment ? moment(this._d).format(format || this._o.format) : this._d.toDateString(); - }, - - /** - * return a Moment.js object of the current selection (if available) - */ - getMoment: function() - { - return hasMoment ? moment(this._d) : null; - }, - - /** - * set the current selection from a Moment.js object (if available) - */ - setMoment: function(date, preventOnSelect) - { - if (hasMoment && moment.isMoment(date)) { - this.setDate(date.toDate(), preventOnSelect); - } - }, - - /** - * return a Date object of the current selection - */ - getDate: function() - { - return isDate(this._d) ? new Date(this._d.getTime()) : null; - }, - - /** - * set the current selection - */ - setDate: function(date, preventOnSelect) - { - if (!date) { - this._d = null; - return this.draw(); - } - if (typeof date === 'string') { - date = new Date(Date.parse(date)); - } - if (!isDate(date)) { - return; - } - - var min = this._o.minDate, - max = this._o.maxDate; - - if (isDate(min) && date < min) { - date = min; - } else if (isDate(max) && date > max) { - date = max; - } - - this._d = new Date(date.getTime()); - setToStartOfDay(this._d); - this.gotoDate(this._d); - - if (this._o.field) { - this._o.field.value = this.toString(); - fireEvent(this._o.field, 'change', { firedBy: this }); - } - if (!preventOnSelect && typeof this._o.onSelect === 'function') { - this._o.onSelect.call(this, this.getDate()); - } - }, - - /** - * change view to a specific date - */ - gotoDate: function(date) - { - if (!isDate(date)) { - return; - } - this._y = date.getFullYear(); - this._m = date.getMonth(); - this.draw(); - }, - - gotoToday: function() - { - this.gotoDate(new Date()); - }, - - /** - * change view to a specific month (zero-index, e.g. 0: January) - */ - gotoMonth: function(month) - { - if (!isNaN( (month = parseInt(month, 10)) )) { - this._m = month < 0 ? 0 : month > 11 ? 11 : month; - this.draw(); - } - }, - - nextMonth: function() - { - if (++this._m > 11) { - this._m = 0; - this._y++; - } - this.draw(); - }, - - prevMonth: function() - { - if (--this._m < 0) { - this._m = 11; - this._y--; - } - this.draw(); - }, - - /** - * change view to a specific full year (e.g. "2012") - */ - gotoYear: function(year) - { - if (!isNaN(year)) { - this._y = parseInt(year, 10); - this.draw(); - } - }, - - /** - * change the minDate - */ - setMinDate: function(value) - { - this._o.minDate = value; - }, - - /** - * change the maxDate - */ - setMaxDate: function(value) - { - this._o.maxDate = value; - }, - - /** - * refresh the HTML - */ - draw: function(force) - { - if (!this._v && !force) { - return; - } - var opts = this._o, - minYear = opts.minYear, - maxYear = opts.maxYear, - minMonth = opts.minMonth, - maxMonth = opts.maxMonth; - - if (this._y <= minYear) { - this._y = minYear; - if (!isNaN(minMonth) && this._m < minMonth) { - this._m = minMonth; - } - } - if (this._y >= maxYear) { - this._y = maxYear; - if (!isNaN(maxMonth) && this._m > maxMonth) { - this._m = maxMonth; - } - } - - this.el.innerHTML = renderTitle(this) + this.render(this._y, this._m); - - if (opts.bound) { - this.adjustPosition(); - if(opts.field.type !== 'hidden') { - sto(function() { - opts.trigger.focus(); - }, 1); - } - } - - if (typeof this._o.onDraw === 'function') { - var self = this; - sto(function() { - self._o.onDraw.call(self); - }, 0); - } - }, - - adjustPosition: function() - { - var field = this._o.trigger, pEl = field, - width = this.el.offsetWidth, height = this.el.offsetHeight, - viewportWidth = window.innerWidth || document.documentElement.clientWidth, - viewportHeight = window.innerHeight || document.documentElement.clientHeight, - scrollTop = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop, - left, top, clientRect; - - if (typeof field.getBoundingClientRect === 'function') { - clientRect = field.getBoundingClientRect(); - left = clientRect.left + window.pageXOffset; - top = clientRect.bottom + window.pageYOffset; - } else { - left = pEl.offsetLeft; - top = pEl.offsetTop + pEl.offsetHeight; - while((pEl = pEl.offsetParent)) { - left += pEl.offsetLeft; - top += pEl.offsetTop; - } - } - - // default position is bottom & left - if (left + width > viewportWidth || - ( - this._o.position.indexOf('right') > -1 && - left - width + field.offsetWidth > 0 - ) - ) { - left = left - width + field.offsetWidth; - } - if (top + height > viewportHeight + scrollTop || - ( - this._o.position.indexOf('top') > -1 && - top - height - field.offsetHeight > 0 - ) - ) { - top = top - height - field.offsetHeight; - } - this.el.style.cssText = [ - 'position: absolute', - 'left: ' + left + 'px', - 'top: ' + top + 'px' - ].join(';'); - }, - - /** - * render HTML for a particular month - */ - render: function(year, month) - { - var opts = this._o, - now = new Date(), - days = getDaysInMonth(year, month), - before = new Date(year, month, 1).getDay(), - data = [], - row = []; - setToStartOfDay(now); - if (opts.firstDay > 0) { - before -= opts.firstDay; - if (before < 0) { - before += 7; - } - } - var cells = days + before, - after = cells; - while(after > 7) { - after -= 7; - } - cells += 7 - after; - for (var i = 0, r = 0; i < cells; i++) - { - var day = new Date(year, month, 1 + (i - before)), - isDisabled = (opts.minDate && day < opts.minDate) || (opts.maxDate && day > opts.maxDate), - isSelected = isDate(this._d) ? compareDates(day, this._d) : false, - isToday = compareDates(day, now), - isEmpty = i < before || i >= (days + before); - - row.push(renderDay(1 + (i - before), isSelected, isToday, isDisabled, isEmpty)); - - if (++r === 7) { - data.push(renderRow(row, opts.isRTL)); - row = []; - r = 0; - } - } - return renderTable(opts, data); - }, - - isVisible: function() - { - return this._v; - }, - - show: function() - { - if (!this._v) { - if (this._o.bound) { - addEvent(document, 'click', this._onClick); - } - removeClass(this.el, 'is-hidden'); - this._v = true; - this.draw(); - if (typeof this._o.onOpen === 'function') { - this._o.onOpen.call(this); - } - } - }, - - hide: function() - { - var v = this._v; - if (v !== false) { - if (this._o.bound) { - removeEvent(document, 'click', this._onClick); - } - this.el.style.cssText = ''; - addClass(this.el, 'is-hidden'); - this._v = false; - if (v !== undefined && typeof this._o.onClose === 'function') { - this._o.onClose.call(this); - } - } - }, - - /** - * GAME OVER - */ - destroy: function() - { - this.hide(); - removeEvent(this.el, 'mousedown', this._onMouseDown, true); - removeEvent(this.el, 'change', this._onChange); - if (this._o.field) { - removeEvent(this._o.field, 'change', this._onInputChange); - if (this._o.bound) { - removeEvent(this._o.trigger, 'click', this._onInputClick); - removeEvent(this._o.trigger, 'focus', this._onInputFocus); - removeEvent(this._o.trigger, 'blur', this._onInputBlur); - } - } - if (this.el.parentNode) { - this.el.parentNode.removeChild(this.el); - } - } - - }; - - return Pikaday; - -})); diff --git a/src/Bundle/ChillMainBundle/Resources/public/js/pikaday/plugins/pikaday.jquery.js b/src/Bundle/ChillMainBundle/Resources/public/js/pikaday/plugins/pikaday.jquery.js deleted file mode 100644 index a95ddc59b..000000000 --- a/src/Bundle/ChillMainBundle/Resources/public/js/pikaday/plugins/pikaday.jquery.js +++ /dev/null @@ -1,52 +0,0 @@ -/*! - * Pikaday jQuery plugin. - * - * Copyright © 2013 David Bushell | BSD & MIT license | https://github.com/dbushell/Pikaday - */ - -(function (root, factory) -{ - 'use strict'; - - if (typeof exports === 'object') { - // CommonJS module - factory(require('jquery'), require('../pikaday')); - } else if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - define(['jquery', 'pikaday'], factory); - } else { - // Browser globals - factory(root.jQuery, root.Pikaday); - } -}(this, function ($, Pikaday) -{ - 'use strict'; - - $.fn.pikaday = function() - { - var args = arguments; - - if (!args || !args.length) { - args = [{ }]; - } - - return this.each(function() - { - var self = $(this), - plugin = self.data('pikaday'); - - if (!(plugin instanceof Pikaday)) { - if (typeof args[0] === 'object') { - var options = $.extend({}, args[0]); - options.field = self[0]; - self.data('pikaday', new Pikaday(options)); - } - } else { - if (typeof args[0] === 'string' && typeof plugin[args[0]] === 'function') { - plugin[args[0]].apply(plugin, Array.prototype.slice.call(args,1)); - } - } - }); - }; - -})); diff --git a/src/Bundle/ChillMainBundle/Resources/public/main.js b/src/Bundle/ChillMainBundle/Resources/public/main.js index fd67f55b8..41618d245 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/main.js +++ b/src/Bundle/ChillMainBundle/Resources/public/main.js @@ -5,11 +5,6 @@ const $ = require('jquery'); // create global $ and jQuery variables global.$ = global.jQuery = $; -const moment = require('moment'); -global.moment = moment; - -const pikaday = require('pikaday-jquery'); - const select2 = require('select2'); global.select2 = select2; @@ -23,7 +18,6 @@ global.chill = chill; */ require('./scss/chillmain.scss'); require('./css/chillmain.css'); -require('./css/pikaday.css'); require('./js/collection/collections.js'); diff --git a/src/Bundle/ChillMainBundle/Resources/public/modules/bootstrap/bootstrap.scss b/src/Bundle/ChillMainBundle/Resources/public/modules/bootstrap/bootstrap.scss index 8a77ac48f..6b91d1bf0 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/modules/bootstrap/bootstrap.scss +++ b/src/Bundle/ChillMainBundle/Resources/public/modules/bootstrap/bootstrap.scss @@ -17,20 +17,20 @@ // @import "bootstrap/scss/grid"; // @import "bootstrap/scss/tables"; // @import "bootstrap/scss/forms"; -// @import "bootstrap/scss/buttons"; -// @import "bootstrap/scss/transitions"; +@import "bootstrap/scss/buttons"; +@import "bootstrap/scss/transitions"; // @import "bootstrap/scss/dropdown"; // @import "bootstrap/scss/button-group"; // @import "bootstrap/scss/input-group"; // @import "bootstrap/scss/custom-forms"; -// @import "bootstrap/scss/nav"; +@import "bootstrap/scss/nav"; // @import "bootstrap/scss/navbar"; // @import "bootstrap/scss/card"; // @import "bootstrap/scss/breadcrumb"; // @import "bootstrap/scss/pagination"; @import "bootstrap/scss/badge"; // @import "bootstrap/scss/jumbotron"; -// @import "bootstrap/scss/alert"; +@import "bootstrap/scss/alert"; // @import "bootstrap/scss/progress"; // @import "bootstrap/scss/media"; // @import "bootstrap/scss/list-group"; diff --git a/src/Bundle/ChillMainBundle/Resources/public/modules/bootstrap/index.js b/src/Bundle/ChillMainBundle/Resources/public/modules/bootstrap/index.js index 075823cab..e75a810c2 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/modules/bootstrap/index.js +++ b/src/Bundle/ChillMainBundle/Resources/public/modules/bootstrap/index.js @@ -4,6 +4,8 @@ // Or compile bootstrap only enabled assets require('./bootstrap.scss'); + // You can specify which plugins you need //import { Tooltip, Toast, Popover } from 'bootstrap'; import Modal from 'bootstrap/js/dist/modal'; +import Collapse from 'bootstrap/js/src/collapse'; diff --git a/src/Bundle/ChillMainBundle/Resources/public/scss/chillmain.scss b/src/Bundle/ChillMainBundle/Resources/public/scss/chillmain.scss index f101b78ca..cedc04e10 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/scss/chillmain.scss +++ b/src/Bundle/ChillMainBundle/Resources/public/scss/chillmain.scss @@ -79,6 +79,18 @@ div.flex-table { h2, h3, h4 { color: var(--chill-blue); } + div.item-bloc { + // We use box-shadow instead of border + // to avoid to manage border double-width + // when blocs are resized for small screen ! + // Then we can simulate border-collapse: collapse (table) + box-shadow: + 1px 0 0 0 #000, + 0 1px 0 0 #000, + 1px 1px 0 0 #000, /* fix the corner */ + 1px 0 0 0 #000 inset, + 0 1px 0 0 #000 inset; + } } /* @@ -94,11 +106,8 @@ div.flex-bloc { div.item-bloc { flex-grow: 0; flex-shrink: 1; flex-basis: 50%; - margin: 0; - border: 1px solid #000; padding: 1em; - border-top: 0; &:nth-child(1), &:nth-child(2) { border-top: 1px solid #000; @@ -112,7 +121,7 @@ div.flex-bloc { display: flex; flex-direction: column; - div.item-row { + & > div.item-row { flex-grow: 1; flex-shrink: 1; flex-basis: auto; display: flex; flex-direction: column; @@ -167,11 +176,6 @@ div.flex-table { display: flex; flex-direction: column; padding: 1em; - border: 1px solid #000; - border-top: 0; - &:first-child { - border-top: 1px solid #000; - } &:nth-child(even) { background-color: #e6e6e6; } diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/OnTheFly.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/OnTheFly.vue new file mode 100644 index 000000000..8e1e2227a --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/OnTheFly.vue @@ -0,0 +1,153 @@ + + + + + diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/OnTheFly/Create.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/OnTheFly/Create.vue new file mode 100644 index 000000000..f374647ff --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/OnTheFly/Create.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/OnTheFly/ThirdParty.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/OnTheFly/ThirdParty.vue new file mode 100644 index 000000000..b8dced534 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/OnTheFly/ThirdParty.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.js b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.js index 319378d7e..d89470bc4 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.js +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.js @@ -46,7 +46,23 @@ const messages = { previous: "Précédent", top: "Haut", bottom: "Bas", - } + }, + onthefly: { + show: { + person: "Détails de l'usager", + thirdparty: "Détails du tiers" + }, + edit: { + person: "Modifier un usager", + thirdparty: "Modifier un tiers" + }, + create: { + button: "Créer \"{q}\"", + title: "Créer à la volée…", + person: "un nouvel usager", + thirdparty: "un nouveau tiers" + }, + }, } }; diff --git a/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig index e678932f0..f087578f3 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Form/fields.html.twig @@ -112,24 +112,6 @@ {% endblock money_widget %} - -{% block date_widget %} -{% apply spaceless %} - {% if widget == 'single_text' %} - {% set attr = {'class' : 'input datepicker'} %} - {{ block('form_widget_simple') }} - {% else %} -
    - {{ date_pattern|replace({ - '{{ year }}': form_widget(form.year ), - '{{ month }}': form_widget(form.month ), - '{{ day }}': form_widget(form.day ), - })|raw }} -
    - {% endif %} -{% endapply %} -{% endblock date_widget %} - {%- block time_widget -%} {%- if widget == 'single_text' -%} {{ block('form_widget_simple') }} @@ -196,4 +178,4 @@ {{ form_widget(entry) }} {% endif %} {% endfor %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/src/Bundle/ChillMainBundle/Resources/views/layout.html.twig b/src/Bundle/ChillMainBundle/Resources/views/layout.html.twig index 7c8231d4b..0381233a4 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/layout.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/layout.html.twig @@ -28,16 +28,16 @@ {{ installation.name }} - {% block title %}{% endblock %} - - + {{ encore_entry_link_tags('scratch') }} + {{ encore_entry_link_tags('chill') }} {% if active_bootstrap == 1 %} - + {{ encore_entry_link_tags('bootstrap') }} {% endif %} {% if active_forkawesome == 1 %} - + {{ encore_entry_link_tags('forkawesome') }} {% endif %} {% if active_ckeditor == 1 %} - + {{ encore_entry_link_tags('ckeditor5') }} {% endif %} {% block css%}{% endblock %} @@ -152,21 +152,18 @@ {{ include('@ChillMain/Layout/_footer.html.twig') }} - - - + {{ encore_entry_script_tags('scratch') }} + {{ encore_entry_script_tags('chill') }} {% if active_bootstrap == 1 %} - + {{ encore_entry_script_tags('bootstrap') }} {% endif %} {% if active_forkawesome == 1 %} - + {{ encore_entry_script_tags('forkawesome') }} {% endif %} {% if active_ckeditor == 1 %} - + {{ encore_entry_script_tags('ckeditor5') }} {% endif %} diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Confirmation.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Confirmation.vue new file mode 100644 index 000000000..cc97d7ef9 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Confirmation.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Dates.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Dates.vue new file mode 100644 index 000000000..be332523d --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Dates.vue @@ -0,0 +1,36 @@ + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Household.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Household.vue new file mode 100644 index 000000000..db9670d43 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Household.vue @@ -0,0 +1,80 @@ + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/MemberDetails.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/MemberDetails.vue new file mode 100644 index 000000000..7147ed9c7 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/MemberDetails.vue @@ -0,0 +1,126 @@ + + + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/index.js new file mode 100644 index 000000000..c9f5bb111 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/index.js @@ -0,0 +1,16 @@ +import { createApp } from 'vue'; +import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'; +import { appMessages } from './js/i18n'; +import { store } from './store'; + +import App from './App.vue'; + +const i18n = _createI18n(appMessages); + +const app = createApp({ + template: ``, +}) +.use(store) +.use(i18n) +.component('app', App) +.mount('#household_members_editor'); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/js/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/js/i18n.js new file mode 100644 index 000000000..116203ba1 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/js/i18n.js @@ -0,0 +1,52 @@ + +import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n' + +const appMessages = { + fr: { + household_members_editor: { + household: { + no_household_choose_one: "Aucun ménage de destination. Choisissez un ménage.", + new_household: "Nouveau ménage", + create_household: "Créer un ménage", + search_household: "Chercher un ménage", + will_leave_any_household: "Ne rejoignent pas de ménage", + leave_without_household: "Sans nouveau ménage" + }, + concerned: { + title: "Usagers concernés", + add_persons: "Ajouter d'autres usagers", + search: "Rechercher des usagers", + move_to: "Déplacer vers", + persons_to_positionnate: 'Usagers à positionner', + persons_leaving: "Usagers quittant leurs ménages", + }, + drop_persons_here: "Glissez-déposez ici les usagers pour la position \"{position}\"", + all_positionnated: "Tous les usagers sont positionnés", + holder: "Titulaire", + is_holder: "Sera titulaire", + is_not_holder: "Ne sera pas titulaire", + remove_position: "Retirer des {position}", + remove_concerned: "Ne plus transférer", + household_part: "Ménage de destination", + dates_title: "Période de validité", + dates: { + start_date: "Début de validité", + end_date: "Fin de validité", + }, + confirmation: { + save: "Enregistrer", + there_are_warnings: "Impossible de valider actuellement", + check_those_items: "Veuillez corriger les éléments suivants", + }, + give_a_position_to_every_person: "Indiquez une position pour chaque usager concerné", + add_destination: "Indiquez un ménage de destination", + add_at_least_onePerson: "Indiquez au moins un usager à transférer", + } + } +}; + +Object.assign(appMessages.fr, personMessages.fr); + +export { + appMessages +}; diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/store/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/store/index.js new file mode 100644 index 000000000..32eb5b722 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/store/index.js @@ -0,0 +1,239 @@ +import { createStore } from 'vuex'; +import { householdMove, householdMoveTest } from './../api.js'; +import { datetimeToISO } from 'ChillMainAssets/js/date.js'; + +const debug = process.env.NODE_ENV !== 'production'; + +const concerned = window.household_members_editor_data.persons.map(p => { + return { + person: p, + position: null, + allowRemove: false, + holder: false, + comment: "", + }; +}); + +const store = createStore({ + strict: debug, + state: { + concerned, + household: window.household_members_editor_data.household, + positions: window.household_members_editor_data.positions, + startDate: new Date(), + allowHouseholdCreate: window.household_members_editor_data.allowHouseholdCreate, + allowHouseholdSearch: window.household_members_editor_data.allowHouseholdSearch, + allowLeaveWithoutHousehold: window.household_members_editor_data.allowLeaveWithoutHousehold, + forceLeaveWithoutHousehold: false, + warnings: [], + }, + getters: { + isHouseholdNew(state) { + return !Number.isInteger(state.household.id); + }, + hasHousehold(state) { + return state.household !== null; + }, + persons(state) { + return state.concerned.map(conc => conc.person); + }, + concUnpositionned(state) { + return state.concerned + .filter(conc => conc.position === null) + ; + }, + positions(state) { + return state.positions; + }, + personByPosition: (state) => (position_id) => { + return state.concerned + .filter(conc => + conc.position !== null ? conc.position.id === position_id : false + ) + .map(conc => conc.person) + ; + }, + concByPosition: (state) => (position_id) => { + return state.concerned + .filter(conc => + conc.position !== null ? conc.position.id === position_id : false + ) + ; + }, + concByPersonId: (state) => (person_id) => { + return state.concerned + .find(conc => conc.person.id === person_id) + ; + }, + needsPositionning(state) { + return state.forceLeaveWithoutHousehold === false; + }, + buildPayload: (state) => { + let + conc, + payload_conc, + payload = { + concerned: [], + destination: null + } + ; + + if (state.forceLeaveWithoutHousehold === false) { + payload.destination = { + id: state.household.id, + type: state.household.type + }; + } + + for (let i in state.concerned) { + conc = state.concerned[i]; + payload_conc = { + person: { + id: conc.person.id, + type: conc.person.type + }, + start_date: { + datetime: datetimeToISO(state.startDate) + } + }; + + if (state.forceLeaveWithoutHousehold === false) { + payload_conc.position = { + id: conc.position.id, + type: conc.position.type + }; + payload_conc.holder = conc.holder; + payload_conc.comment = conc.comment; + } + + payload.concerned.push(payload_conc); + } + + return payload; + }, + }, + mutations: { + addConcerned(state, person) { + let persons = state.concerned.map(conc => conc.person.id); + if (!persons.includes(person.id)) { + state.concerned.push({ + person, + position: null, + allowRemove: true, + holder: false, + comment: "", + }); + } else { + console.err("person already included"); + } + }, + markPosition(state, { person_id, position_id}) { + let + position = state.positions.find(pos => pos.id === position_id), + conc = state.concerned.find(c => c.person.id === person_id); + conc.position = position; + }, + setComment(state, {conc, comment}) { + conc.comment = comment; + }, + toggleHolder(state, conc) { + conc.holder = !conc.holder; + }, + removePosition(state, conc) { + conc.holder = false; + conc.position = null; + }, + removeConcerned(state, conc) { + state.concerned = state.concerned.filter(c => + c.person.id !== conc.person.id + ) + }, + createHousehold(state) { + state.household = { type: 'household', members: [], address: null } + state.forceLeaveWithoutHousehold = false; + }, + forceLeaveWithoutHousehold(state) { + state.household = null; + state.forceLeaveWithoutHousehold = true; + }, + setStartDate(state, dateI) { + state.startDate = dateI; + }, + setWarnings(state, warnings) { + state.warnings = warnings; + }, + }, + actions: { + addConcerned({ commit, dispatch }, person) { + commit('addConcerned', person); + dispatch('computeWarnings'); + }, + markPosition({ commit, state, dispatch }, { person_id, position_id }) { + commit('markPosition', { person_id, position_id }); + dispatch('computeWarnings'); + }, + toggleHolder({ commit }, conc) { + commit('toggleHolder', conc); + }, + removePosition({ commit, dispatch }, conc) { + commit('removePosition', conc); + dispatch('computeWarnings'); + }, + removeConcerned({ commit, dispatch }, conc) { + commit('removeConcerned', conc); + dispatch('computeWarnings'); + }, + createHousehold({ commit, dispatch }) { + commit('createHousehold'); + dispatch('computeWarnings'); + }, + forceLeaveWithoutHousehold({ commit, dispatch }) { + commit('forceLeaveWithoutHousehold'); + dispatch('computeWarnings'); + }, + setStartDate({ commit }, date) { + commit('setStartDate', date); + }, + setComment({ commit }, payload) { + commit('setComment', payload); + }, + computeWarnings({ commit, state, getters }) { + let warnings = [], + payload; + + if (!getters.hasHousehold && !state.forceLeaveWithoutHousehold) { + warnings.push({ m: 'household_members_editor.add_destination', a: {} }); + } + + if (state.concerned.length === 0) { + warnings.push({ m: 'household_members_editor.add_at_least_onePerson', a: {} }); + } + + if (getters.concUnpositionned.length > 0 + && !state.forceLeaveWithoutHousehold) { + warnings.push({ m: 'household_members_editor.give_a_position_to_every_person', a: {} }) + } + + commit('setWarnings', warnings); + }, + confirm({ getters, state }) { + let payload = getters.buildPayload, + person_id, + household_id; + householdMove(payload).then(household => { + if (household === null) { + person_id = getters.persons[0].id; + window.location.replace(`/fr/person/${person_id}/general`); + } else { + household_id = household.id; + // nothing to do anymore here, bye-bye ! + window.location.replace(`/fr/person/household/${household_id}/members`); + } + }); + }, + } +}); + +store.dispatch('computeWarnings'); + +export { store }; diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_api/OnTheFly.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_api/OnTheFly.js new file mode 100644 index 000000000..6adbc7028 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_api/OnTheFly.js @@ -0,0 +1,34 @@ +/* +* GET a person by id +*/ +const getPerson = (id) => { + const url = `/api/1.0/person/person/${id}.json`; + return fetch(url) + .then(response => { + if (response.ok) { return response.json(); } + throw Error('Error with request resource response'); + }); +}; + +/* +* POST a new person +*/ +const postPerson = (body) => { + const url = `/api/1.0/person/person.json`; + return fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json;charset=utf-8' + }, + body: JSON.stringify(body) + }) + .then(response => { + if (response.ok) { return response.json(); } + throw Error('Error with request resource response'); + }); +}; + +export { + getPerson, + postPerson +}; diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons.vue index a37f93e7e..dac29ca72 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons.vue @@ -1,9 +1,9 @@ @@ -84,6 +89,7 @@ diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/PersonSuggestion.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/PersonSuggestion.vue index 3846f7b39..c6494e461 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/PersonSuggestion.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/PersonSuggestion.vue @@ -42,7 +42,7 @@ export default { computed: { selected: { set(value) { - console.log('value', value); + //console.log('value', value); this.$emit('updateSelected', value); }, get() { diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypePerson.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypePerson.vue index af5b13b16..eff860f91 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypePerson.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypePerson.vue @@ -14,22 +14,23 @@ {{ $t('item.type_person') }} - + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue index 37cee7852..5a4aa9de6 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue @@ -15,22 +15,23 @@ {{ $t('item.type_thirdparty') }} - + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/OnTheFly/Person.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/OnTheFly/Person.vue new file mode 100644 index 000000000..a3cf339e2 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/OnTheFly/Person.vue @@ -0,0 +1,200 @@ + + + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Person/Person.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Person/Person.vue new file mode 100644 index 000000000..274d9ee88 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/Person/Person.vue @@ -0,0 +1,16 @@ + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_js/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_js/i18n.js index e92a81e62..f83004ce8 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_js/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_js/i18n.js @@ -15,7 +15,29 @@ const personMessages = { person: { firstname: "Prénom", lastname: "Nom", - born: "né le ", + born: (ctx) => { + if (ctx.gender === 'man') { + return 'Né le'; + } else if (ctx.gender === 'woman') { + return 'Née le'; + } else { + return 'Né·e le'; + } + }, + center_id: "Identifiant du centre", + center_type: "Type de centre", + center_name: "Territoire", // vendée + phonenumber: "Téléphone", + mobilenumber: "Mobile", + altnames: "Autres noms", + gender: { + title: "Genre", + placeholder: "Choisissez le genre de l'usager", + woman: "Femme", + man: "Homme", + neuter: "Neutre", + } + }, error_only_one_person: "Une seule personne peut être sélectionnée !" } diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/edit.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/edit.html.twig index 6aa978149..65edd5155 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/edit.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/edit.html.twig @@ -15,5 +15,5 @@ window.accompanyingCourseId = {{ accompanyingCourse.id|e('js') }}; window.vueRootComponent = 'app'; - {{ encore_entry_script_tags('accompanying_course') }} + {{ encore_entry_script_tags('vue_accourse') }} {% endblock %} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/index.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/index.html.twig index 98f26987f..4fef55ceb 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/index.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/index.html.twig @@ -31,7 +31,7 @@ {% set gender = (p.person.gender == 'woman') ? 'fa-venus' : (p.person.gender == 'man') ? 'fa-mars' : 'fa-neuter' %} {% set genderTitle = (p.person.gender == 'woman') ? 'femme' : - (p.person.gender == 'homme') ? 'fa-mars' : 'neutre' %} + (p.person.gender == 'man') ? 'homme' : 'neutre' %} {{ born ~ ' le ' ~ p.person.birthdate|format_date('short') }}

    @@ -62,6 +62,19 @@
  • + {% if p.person.isSharingHousehold %} +
  • + + + {{ 'household.Household file'|trans }} + +
  • + {% endif %}
diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/layout.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/layout.html.twig index 0bab5d893..58591a618 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/layout.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/layout.html.twig @@ -16,7 +16,7 @@ {% endblock %} {% block css %} - {{ encore_entry_link_tags('accompanying_course') }} + {{ encore_entry_link_tags('vue_accourse') }} {% endblock %} {% block js %} @@ -24,5 +24,5 @@ window.accompanyingCourseId = {{ accompanyingCourse.id|e('js') }}; window.vueRootComponent = 'banner'; - {{ encore_entry_script_tags('accompanying_course') }} + {{ encore_entry_script_tags('vue_accourse') }} {% endblock %} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Entity/person.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Entity/person.html.twig index afcd2799c..24afd7bf3 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Entity/person.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Entity/person.html.twig @@ -1,15 +1,17 @@ {%- if addLink and is_granted('CHILL_PERSON_SEE', person) -%} {%- set showLink = true -%}{%- endif -%} - {{ person.firstName }} - {{ person.lastName }} + {{ person.firstName }} + {{ person.lastName }} {%- if addAltNames -%} {%- for n in person.altNames -%} {%- if loop.first -%}({% else %} {%- endif -%} - {{ n.label }} + {{- n.label -}} - {%- if loop.last %}) {% endif -%} + {%- if loop.last -%}) {%- endif -%} {%- endfor -%} {%- endif -%} - {%- if showLink is defined -%}{%- endif -%} + {%- if showLink is defined -%}{%- endif -%} +{#- tricks to remove easily whitespace after template -#} +{%- if true -%}{%- endif -%} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Entity/social_action.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Entity/social_action.html.twig new file mode 100644 index 000000000..246ddd1ea --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/views/Entity/social_action.html.twig @@ -0,0 +1,13 @@ +{% set reversed_parents = parents|reverse %} + diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Household/Member/edit.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Household/Member/edit.html.twig new file mode 100644 index 000000000..09813c2bb --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/views/Household/Member/edit.html.twig @@ -0,0 +1,28 @@ +{% extends '@ChillPerson/Household/layout.html.twig' %} + +{% block title 'household.Edit member household'|trans %} + +{% block content %} + +

{{ block('title') }}

+ +{{ form_start(form) }} +{{ form_widget(form) }} + + + +{{ form_end(form) }} + +{% endblock %} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/Household/banner.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/Household/banner.html.twig index 9ea33c8d4..795861529 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/Household/banner.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/Household/banner.html.twig @@ -1,11 +1,11 @@ -
+