commit b16ca31d71d0140d02203b8db640c57233ccf29c Author: francesco.mangiacrapa Date: Thu Sep 21 17:01:55 2023 +0200 copied from SVN diff --git a/.project b/.project new file mode 100644 index 0000000..2c4c958 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + ckanext-d4science_theme + + + + + + org.python.pydev.PyDevBuilder + + + + + + org.python.pydev.pythonNature + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..77f221a --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/setup.py=utf-8 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3ffc567 --- /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. + + + Copyright (C) + + 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 +. \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..06e4a8a --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include README.rst +recursive-include ckanext/d4science_theme *.html *.json *.js *.less *.css \ No newline at end of file diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..78b2921 --- /dev/null +++ b/README.rst @@ -0,0 +1,166 @@ +.. You should enable this project on travis-ci.org and coveralls.io to make + these badges work. The necessary Travis and Coverage config files have been + generated for you. + +.. image:: https://travis-ci.org//ckanext-d4science_theme.svg?branch=master + :target: https://travis-ci.org//ckanext-d4science_theme + +.. image:: https://coveralls.io/repos//ckanext-d4science_theme/badge.svg + :target: https://coveralls.io/r//ckanext-d4science_theme + +.. image:: https://pypip.in/download/ckanext-d4science_theme/badge.svg + :target: https://pypi.python.org/pypi//ckanext-d4science_theme/ + :alt: Downloads + +.. image:: https://pypip.in/version/ckanext-d4science_theme/badge.svg + :target: https://pypi.python.org/pypi/ckanext-d4science_theme/ + :alt: Latest Version + +.. image:: https://pypip.in/py_versions/ckanext-d4science_theme/badge.svg + :target: https://pypi.python.org/pypi/ckanext-d4science_theme/ + :alt: Supported Python versions + +.. image:: https://pypip.in/status/ckanext-d4science_theme/badge.svg + :target: https://pypi.python.org/pypi/ckanext-d4science_theme/ + :alt: Development Status + +.. image:: https://pypip.in/license/ckanext-d4science_theme/badge.svg + :target: https://pypi.python.org/pypi/ckanext-d4science_theme/ + :alt: License + +============= +ckanext-d4science_theme +============= + +.. Put a description of your extension here: + What does it do? What features does it have? + Consider including some screenshots or embedding a video! + + +------------ +Requirements +------------ + +For example, you might want to mention here which versions of CKAN this +extension works with. + + +------------ +Installation +------------ + +.. Add any additional install steps to the list below. + For example installing any non-Python dependencies or adding any required + config settings. + +To install ckanext-d4science_theme: + +1. Activate your CKAN virtual environment, for example:: + + . /usr/lib/ckan/default/bin/activate + +2. Install the ckanext-d4science_theme Python package into your virtual environment:: + + pip install ckanext-d4science_theme + +3. Add ``d4science_theme`` to the ``ckan.plugins`` setting in your CKAN + config file (by default the config file is located at + ``/etc/ckan/default/production.ini``). + +4. Restart CKAN. For example if you've deployed CKAN with Apache on Ubuntu:: + + sudo service apache2 reload + + +--------------- +Config Settings +--------------- + +Document any optional config settings here. For example:: + + # The minimum number of hours to wait before re-checking a resource + # (optional, default: 24). + ckanext.d4science_theme.some_setting = some_default_value + + +------------------------ +Development Installation +------------------------ + +To install ckanext-d4science_theme for development, activate your CKAN virtualenv and +do:: + + git clone https://github.com//ckanext-d4science_theme.git + cd ckanext-d4science_theme + python setup.py develop + pip install -r dev-requirements.txt + + +----------------- +Running the Tests +----------------- + +To run the tests, do:: + + nosetests --nologcapture --with-pylons=test.ini + +To run the tests and produce a coverage report, first make sure you have +coverage installed in your virtualenv (``pip install coverage``) then run:: + + nosetests --nologcapture --with-pylons=test.ini --with-coverage --cover-package=ckanext.d4science_theme --cover-inclusive --cover-erase --cover-tests + + +--------------------------------- +Registering ckanext-d4science_theme on PyPI +--------------------------------- + +ckanext-d4science_theme should be availabe on PyPI as +https://pypi.python.org/pypi/ckanext-d4science_theme. If that link doesn't work, then +you can register the project on PyPI for the first time by following these +steps: + +1. Create a source distribution of the project:: + + python setup.py sdist + +2. Register the project:: + + python setup.py register + +3. Upload the source distribution to PyPI:: + + python setup.py sdist upload + +4. Tag the first release of the project on GitHub with the version number from + the ``setup.py`` file. For example if the version number in ``setup.py`` is + 0.0.1 then do:: + + git tag 0.0.1 + git push --tags + + +---------------------------------------- +Releasing a New Version of ckanext-d4science_theme +---------------------------------------- + +ckanext-d4science_theme is availabe on PyPI as https://pypi.python.org/pypi/ckanext-d4science_theme. +To publish a new version to PyPI follow these steps: + +1. Update the version number in the ``setup.py`` file. + See `PEP 440 `_ + for how to choose version numbers. + +2. Create a source distribution of the new version:: + + python setup.py sdist + +3. Upload the source distribution to PyPI:: + + python setup.py sdist upload + +4. Tag the new release of the project on GitHub with the version number from + the ``setup.py`` file. For example if the version number in ``setup.py`` is + 0.0.2 then do:: + + git tag 0.0.2 + git push --tags diff --git a/bin/travis-build.bash b/bin/travis-build.bash new file mode 100644 index 0000000..5641a97 --- /dev/null +++ b/bin/travis-build.bash @@ -0,0 +1,38 @@ +#!/bin/bash +set -e + +echo "This is travis-build.bash..." + +echo "Installing the packages that CKAN requires..." +sudo apt-get update -qq +sudo apt-get install postgresql-$PGVERSION solr-jetty libcommons-fileupload-java:amd64=1.2.2-1 + +echo "Installing CKAN and its Python dependencies..." +git clone https://github.com/ckan/ckan +cd ckan +export latest_ckan_release_branch=`git branch --all | grep remotes/origin/release-v | sort -r | sed 's/remotes\/origin\///g' | head -n 1` +echo "CKAN branch: $latest_ckan_release_branch" +git checkout $latest_ckan_release_branch +python setup.py develop +pip install -r requirements.txt --allow-all-external +pip install -r dev-requirements.txt --allow-all-external +cd - + +echo "Creating the PostgreSQL user and database..." +sudo -u postgres psql -c "CREATE USER ckan_default WITH PASSWORD 'pass';" +sudo -u postgres psql -c 'CREATE DATABASE ckan_test WITH OWNER ckan_default;' + +echo "Initialising the database..." +cd ckan +paster db init -c test-core.ini +cd - + +echo "Installing ckanext-d4science_theme and its requirements..." +python setup.py develop +pip install -r dev-requirements.txt + +echo "Moving test.ini into a subdir..." +mkdir subdir +mv test.ini subdir + +echo "travis-build.bash is done." \ No newline at end of file diff --git a/bin/travis-run.sh b/bin/travis-run.sh new file mode 100644 index 0000000..de89788 --- /dev/null +++ b/bin/travis-run.sh @@ -0,0 +1,6 @@ +#!/bin/sh -e + +echo "NO_START=0\nJETTY_HOST=127.0.0.1\nJETTY_PORT=8983\nJAVA_HOME=$JAVA_HOME" | sudo tee /etc/default/jetty +sudo cp ckan/ckan/config/solr/schema.xml /etc/solr/conf/schema.xml +sudo service jetty restart +nosetests --nologcapture --with-pylons=subdir/test.ini --with-coverage --cover-package=ckanext.d4science_theme --cover-inclusive --cover-erase --cover-tests \ No newline at end of file diff --git a/ckanext/__init__.py b/ckanext/__init__.py new file mode 100644 index 0000000..2e2033b --- /dev/null +++ b/ckanext/__init__.py @@ -0,0 +1,7 @@ +# this is a namespace package +try: + import pkg_resources + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/ckanext/d4science_theme/__init__.py b/ckanext/d4science_theme/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ckanext/d4science_theme/controllers/__init__.py b/ckanext/d4science_theme/controllers/__init__.py new file mode 100644 index 0000000..68f2e01 --- /dev/null +++ b/ckanext/d4science_theme/controllers/__init__.py @@ -0,0 +1,4 @@ +#The __init__.py files are required to make Python +#treat the directories as containing packages; this is done to prevent directories with a common name, such as string, from unintentionally hiding valid modules that occur later on the module search path. +#See: https://docs.python.org/3/tutorial/modules.html#packages + diff --git a/ckanext/d4science_theme/controllers/home.py b/ckanext/d4science_theme/controllers/home.py new file mode 100644 index 0000000..a5627b6 --- /dev/null +++ b/ckanext/d4science_theme/controllers/home.py @@ -0,0 +1,75 @@ +import logging +from ckan.controllers.home import HomeController +import ckan.plugins as p +from ckan.common import OrderedDict, _, g, c +import ckan.lib.search as search +import ckan.model as model +import ckan.logic as logic +import ckan.lib.maintain as maintain +import ckan.lib.base as base +import ckan.lib.helpers as h + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + +class d4SHomeController(): + + #Overriding controllers.HomeController.index method + def index(self): + try: + # package search + context = {'model': model, 'session': model.Session,'user': c.user, 'auth_user_obj': c.userobj} + + facets = OrderedDict() + + default_facet_titles = { + 'organization': _('Organizations'), + 'groups': _('Groups'), + 'tags': _('Tags'), + 'res_format': _('Formats'), + 'license_id': _('Licenses'), + } + + for facet in g.facets: + if facet in default_facet_titles: + facets[facet] = default_facet_titles[facet] + else: + facets[facet] = facet + + # Facet titles + for plugin in p.PluginImplementations(p.IFacets): + facets = plugin.dataset_facets(facets, 'dataset') + + c.facet_titles = facets + + data_dict = { + 'q': '*:*', + 'facet.field': facets.keys(), + 'rows': 4, + 'start': 0, + 'sort': 'views_recent desc', + 'fq': 'capacity:"public"' + } + query = logic.get_action('package_search')(context, data_dict) + c.search_facets = query['search_facets'] + c.package_count = query['count'] + c.datasets = query['results'] + + #print "c.search_facets: " + #print " ".join(c.search_facets) + + except search.SearchError: + c.package_count = 0 + + if c.userobj and not c.userobj.email: + url = h.url_for(controller='user', action='edit') + msg = _('Please update your profile' + ' and add your email address. ') % url + \ + _('%s uses your email address' + ' if you need to reset your password.') \ + % g.site_title + h.flash_notice(msg, allow_html=True) + + return base.render('home/index.html', cache_force=True) + diff --git a/ckanext/d4science_theme/controllers/organization.py b/ckanext/d4science_theme/controllers/organization.py new file mode 100644 index 0000000..fe9c5f2 --- /dev/null +++ b/ckanext/d4science_theme/controllers/organization.py @@ -0,0 +1,135 @@ +# encoding: utf-8 + +import re + +import ckan.controllers.group as group +import ckan.plugins as plugins +import logging +import datetime +from urllib import urlencode + +from pylons.i18n import get_lang + +import ckan.lib.base as base +import ckan.lib.helpers as h +import ckan.lib.maintain as maintain +import ckan.lib.navl.dictization_functions as dict_fns +import ckan.logic as logic +import ckan.lib.search as search +import ckan.model as model +import ckan.authz as authz +import ckan.lib.plugins +import ckan.plugins as plugins +from ckan.common import OrderedDict, c, g, request, _ + + +''' +Created by Francesco Mangiacrapa, see: #8964 +''' +class OrganizationVREController(group.GroupController): + ''' The organization controller is for Organizations, which are implemented + as Groups with is_organization=True and group_type='organization'. It works + the same as the group controller apart from: + * templates and logic action/auth functions are sometimes customized + (switched using _replace_group_org) + * 'bulk_process' action only works for organizations + + Nearly all the code for both is in the GroupController (for historical + reasons). + ''' + + group_types = ['organization'] + + def _guess_group_type(self, expecting_name=False): + return 'organization' + + def _replace_group_org(self, string): + ''' substitute organization for group if this is an org''' + return re.sub('^group', 'organization', string) + + def _update_facet_titles(self, facets, group_type): + for plugin in plugins.PluginImplementations(plugins.IFacets): + facets = plugin.organization_facets( + facets, group_type, None) + + def index(self): + group_type = self._guess_group_type() + + page = h.get_page_number(request.params) or 1 + items_per_page = 21 + + context = {'model': model, 'session': model.Session, + 'user': c.user, 'for_view': True, + 'with_private': False} + + q = c.q = request.params.get('q', '') + sort_by = c.sort_by_selected = request.params.get('sort') + try: + self._check_access('site_read', context) + self._check_access('group_list', context) + except NotAuthorized: + abort(403, _('Not authorized to see this page')) + + # pass user info to context as needed to view private datasets of + # orgs correctly + if c.userobj: + context['user_id'] = c.userobj.id + context['user_is_admin'] = c.userobj.sysadmin + + data_dict_global_results = { + 'all_fields': False, + 'q': q, + 'sort': sort_by, + 'type': group_type or 'group', + } + global_results = self._action('group_list')(context, + data_dict_global_results) + + data_dict_page_results = { + 'all_fields': True, + 'q': q, + 'sort': sort_by, + 'type': group_type or 'group', + 'limit': items_per_page, + 'offset': items_per_page * (page - 1), + } + page_results = self._action('group_list')(context, + data_dict_page_results) + + c.page = h.Page( + collection=global_results, + page=page, + url=h.pager_url, + items_per_page=items_per_page, + ) + + c.page.items = page_results + return base.render('organization_vre/index.html', + extra_vars={'group_type': group_type}) + + + def read(self, id, limit=20): + group_type = self._ensure_controller_matches_group_type( + id.split('@')[0]) + + context = {'model': model, 'session': model.Session, + 'user': c.user, + 'schema': self._db_to_form_schema(group_type=group_type), + 'for_view': True} + data_dict = {'id': id, 'type': group_type} + + # unicode format (decoded from utf8) + c.q = request.params.get('q', '') + + try: + # Do not query for the group datasets when dictizing, as they will + # be ignored and get requested on the controller anyway + data_dict['include_datasets'] = False + c.group_dict = self._action('group_show')(context, data_dict) + c.group = context['group'] + except (NotFound, NotAuthorized): + abort(404, _('Group not found')) + + self._read(id, limit, group_type) + return base.render('organization_vre/read.html', + extra_vars={'group_type': group_type}) \ No newline at end of file diff --git a/ckanext/d4science_theme/controllers/systemtype.py b/ckanext/d4science_theme/controllers/systemtype.py new file mode 100644 index 0000000..d37b5ad --- /dev/null +++ b/ckanext/d4science_theme/controllers/systemtype.py @@ -0,0 +1,92 @@ +import logging +import ckan.plugins as p +from ckan.common import OrderedDict, _, g, c +import ckan.lib.search as search +import ckan.model as model +import ckan.logic as logic +import ckan.lib.maintain as maintain +import ckan.lib.base as base +import ckan.lib.helpers as h + +from urllib import urlencode + +from pylons.i18n import get_lang + +import ckan.lib.base as base +import ckan.lib.helpers as h +import ckan.lib.maintain as maintain +import ckan.lib.navl.dictization_functions as dict_fns +import ckan.logic as logic +import ckan.lib.search as search +import ckan.model as model +import ckan.authz as authz +import ckan.lib.plugins +import ckan.plugins as plugins +from ckan.common import OrderedDict, c, g, request, _ + + + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + +class d4STypeController(base.BaseController): + + #Overriding controllers.HomeController.index method + def index(self): + try: + # package search + context = {'model': model, 'session': model.Session,'user': c.user, 'auth_user_obj': c.userobj} + + facets = OrderedDict() + + default_facet_titles = { + 'organization': _('Organizations'), + 'groups': _('Groups'), + 'tags': _('Tags'), + 'res_format': _('Formats'), + 'license_id': _('Licenses'), + } + + for facet in g.facets: + if facet in default_facet_titles: + facets[facet] = default_facet_titles[facet] + else: + facets[facet] = facet + + # Facet titles + for plugin in p.PluginImplementations(p.IFacets): + facets = plugin.dataset_facets(facets, 'dataset') + + c.facet_titles = facets + + data_dict = { + 'q': '*:*', + 'facet.field': facets.keys(), + 'rows': 4, + 'start': 0, + 'sort': 'views_recent desc', + 'fq': 'capacity:"public"' + } + query = logic.get_action('package_search')(context, data_dict) + c.search_facets = query['search_facets'] + c.package_count = query['count'] + c.datasets = query['results'] + + #print "c.search_facets: " + #print " ".join(c.search_facets) + + except search.SearchError: + c.package_count = 0 + + if c.userobj and not c.userobj.email: + url = h.url_for(controller='user', action='edit') + msg = _('Please update your profile' + ' and add your email address. ') % url + \ + _('%s uses your email address' + ' if you need to reset your password.') \ + % g.site_title + h.flash_notice(msg, allow_html=True) + + return base.render('type/index.html', cache_force=True) + diff --git a/ckanext/d4science_theme/d4sdiscovery/__init__.py b/ckanext/d4science_theme/d4sdiscovery/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ckanext/d4science_theme/d4sdiscovery/d4s_cache_controller.py b/ckanext/d4science_theme/d4sdiscovery/d4s_cache_controller.py new file mode 100644 index 0000000..799d2bf --- /dev/null +++ b/ckanext/d4science_theme/d4sdiscovery/d4s_cache_controller.py @@ -0,0 +1,106 @@ +import datetime +import logging +import os +import tempfile +import csv + +from icproxycontroller import NAMESPACE_ID_LABEL + +log = logging.getLogger(__name__) + +CATALINA_HOME = 'CATALINA_HOME' +temp_dir = None +namespaces_dir = None +NAMESPACES_DIR_NAME = "namespaces_for_catalogue" +NAMESPACES_CACHE_FILENAME = "Namespaces_Catalogue_Categories.csv" + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + + +# D4S_Cache_Controller +class D4S_Cache_Controller(): + namespaces_cache_path = None + __scheduler = None + + def __init__(self): + """ Virtually private constructor. """ + log.debug("__init__ D4S_Cache_Controller") + self._check_cache() + + def _check_cache(self): + + if self.namespaces_cache_path is None: + self.init_temp_dir() + self.namespaces_cache_path = os.path.join(namespaces_dir, NAMESPACES_CACHE_FILENAME) + log.info("The namespaces cache is located at: %s" % self.namespaces_cache_path) + + if not os.path.exists(self.namespaces_cache_path): + log.info("File does not exists creating it") + try: + with open(self.namespaces_cache_path, mode='w') as namespaces_file: + csv.writer(namespaces_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) + log.info("Cache created at %s" % self.namespaces_cache_path) + except Exception as e: + print(e) + + ''' Write the list of dictionary with namespaces''' + def write_namespaces(self, namespace_list_of_dict): + # Insert Data + with open(self.namespaces_cache_path, 'w') as namespaces_file: + writer = csv.writer(namespaces_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) + writer.writerow([NAMESPACE_ID_LABEL, 'name', 'title', 'description']) + for namespace_dict in namespace_list_of_dict: + #print("namespace %s" % namespace_dict) + writer.writerow([namespace_dict[NAMESPACE_ID_LABEL], namespace_dict['name'], namespace_dict['title'], namespace_dict['description']]) + + log.info("Inserted %d namespaces in the Cache" % len(namespace_list_of_dict)) + + '''Returns the list of dictionary with namespaces''' + def read_namespaces(self): + # Read Data + namespace_list_of_dict = [] + try: + with open(self.namespaces_cache_path, 'r') as namespaces_file: + reader = csv.DictReader(namespaces_file) + for row in reader: + #print("read namespace %s" % row) + namespace_list_of_dict.append(dict(row)) + + log.debug("from Cache returning namespace_list_of_dict %s: " % namespace_list_of_dict) + log.info("from Cache read namespace_list_of_dict with %d item/s " % len(namespace_list_of_dict)) + return namespace_list_of_dict + except Exception as e: + print(e) + + log.info("no namespace in the Cache returning empty list of dict") + return namespace_list_of_dict + + @property + def get_namespaces_cache_path(self): + return self.namespaces_cache_path + + @classmethod + def init_temp_dir(cls): + global temp_dir + global NAMESPACES_DIR_NAME + global namespaces_dir + try: + temp_dir = str(os.environ[CATALINA_HOME]) + temp_dir = os.path.join(temp_dir, "temp") + except KeyError as error: + log.error("No environment variable for: %s" % CATALINA_HOME) + + if temp_dir is None: + temp_dir = tempfile.gettempdir() # using system tmp dir + + log.debug("Temp dir is: %s" % temp_dir) + + namespaces_dir = os.path.join(temp_dir, NAMESPACES_DIR_NAME) + + if not os.path.exists(namespaces_dir): + os.makedirs(namespaces_dir) + + + diff --git a/ckanext/d4science_theme/d4sdiscovery/d4s_extras.py b/ckanext/d4science_theme/d4sdiscovery/d4s_extras.py new file mode 100644 index 0000000..8a62764 --- /dev/null +++ b/ckanext/d4science_theme/d4sdiscovery/d4s_extras.py @@ -0,0 +1,30 @@ +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + +import logging +log = logging.getLogger(__name__) + +class D4S_Extras(): + + def __init__(self, category_dict={}, extras=[]): + self._category = category_dict + self._extras = extras + + def append_extra(self, k, v): + #print ("self._extras: %s" %self._extras) + if k is not None: + self._extras.append({k:v}) + + @property + def category(self): + return self._category + + @property + def extras(self): + return self._extras + + def __repr__(self): + return 'category: %s'%self._category+' ' \ + 'extras: %s'%self._extras + diff --git a/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces.py b/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces.py new file mode 100644 index 0000000..54f1e90 --- /dev/null +++ b/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces.py @@ -0,0 +1,39 @@ +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + +#OrderedDict([(u'@id', u'extra_information'), (u'name', u'Extra Information'), (u'title', u'Extras'), (u'description', u'This section is about Extra(s)')]), u'contact': OrderedDict([(u'@id', u'contact'), (u'name', u'Contact'), (u'title', u'Contact Title'), (u'description', u'This section is about Contact(s)')]), u'developer_information': OrderedDict([(u'@id', u'developer_information'), (u'name', u'Developer'), (u'title', u'Developer Information'), (u'description', u'This section is about Developer(s)')])} + +import logging +log = logging.getLogger(__name__) + +class D4S_Namespaces(): + + def __init__(self, id=None, name=None, title=None, description=None): + self._id = id + self._name = name + self._title = title + self._description = description + + @property + def id(self): + return self._id + + @property + def name(self): + return self._name + + @property + def title(self): + return self._title + + + @property + def description(self): + return self._description + + def __repr__(self): + return '{id: %s'%self.id+', ' \ + 'name: %s'%self.name+ ', ' \ + 'title: %s'%self.title+ ', ' \ + 'description: %s'%self.description+ '}' diff --git a/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces_controller.py b/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces_controller.py new file mode 100644 index 0000000..6d4779d --- /dev/null +++ b/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces_controller.py @@ -0,0 +1,130 @@ +import logging +import time + +from d4s_cache_controller import D4S_Cache_Controller +from icproxycontroller import D4S_IS_DiscoveryCatalogueNamespaces +from threading import Event, Thread + +CATEGORY = 'category' +NOCATEOGORY = 'nocategory' + +log = logging.getLogger(__name__) + +cancel_future_calls = None + +# Refreshing time for namespaces cache in secs. +NAMESPACES_CACHE_REFRESHING_TIME = 60 * 60 + + +# Funtion to call repeatedly another function +def call_repeatedly(interval, func, *args): + log.info("call_repeatedly called on func '{}' with interval {} sec".format(func.func_name, interval)) + stopped = Event() + + def loop(): + while not stopped.wait(interval): # the first call is in `interval` secs + func(*args) + + th = Thread(name='daemon_caching_namespaces', target=loop) + th.setDaemon(True) + th.start() + return stopped.set + + +def reload_namespaces_from_IS(urlICProxy, resourceID, gcubeToken): + log.info("_reload_namespaces_from_IS called") + try: + discovery_ctg_namespaces = D4S_IS_DiscoveryCatalogueNamespaces(urlICProxy, resourceID, gcubeToken) + namespaces_list_of_dict = discovery_ctg_namespaces.getNamespacesDictFromResource() + + if namespaces_list_of_dict is not None and len(namespaces_list_of_dict) > 0: + log.debug("namespaces read from IS are: %s" % namespaces_list_of_dict) + D4S_Cache_Controller().write_namespaces(namespaces_list_of_dict) + else: + log.info("namespaces list read from IS is empty. Skipping caching update") + + except Exception as e: + print("Error occurred on reading namespaces from IS and refilling the cache!") + print(e) + + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + + +# D4S_IS_DiscoveryCatalogueNamespacesController is used to discovery namespaces for Catalogue Categories (implemented as a Singleton) +# @param: urlICProxy is the URI of IC proxy rest-full service provided by IS +# @param: resourceID is the resource ID of the Generic Resource: "Namespaces Catalogue Categories" +# @param: gcubeToken the gcube token used to contact the IC proxy +class D4S_Namespaces_Controller(): + __instance = None + + @staticmethod + def getInstance(): + """ Static access method. """ + if D4S_Namespaces_Controller.__instance is None: + D4S_Namespaces_Controller() + + return D4S_Namespaces_Controller.__instance + + def __init__(self): + """ Virtually private constructor. """ + log.debug("__init__ D4S_Namespaces_Controller") + + if D4S_Namespaces_Controller.__instance is not None: + raise Exception("This class is a singleton!") + else: + D4S_Namespaces_Controller.__instance = self + + self._d4s_cache_controller = D4S_Cache_Controller() + self._urlICProxy = None + self._resourceID = None + self._gcubeToken = None + + def load_namespaces(self, urlICProxy, resourceID, gcubeToken): + log.debug("readNamespaces called") + self._urlICProxy = urlICProxy + self._resourceID = resourceID + self._gcubeToken = gcubeToken + return self._check_namespaces() + + def _read_namespaces(self): + return self._d4s_cache_controller.read_namespaces() + + def _check_namespaces(self): + log.debug("_check_namespaces called") + + if self._d4s_cache_controller is None: + self._d4s_cache_controller = D4S_Cache_Controller() + + namespace_list = self._read_namespaces() + + # when the Cache is empty + if namespace_list is None or not namespace_list: + # reading namespaces from IS and filling the DB + log.info("The Cache is empty. Reading the namespace from IS and filling the Cache") + reload_namespaces_from_IS(self._urlICProxy, self._resourceID, self._gcubeToken) + # reloading the namespaces from the cache + namespace_list = self._read_namespaces() + + # starting Thread daemon for refreshing the namespaces Cache + global cancel_future_calls + if cancel_future_calls is None: + cancel_future_calls = call_repeatedly(NAMESPACES_CACHE_REFRESHING_TIME, reload_namespaces_from_IS, + self._urlICProxy, + self._resourceID, + self._gcubeToken) + + return namespace_list + + def get_dict_ctg_namespaces(self): + log.debug("get_dict_ctg_namespaces called") + namespace_list_of_dict = self._check_namespaces() + return self.convert_namespaces_to_d4s_namespacedict(namespace_list_of_dict) + + # Private method + @staticmethod + def convert_namespaces_to_d4s_namespacedict(namespace_list_of_dict): + log.debug("convert_namespaces_to_d4s_namespacedict called on %s" % namespace_list_of_dict) + return D4S_IS_DiscoveryCatalogueNamespaces.to_namespaces_dict_index_for_id(namespace_list_of_dict) diff --git a/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces_extras_util.py b/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces_extras_util.py new file mode 100644 index 0000000..fd9b8f9 --- /dev/null +++ b/ckanext/d4science_theme/d4sdiscovery/d4s_namespaces_extras_util.py @@ -0,0 +1,89 @@ +import logging +import collections +from d4s_extras import D4S_Extras + +CATEGORY = 'category' +NOCATEOGORY = 'nocategory' + +log = logging.getLogger(__name__) + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + + +# D4S_Namespaces_Extra_Util is used to get the extra fields indexed for D4Science namespaces +# @param: namespace_dict is the namespace dict of D4Science namespaces (defined in the Generic Resource: "Namespaces Catalogue Categories") +# @param: extras is the dictionary of extra fields for a certain item +class D4S_Namespaces_Extra_Util(): + + def get_extras_indexed_for_namespaces(self, namespace_dict, extras): + extras_for_categories = collections.OrderedDict() + + # ADDING ALL EXTRAS WITH NAMESPACE + for namespaceid in namespace_dict.keys(): + dict_extras = None + nms = namespaceid + ":" + #has_namespace_ref = None + for key, value in extras: + k = key + v = value + # print "key: " + k + # print "value: " + v + if k.startswith(nms): + + if namespaceid not in extras_for_categories: + extras_for_categories[namespaceid] = collections.OrderedDict() + + dict_extras = extras_for_categories[namespaceid] + log.debug("dict_extras %s "%dict_extras) + + if (dict_extras is None) or (not dict_extras): + dict_extras = D4S_Extras(namespace_dict.get(namespaceid), []) + log.debug("dict_extras after init %s " % dict_extras) + + #print ("dict_extras after init %s " % dict_extras) + log.debug("replacing namespace into key %s " % k +" with empty string") + nms = namespaceid + ":" + k = k.replace(nms, "") + dict_extras.append_extra(k, v) + extras_for_categories[namespaceid] = dict_extras + log.debug("adding d4s_extra: %s " % dict_extras+ " - to namespace id: %s" %namespaceid) + #has_namespace_ref = True + #break + + #ADDING ALL EXTRAS WITHOUT NAMESPACE + for key, value in extras: + k = key + v = value + + has_namespace_ref = None + for namespaceid in namespace_dict.keys(): + nms = namespaceid + ":" + #IF KEY NOT STARTING WITH NAMESPACE + if k.startswith(nms): + has_namespace_ref = True + log.debug("key: %s " % k + " - have namespace: %s" % nms) + break + + if has_namespace_ref is None: + log.debug("key: %s " % k + " - have not namespace") + if NOCATEOGORY not in extras_for_categories: + extras_for_categories[NOCATEOGORY] = collections.OrderedDict() + + dict_extras_no_cat = extras_for_categories[NOCATEOGORY] + #print ("dict_extras_no_cat %s " % dict_extras_no_cat) + + if (dict_extras_no_cat is None) or (not dict_extras_no_cat): + dict_extras_no_cat = D4S_Extras(NOCATEOGORY, []) + + #print ("adding key: %s "%k+" - value: %s"%v) + log.debug("NOCATEOGORY adding key: %s " % k + " - value: %s" % v) + + dict_extras_no_cat.append_extra(k, v) + log.debug("dict_extras_no_cat %s " % dict_extras_no_cat) + extras_for_categories[NOCATEOGORY] = dict_extras_no_cat + log.debug("extras_for_categories NOCATEOGORY %s " % extras_for_categories) + + return extras_for_categories + diff --git a/ckanext/d4science_theme/d4sdiscovery/icproxycontroller.py b/ckanext/d4science_theme/d4sdiscovery/icproxycontroller.py new file mode 100644 index 0000000..d882505 --- /dev/null +++ b/ckanext/d4science_theme/d4sdiscovery/icproxycontroller.py @@ -0,0 +1,110 @@ +import logging +import urllib2 +from lxml import etree + +import xmltodict +import collections + +from d4s_namespaces import D4S_Namespaces + +XPATH_NAMESPACES = "/Resource/Profile/Body/namespaces" +gcubeTokenParam = "gcube-token" +NAMESPACE_ID_LABEL = '@id' + +log = logging.getLogger(__name__) + + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + +def getResponseBody(uri): + req = urllib2.Request(uri) + try: + resp = urllib2.urlopen(req, timeout=20) + except urllib2.HTTPError as e: + log.error("Error on contacting URI: %s" % uri) + log.error("HTTPError: %d" % e.code) + return None + except urllib2.URLError as e: + # Not an HTTP-specific error (e.g. connection refused) + log.error("URLError - Input URI: %s " % uri + " is not valid!!") + return None + else: + # 200 + body = resp.read() + return body + + +# D4S_IS_DiscoveryCatalogueNamespaces is used to discovery namespaces for Catalogue Categories. +# @param: urlICProxy is the URI of IC proxy rest-full service provided by IS +# @param: resourceID is the resource ID of the Generic Resource: "Namespaces Catalogue Categories" +# @param: gcubeToken the gcube token used to contact the IC proxy +class D4S_IS_DiscoveryCatalogueNamespaces(): + + def __init__(self, urlICProxy, resourceID, gcubeToken): + self.urlICProxy = urlICProxy + self.resourceID = resourceID + self.gcubeToken = gcubeToken + + def getNamespacesDictFromResource(self): + + doc = {} + namespace_list = [] + + try: + # print("proxy: "+self.urlICProxy) + # print("resourceID: " + self.resourceID) + # print("gcubeTokenParam: " + gcubeTokenParam) + # print("gcubeToken: " + self.gcubeToken) + + uri = self.urlICProxy + "/" + self.resourceID + "?" + gcubeTokenParam + "=" + self.gcubeToken + log.info("Contacting URL: %s" % uri) + theResource = getResponseBody(uri) + log.debug("Resource returned %s " % theResource) + theResourceXML = etree.XML(theResource) + theNamespaces = theResourceXML.xpath(XPATH_NAMESPACES) + log.debug("The body %s" % etree.tostring(theNamespaces[0])) + + if theNamespaces is not None and theNamespaces[0] is not None: + bodyToString = etree.tostring(theNamespaces[0]) + doc = xmltodict.parse(bodyToString) + else: + log.warn("No Namespace for Catalogue Categories found, returning None") + except Exception as inst: + log.error("Error on getting catalogue namespaces: " + str(inst)) + log.info("Returning empty list of namespaces") + return namespace_list + + log.debug("IS namespaces resource to dict is: %s" % doc) + + + if (doc.has_key('namespaces')): + # log.debug('Namespaces obj %s:' % doc['namespaces']) + namespaces = doc['namespaces'] + if doc is not None and namespaces.has_key('namespace'): + namespace_list = namespaces['namespace'] + + log.info("Loaded %d namespaces from IS resource" % len(namespace_list)) + return namespace_list + + @staticmethod + def to_namespaces_dict_index_for_id(namespace_list): + namespace_dict = collections.OrderedDict() + log.debug("namespaces to dict: %s" % namespace_list) + try: + if namespace_list is not None and len(namespace_list) > 0: + for namespace in namespace_list: + try: + if namespace.has_key(NAMESPACE_ID_LABEL): + namespace_dict[namespace[NAMESPACE_ID_LABEL]] = D4S_Namespaces( + namespace[NAMESPACE_ID_LABEL], + namespace['name'], + namespace['title'], + namespace['description']) + except Exception as inst: + log.error("Error on converting catalogue namespaces: " + str(inst)) + except Exception as inst: + log.error("Error on checking namespace_list: " + str(inst)) + # print "namespace_dict to Nam: %s"%namespace_dict + return namespace_dict diff --git a/ckanext/d4science_theme/fanstatic/.gitignore b/ckanext/d4science_theme/fanstatic/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/ckanext/d4science_theme/fanstatic/d4science_scripts.js b/ckanext/d4science_theme/fanstatic/d4science_scripts.js new file mode 100644 index 0000000..642cdc5 --- /dev/null +++ b/ckanext/d4science_theme/fanstatic/d4science_scripts.js @@ -0,0 +1,303 @@ +/* ===================================================== + JavaScript used by CKAN plugin: 'd4science_theme' + Created by Francesco Mangiacrapa ISTI-CNR Pisa, Italy + ===================================================== */ + + +CKAN_D4S_Breadcrumb_Manager = { + + breadcrumbShow : function (show) { + + var breadcrumb = document.getElementById('ckan-breadcrumb'); + console.log('breadcrumb is '+breadcrumb) + if(breadcrumb){ + if(show){ + breadcrumb.style.display = 'block'; + this.organizationTreeShow(true); + } else{ + breadcrumb.style.display = 'none'; + this.organizationTreeShow(false); + } + } + + //var elements = document.getElementsByTagName('a'); + //for(var i = 0, len = elements.length; i < len; i++) { + // elements[i].onclick = function () { + // //alert("You clicked an external link to: " + this.href); + // //window.parent.add_hide_breadcrumb_to_dom(false); + // this.add_hide_breadcrumb_to_dom(false); + // } + //} + }, + + organizationTreeShow : function (show) { + var trees = document.getElementsByClassName("hierarchy-tree-top"); + + if (trees){ + for (i = 0; i < trees.length; i++) { + if(show){ + trees[i].style.display = 'block'; + } else{ + trees[i].style.display = 'none'; + } + } + } + }, + + checkBreadcrumbShow : function () { + + var showBdc = this.getSessionStorageItem("showbreadcrumb") + //console.log("showBdc is: "+showBdc) + if(showBdc != undefined && showBdc=="false"){ + console.log("Show breadcrumb false"); + this.breadcrumbShow(false); + }else{ + console.log("Show breadcrumb true"); + this.breadcrumbShow(true); + } + }, + + + setSessionStorageItem : function (item_key, item_value) { + + // Check browser support + if (typeof(Storage) !== "undefined") { + // Store + sessionStorage.setItem(item_key, item_value); + return true; + } else { + console.log("Sorry, your browser does not support Web Storage..."); + return false; + } + }, + + + getSessionStorageItem : function (item_key) { + + // Check browser support + if (typeof(Storage) !== "undefined") { + // Store + return sessionStorage.getItem(item_key); + } else { + console.log("Sorry, your browser does not support Web Storage..."); + return undefined; + } + } + +} + + +CKAN_D4S_Functions_Util = { + + getPosition : function(canvas, event){ + var x = new Number(); + var y = new Number(); + try { + if (event.clientX != undefined && event.clientY != undefined) + { + + x = event.clientX; + y = event.clientY; + } + else // Firefox method to get the position + { + x = event.clientX + document.body.scrollLeft + + document.documentElement.scrollLeft; + y = event.clientY + document.body.scrollTop + + document.documentElement.scrollTop; + } + x -= canvas.offsetLeft; + y -= canvas.offsetTop; + }catch (err) { + //silent error + } + return '{"posX": "'+x+'", "posY": "'+y+'"}'; + }, + + // When the user clicks on div, open the popup + showPopupD4S : function(event, my_div, my_popup_left_position) { + var popup = document.getElementById(my_div); + var clickPosition = this.getPosition(my_div, event) + var myPosition = JSON.parse(clickPosition); + this.closePopups(my_div); + // When the user clicks anywhere outside of the modal, close it + /*window.onclick = function(event) { + if (event.target != popup) { + popup.style.display = "none"; + } + }*/ + popup.classList.toggle("show"); + + if(my_popup_left_position){ + popup.style.left = my_popup_left_position; + } + else if (myPosition.posX){ + popup.style.left = myPosition.posX + "px"; + } + }, + + closePopups : function ($target) { + var popups = document.getElementsByClassName('popuptext'); + for (i = 0; i < popups.length; i++) { + if (popups[i].getAttribute('id') != $target) { + popups[i].classList.remove('show'); + } + } + }, + + checkURL : function (url) { + //console.log('checking url: '+url) + var regex = new RegExp('^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/|www\.|ftp:\/\/)+[^ "]+$'); + if (regex.test(url)) { + return true; + } + return false; + } + +} + +CKAN_D4S_HTMLMessage_Util = { + + postHeightToPortlet : function (selectedProduct, product) { + var h = document.body.scrollHeight + "px"; + var p = ""; + var msg = ""; + //WORK AROUND IF TWO MESSAGES ARE SENT FROM A PAGE OF A PRODUCT + //THE MESSAGE WITH 'NULL' PRODUCT IS SKIPPED + //console.log("window.location.pathname? "+window.location.pathname); + var pathArray = window.location.pathname.split('/'); + var productContext = "dataset"; + if(pathArray.length>1){ + //console.log("pathArray is: "+pathArray); + var secondLevelLocation = pathArray[1]; //it is the second level location + //console.log("secondLevelLocation is: "+secondLevelLocation); + //console.log("h is: "+h); + if(secondLevelLocation == productContext){ //is it product context? + if(product !== 'undefined' && product !== null){ + p = product; + //console.log("product selected is: "+p); + }else{ + //console.log("product is null or undefined, passing only height"); + msg = "{\"height\": \""+h+"\"}"; + //window.postMessage(msg,'*'); + this.postMessageToParentWindow(msg); + return; + } + } + } + + //msg = "{'height': '"+h+"', 'product': '"+p+"'}"; + msg = "{\"height\": \""+h+"\", \"product\": \""+p+"\"}"; + //window.postMessage(msg,'*'); + //console.log("posting message in the window: "+msg); + this.postMessageToParentWindow(msg); + }, + + postMessageToParentWindow : function (msg) { + //window.postMessage(msg,'*'); + //console.log("posting message in the window: "+msg); + if(window.parent!=null){ + console.log("posting message in the parent window: "+msg); + window.parent.postMessage(msg,'*'); + } + return; + } + +} + +CKAN_D4S_JSON_Util = { + + + //ADDED by Francesco Mangiacrapa + appendHTMLToElement : function(containerID, elementHTML){ + + var divContainer = document.getElementById(containerID); + divContainer.innerHTML = ""; + divContainer.appendChild(elementHTML); + }, + + //ADDED by Francesco Mangiacrapa + jsonToHTML : function(containerID, cssClassToTable) { + + try + { + var jsonTxt = document.getElementById(containerID).innerHTML; + var jsonObj = JSON.parse(jsonTxt); + //console.log(jsonObj.length) + + if(jsonObj.length==undefined) + jsonObj = [jsonObj] + //console.log(jsonObj.length) + + // EXTRACT VALUE FOR HTML HEADER. + var col = []; + for (var i = 0; i < jsonObj.length; i++) { + for (var key in jsonObj[i]) { + //console.log('key json' +key) + if (col.indexOf(key) === -1) { + col.push(key); + } + } + } + + // CREATE DYNAMIC TABLE. + var table = document.createElement("table"); + var addDefaultCss = "json-to-html-table-column"; + if(cssClassToTable){ + addDefaultCss = cssClassToTable; + } + try{ + table.classList.add(addDefaultCss); + }catch(e){ + console.log('invalid css add', e); + } + + // ADD JSON DATA TO THE TABLE AS ROWS. + for (var i = 0; i < col.length; i++) { + + tr = table.insertRow(-1); + var firstCell = tr.insertCell(-1); + //firstCell.style.cssText="font-weight: bold; text-align: center; vertical-align: middle;"; + firstCell.innerHTML = col[i]; + for (var j = 0; j < jsonObj.length; j++) { + var tabCell = tr.insertCell(-1); + var theValue = jsonObj[j][col[i]]; + /* console.log(theValue + ' is url? '+isUrl);*/ + if(CKAN_D4S_Functions_Util.checkURL(theValue)){ + theValue = ''+theValue+''; + } + + tabCell.innerHTML = theValue; + } + } + + // FINALLY ADD THE NEWLY CREATED TABLE WITH JSON DATA TO A CONTAINER. + this.appendHTMLToElement(containerID, table); + + } + catch(e){ + console.log('invalid json', e); + } + } +} + + +//Task #8032 +window.addEventListener("message", + function (e) { + + var curr_loc = window.location.toString() + var orgin = e.origin.toString() + if(curr_loc.startsWith(orgin)){ + //alert("ignoring message from myself"); + return; + } + //console.log("origin: "+e.data) + if(e.data == null) + return; + + var pMess = JSON.parse(e.data) + //console.log(pMess.explore_vres_landing_page) + window.linktogateway = pMess.explore_vres_landing_page; + },false); + \ No newline at end of file diff --git a/ckanext/d4science_theme/fanstatic/d4science_theme.css b/ckanext/d4science_theme/fanstatic/d4science_theme.css new file mode 100644 index 0000000..9e416b1 --- /dev/null +++ b/ckanext/d4science_theme/fanstatic/d4science_theme.css @@ -0,0 +1,844 @@ +/* ===================================================== + The "account masthead" bar across the top of the site + ===================================================== */ + +.account-masthead { + background-color: #ccc; +} +/* The "bubble" containing the number of new notifications. */ +.account-masthead .account .notifications a span { + background-color: #9fa0a2; +} +/* The text and icons in the user account info. */ +.account-masthead .account ul li a { + color: rgba(255, 255, 255, 0.6); +} +/* The user account info text and icons, when the user's pointer is hovering + over them. */ +.account-masthead .account ul li a:hover { + color: rgba(255, 255, 255, 0.7); +/* background-color: black;*/ +} + + +/* ======================================================================== + The main masthead bar that contains the site logo, nav links, and search + ======================================================================== */ + +.masthead { + background: #eee url("/bg-noise.png") repeat scroll 0 0; + border-top: 1px solid #555; + padding-top: 5px; + padding-bottom: 15px !important; + border-bottom: 1px solid #999; +/* background-image: url("/bg-pattern.min.svg") !important; */ +} + +.masthead .navigation .nav-pills li a{ + color: #187794; +} + +a.logo > img{ + margin-bottom: 5px; +} + +/* The "navigation pills" in the masthead (the links to Datasets, + Organizations, etc) when the user's pointer hovers over them. */ +.masthead .navigation .nav-pills li a:hover { +/* background-color: rgb(48, 48, 48);*/ + color: white; +} +/* The "active" navigation pill (for example, when you're on the /dataset page + the "Datasets" link is active). */ +.masthead .navigation .nav-pills li.active a { + background-color: #d2d2d5; +} +/* The "box shadow" effect that appears around the search box when it + has the keyboard cursor's focus. */ +.masthead input[type="text"]:focus { + -webkit-box-shadow: inset 0px 0px 2px 0px rgba(0, 0, 0, 0.7); + box-shadow: inset 0px 0px 2px 0px rgba(0, 0, 0, 0.7); +} + + +/* =========================================== + The content in the middle of the front page + =========================================== */ + +/* Remove the "box shadow" effect around various boxes on the page. */ +.box { + box-shadow: none; +} +.hero { + background: #FEFEFE repeat scroll 0 0 !important; +} +/* Remove the borders around the "Welcome to CKAN" and "Search Your Data" + boxes. */ +.hero .box { + /*border: none;*/ + margin-top: 10px !important; +} +/* Change the colors of the "Search Your Data" box. */ +.homepage .module-search .module-content { + color: rgb(68, 68, 68); + background-color: white; +} +/* Change the background color of the "Popular Tags" box. */ +.homepage .module-search .tags { + background-color: #fcfcfc; +} + +.homepage-title{ + font-size: 20px; + font-weight: bold; + color: #202020; + margin-bottom: 20px; +} + +/* Change the background color of the "Popular Tags" box. */ +.homepage .module-search h3{ + color: #444; +} + +/* Remove some padding. This makes the bottom edges of the "Welcome to CKAN" + and "Search Your Data" boxes line up. */ +.module-content:last-child { + /*padding-bottom: 0px;*/ +} +.homepage .module-search { + padding: 0px; +} +/* Add a border line between the top and bottom halves of the front page. */ +.homepage [role="main"] { + border-bottom: 1px solid #bbb; + padding: 10px 0; +} + +.homepage .stats ul li a b{ + font-size: 30px !important; +} + +[role="main"], .main { +/* background: #f5f6fa url("/bg-pattern.min.svg") repeat; scroll 0 0;*/ + /*background: #fafafa url("/bg-pattern.svg") repeat; scroll 0 0;*/ + background: #fdfdfd none repeat scroll 0 0; + min-height: 0px !important; +} + +.media-item-homepage { + background-color: white; + border-radius: 3px; + float: left; + margin: 15px 0 0 15px; + overflow: hidden; + padding-left: 10px; + padding-right: 10px; + position: relative; + text-align: center; + width: 150px; +} + +.media-heading-homepage { + font-size: 16px; + hyphens: auto; + line-height: 1.3; + margin: 5px 0; +} + +.media-grid-homepage { + -moz-border-bottom-colors: none; + -moz-border-left-colors: none; + -moz-border-right-colors: none; + -moz-border-top-colors: none; +/* background: #fbfbfb url("../../../base/images/bg.png") repeat scroll 0 0; + border-color: #dddddd; + border-image: none; + border-style: solid; + border-width: 1px 0;*/ + list-style: outside none none; + margin: 0 -10px; + padding-bottom: 15px; +} +.media-grid-homepage::before, .media-grid::after { + content: ""; + display: table; + line-height: 0; +} +.media-grid-homepage::after { + clear: both; +} + +.background-circle{ + padding: 10px 10px; + display: inline-block !important; + -webkit-border-radius: 90px; + -moz-border-radius: 90px; + border-radius: 90px; + background-color: #4679b2; + text-decoration: none !important; +} + +.color-white{ + color: white !important; +} + +.badge-circle { + border-radius: 50% 50% 50% 50% !important; + height: 60px; + text-align: center; + vertical-align: middle; + width: 65px; + background-color: #4679b2; + display: inline-block !important; + padding-top: 5px; + text-decoration: none !important; +} + +/* ==================================== + The footer at the bottom of the site + ==================================== */ + +.site-footer, body { + background-color: #bbb; + font-family: "Lato","Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 16px; +} +/* The text in the footer. */ +.site-footer, +.site-footer label, +.site-footer small { + color: rgba(255, 255, 255, 0.6); +} +/* The link texts in the footer. */ +.site-footer a { + color: rgba(255, 255, 255, 0.6); +} + +.site-footer-internal{ + min-height: 10px; + padding: 2px 0; + font-size: 12px; +} + +.site-footer-internal { + /*background-color: rgba(255, 255, 255, 0.6);*/ + text-align: center; + /*display: inline-block;*/ +} + +.site-footer-internal, +.site-footer-internal label, +.site-footer-internal small { + +} + +.site-footer-internal a { + display: inline-block; +} + +.d4s-hide-text { + background-color: transparent; + border: 0 none; + color: transparent; + font: 0px/0 a; + text-shadow: none; +} + +.d4science-footer-logo { + background: url("/gCube_70.png") no-repeat scroll left top rgba(0, 0, 0, 0); + height: 32px; + margin-top: 2px; + text-indent: -900em; + width: 75px; +} + +.d4s-ckan-footer-logo { + background: rgba(0, 0, 0, 0) url("/ckan-logo-footer.png") no-repeat scroll left top; + height: 21px; + margin-top: 2px; + text-indent: -900em; + width: 69px; +} + +.site-footer-d4science { + font-size: 14px; + color: #f5f5f5; + text-align: center; + height: 25px; + padding-top: 5px; + background-color: #7F7F7F; +} + +.site-footer-d4science a { + font-weight: bold; + text-decoration: none; + color: white; +} + + +/* ==================================== + Base elements of the site + ==================================== */ + +div .principaltitle { + color: inherit; + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 20px; + font-weight: bold; + line-height: 1.2; + margin: 15px 0; + text-rendering: optimizelegibility; + word-break: break-all; + padding-bottom: 10px; + padding-top: 5px; + border-bottom: 1px solid #eee; +} + +div .notes { + color: #444444; + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 14px; + line-height: 1.3; + text-align: justify; + word-break: break-all; +} + +div .infotitle { + font-size: 15px; + hyphens: auto; + line-height: 1.3; + word-break: break-all; + font-weight: bold; +} + +.toolbar .breadcrumb{ + font-size: 16px !important; +} + +.box{ + border: 0px !important; +} + +div .sectiontitle{ + color: #9F9F9F; + font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; + font-size: 17px; + font-weight: bold; + margin: 20px 0; + margin-top: 20px; + margin-bottom: 10px; + text-rendering: optimizelegibility; +} + +section .well { + background-color: #fdfdfd !important; + border: 1px solid #e3e3e3; + border-radius: 4px; + box-shadow: none !important; + margin-bottom: 20px; + min-height: 20px; + +} + +.page-heading { + font-size: 18px; + line-height: 1.2; + margin-top: 20px; + margin-bottom: 0px; +} + +#dataset-resources .resource-list{ + background-color: #fdfdfd !important; + border: 1px solid #e3e3e3; + border-radius: 4px; + box-shadow: none !important; + margin: -1px 0 !important; +} + +.wrapper{ + border: 1px solid #d0d0d0; + box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.05); + border-radius: 3px +} + +.home-popular{ + padding-top: 25px; +} + +.logo-homepage{ + max-height: 60px; +} + +.statistics-show{ + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + color: #444444; + text-decoration: none; +} + +.d4s-center-cropped{ + text-align: center; + background-color: #eee; + border: 1px solid #ddd; + padding-bottom: 10px; + padding-top: 10px; +} + +.tag-list { + font-size: 14px; +} + + +/* ==================================== + Acquired Dataset + ==================================== */ +.label-acquired { + background-color: #55a1ce; +} + +.label-owner { + background-color: #e0051e; +} + +.divider { + margin-left:10px; + height:auto; + display:inline-block; +} + +/* ==================================== + List Dataset + ==================================== */ + +/*LEFT +.show_meatadatatype { + color: white; + display: inline-block; // Inline elements with width and height. TL;DR they make the icon buttons stack from left-to-right instead of top-to-bottom + position: relative; // All 'absolute'ly positioned elements are relative to this one + margin-bottom: 20px; + margin-left: 25px; +} +*/ + +/*RIGHT*/ +.show_meatadatatype { + color: white; + display: inline-block; + float: right; + margin-right: 2px; + margin-top: -20px; + position: relative; +} + + + +/* LEFT + * Position the badge within the relatively positioned button +.button__badge { + background-color: #fa3e3e; + border-radius: 2px; + color: white; + + padding: 1px 6px; + font-size: 10px; + + position: absolute; + top: 0; + right: 0; +}*/ + + + +/* RIGTH */ +.button__badge { + color: #808080; + padding: 0px 2px; + font-size: 10px; + top: 0; + right: 0; + font-family: sans-serif, times, georgia; +} + +/* ==================================== + Modal Popup + ==================================== */ + +/* Popup container - can be anything you want */ +/* The Modal (background) */ +.d4s_modal { + display: none; /* Hidden by default */ + position: fixed; /* Stay in place */ + z-index: 10001; /* Sit on top (NB. At 1000 there is the zoom in/out of the Map Widget)*/ + /*padding-top: 100px;*/ /* Location of the box */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: rgb(0,0,0); /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ +} + +/* Modal Content */ +.d4s_modal-content { + background-color: #fefefe; + /*margin: auto;*/ + padding: 20px; + border: 1px solid #888; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + position: absolute; + left: 50%; + margin-left: -225px; + width: 450px; +} + +/* The Close Button */ +.d4s_close { + color: #aaaaaa; + float: right; + font-size: 28px; + font-weight: bold; + padding-left: 20px; +} + +.d4s_close:hover, +.d4s_close:focus { + color: #000; + text-decoration: none; + cursor: pointer; +} + +.d4s_div_clickable{ + cursor: pointer; +} + +/*==================================== +D4S POPUP +======================================*/ + +/* Popup container - can be anything you want */ +.popupD4SNoArrow { + position: relative; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +/* The actual popup */ +.popupD4SNoArrow .popuptext { + visibility: hidden; + width: 300px; + background-color: #555; + color: #fff; + text-align: center; + border-radius: 6px; + padding: 8px; + position: absolute; + z-index: 1; + bottom: 125%; + left: 50%; + margin-left: -150px; +} + +/* Toggle this class - hide and show the popup */ +.popupD4SNoArrow .show { + visibility: visible; + -webkit-animation: fadeIn 1s; + animation: fadeIn 1s; +} + + +/* Popup container - can be anything you want */ +.popupD4S { + position: relative; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +/* The actual popup */ +.popupD4S .popuptext { + visibility: hidden; + width: 300px; + background-color: #555; + color: #fff; + text-align: center; + border-radius: 6px; + padding: 8px; + position: absolute; + z-index: 1; + bottom: 125%; + left: 50%; + margin-left: -150px; +} + +/* Popup arrow */ +.popupD4S .popuptext::after { + content: ""; + position: absolute; + top: 100%; + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: #555 transparent transparent transparent; +} + +/* Toggle this class - hide and show the popup */ +.popupD4S .show { + visibility: visible; + -webkit-animation: fadeIn 1s; + animation: fadeIn 1s; +} + +/* Add animation (fade in the popup) */ +@-webkit-keyframes fadeIn { + from {opacity: 0;} + to {opacity: 1;} +} + +@keyframes fadeIn { + from {opacity: 0;} + to {opacity:1 ;} +} + +/*==================================== +D4S PACKAGE +======================================*/ + +.graphic-preview-style { + text-align: center; + border-top: 1px dotted #DDD; + padding-top: 10px; + padding-bottom: 0px; + margin-top: 15px; +} + +.graphic-preview-style a{ + font-size: 13px; +} + +.graphic-preview-style img{ + max-width: 100% !important; + height: auto; + +} + +.graphic-preview-style #graphic-title{ + font-size: 13px; + +} + +.nav-item{ + word-wrap:break-word; + } + +/*==================================== +RESOURCE_LIST RESOURCE_ITEM INTO PACKAGE +======================================*/ + +.required-access { + font-style: italic; + font-weight: bold; + padding: 5px; +} + +/*==================================== +LINK TO RESOURCES FROM PACKAGE LIST +======================================*/ + +.dataset-resources li a { + background-color: #187794; +} + +.label[data-format="csw"], .label[data-format*="csw"] { + background-color: #e6b800; +} + +/*==================================== +CSS APPLIED TO Similar GRSF Records +======================================*/ + +.my-grsf-table{ + word-break: break-all; +} + +.my-grsf-table tr td{ + width: inherit; +} + +.my-grsf-table tr td:first-child{ + width: 82px !important; +} + +/*==================================== +CSS APPLIED in base.html +======================================*/ + +#ckan-page-loading { + display: none; + position: fixed; + top: 50%; + left: 50%; + margin-top: -130px; + margin-left: -130px; + width: 260px; + height: 260px; + z-index: 100000; + background-image: url("/pageloading.gif"); + background-repeat: no-repeat; + background-position: center; +} + +/*==================================== +CSS APPLIED in search_for_location.html +======================================*/ + +div#search-for-location { + +} + +div#search-for-location #dataset-map { + position: relative !important; + top: +0px !important; +} + +div#search-for-location #dataset-map-container { + height: 300px; +} + + +div#search-for-location .module-heading { + display: none; +} + +div#search-for-extent{ + padding-top: 10px; +} + +/*==================================== +CSS APPLIED in additional_info.html +======================================*/ +.qr-code-table { + width: 100%; +} + +.qr-code-table td { + width: 85%; + border: 1px solid #e3e3e3; +} + +.qr-code-table td:first-child { + padding-left: 10px; + border-right-style: none; + +} + +.qr-code-table td:last-child { + width: 105px; + text-align: center; + border-left-style: none; + +} + +/* MAX-WITH APPIED TO QR_CODE */ +.qr-code-table img { + max-width: 100px; + height: auto; +} + + +/*==================================== +CSS APPLIED FROM JSON TO HTML TABLE +======================================*/ + +.json-to-html-table-column{ + word-break: break-all; +} + +.json-to-html-table-column tr td{ + width: inherit; +} + +.json-to-html-table-column tr td:first-child{ + font-weight: bold; + color: #5a5a5a; +} + +/*==================================== +CSS APPLIED into custom_form_fields +======================================*/ +.disabled-div{ + pointer-events: none; + opacity: 0.5; +} + +.disabled-div input[type="text"]{ + background: #f1f1f1; +} + +/*==================================== +CSS APPLIED into extra_table.html +======================================*/ + +.read-more-state { + display: none; +} + +.read-more-target { + opacity: 0; + max-height: 0; + font-size: 0; + transition: .25s ease; +} + +.read-more-state:checked ~ .read-more-wrap .read-more-target { + opacity: 1; + font-size: inherit; + max-height: 999em; + content: ""; +} + +.read-more-state ~ .read-more-trigger:before { + content: 'Show more'; +} + +.read-more-state:checked ~ .read-more-trigger:before { + content: 'Show less'; +} + +.read-more-state:checked ~ .read-more-wrap::after { + content: ""; +} + +.read-more-trigger { + cursor: pointer; + display: inline-block; + padding: 0 .5em; + color: #187794; + font-size: .9em; + line-height: 2; + border: 1px solid #ddd; + border-radius: .25em; + font-weight: normal; +} + +.read-more-trigger::after { + content: ""; +} + +.read-more-wrap { + margin-bottom: 2px; +} + +.read-more-wrap::after{ + content: " ..."; + +} \ No newline at end of file diff --git a/ckanext/d4science_theme/helpers.py b/ckanext/d4science_theme/helpers.py new file mode 100644 index 0000000..dfd173f --- /dev/null +++ b/ckanext/d4science_theme/helpers.py @@ -0,0 +1,715 @@ +import ckan.authz as authz +import ckan.model as model +from webhelpers.html import escape, HTML, literal, url_escape +from webhelpers.text import truncate +import ckan.lib.helpers as h +import ckan.logic as logic +from ckan.common import config +from ckanext.d4science_theme.d4sdiscovery.d4s_namespaces_controller import D4S_Namespaces_Controller +from ckanext.d4science_theme.d4sdiscovery.d4s_namespaces_extras_util import D4S_Namespaces_Extra_Util +from ckanext.d4science_theme.qrcodelink.generate_qrcode import D4S_QrCode +import urllib2 + +from ckan.common import ( + _, ungettext, g, c, request, session, json, OrderedDict +) + +import random +from operator import itemgetter +from logging import getLogger +import base64 +import sys, os, re +import ConfigParser +import collections + +log = getLogger(__name__) + +systemtype_field = 'systemtypefield' +systemtype_field_default_value = 'system:type' +ic_proxy_url_field = 'ic_proxy_url' +ic_proxy_url_field_default_value = "https://registry.d4science.org/icproxy/gcube/service" +application_token_field = 'application_token' +namespaces_generic_resource_id_default_value = "23d827cd-ba8e-4d8c-9ab4-6303bdb7d1db" +namespaces_gr_id_fieldname = "namespaces_generic_resource_id" +namespaceseparator_field = 'namespace_separator' +namespaceseparator_field_default_value = ':' +systemtype_rgb_colors = ['#c0392b ', '#585858', '#04407C', '#9b59b6', '#2ecc71', '#16a085', '#7f8c8d ', '#2ecc71', + '#FA8072', '#00FFFF', '#C76611', '#f39c12', '#800000'] +systemtype_field_colors = 'systemtype_field_colors' + +systemtype_cms_fields_placeholders = {'prefix': 'system:cm_', 'item_status': 'system:cm_item_status'} + +NOCATEOGORY = 'nocategory' +TRANSLATE_OF_ = 'translate_of_' + +ctg_namespace_ctrl = None + + +# ADDED BY FRANCESCO.MANGIACRAPA, related to Task #5196 +def get_user_role_for_group_or_org(group_id, user_name): + ''' Returns the user's role for the group. (Ignores privileges that cascade + in a group hierarchy.)''' + return authz.users_role_for_group_or_org(group_id, user_name) + + +# ADDED BY FRANCESCO.MANGIACRAPA, related to breadcrumb for Group +def get_parents_for_group(group_name_or_id): + ''' Returns the user's role for the group. (Ignores privileges that cascade + in a group hierarchy.)''' + group = model.Group.get(group_name_or_id) + if group: + return model.Group.get_parent_group_hierarchy(group) + else: + return None + + +# ADDED BY FRANCESCO.MANGIACRAPA +def get_header_param(parameter_name, default=None): + ''' This function allows templates to access header string parameters + from the request. ''' + return request.headers.get(parameter_name, default) + + +# ADDED BY FRANCESCO.MANGIACRAPA +def get_request_param(parameter_name, default=None): + ''' This function allows templates to access query string parameters + from the request. ''' + return request.params.get(parameter_name, default) + + +# ADDED BY FRANCESCO.MANGIACRAPA +def get_cookie_value(cookie_name, default=None): + ''' This function allows templates to access cookie by cookie_name parameter + from the request. ''' + + value = request.cookies.get(cookie_name) + + if value is None: + print 'cookie: ' + cookie_name + ', has value None' + else: + print 'cookie: ' + cookie_name + ', has value ' + value + + return value + + +# Updated BY FRANCESCO.MANGIACRAPA, added allow_html +def markdown_extract_html(text, extract_length=190, allow_html=False): + ''' Returns the plain text representation of markdown encoded text. That + is the texted without any html tags. If extract_length is 0 then it + will not be truncated.''' + if not text: + return '' + if allow_html: + plain = h.markdown(text.strip()) + else: + plain = h.RE_MD_HTML_TAGS.sub('', h.markdown(text)) + + if not extract_length or len(plain) < extract_length: + return literal(plain) + return literal(unicode(truncate(plain, length=extract_length, indicator='...', whole_word=True))) + + +def get_systemtype_field_dict_from_session(): + '''Return the value of 'ckan.d4science_theme.metadatatypefield' + read from production.ini''' + + systemtype_fieldname = session.get(systemtype_field) + + if systemtype_fieldname is None: + log.info(systemtype_field + " not found in session, loading from config") + else: + log.debug(systemtype_field + " found in session having value: %s" % systemtype_fieldname) + return systemtype_fieldname + + systemtype_fieldname = config.get('ckan.d4science_theme.' + systemtype_field) + + if systemtype_fieldname is None: + log.info( + systemtype_field + " field does not exist in production.ini, returning default value %s" % systemtype_field_default_value) + systemtype_fieldname = systemtype_field_default_value + + separator = get_namespace_separator_from_session() + log.debug("Replacing %s" % separator + " with empty string for key %s" % systemtype_field) + systemtype_fieldname_name = systemtype_fieldname.replace(separator, "") + purgedfieldname = purge_namespace_to_fieldname(systemtype_fieldname) + log.debug("Setting %s" % systemtype_fieldname + " in session for key %s" % systemtype_field) + session[systemtype_field] = {'id': systemtype_fieldname, 'name': systemtype_fieldname_name, + 'title': purgedfieldname} + session.save() + return session[systemtype_field] + + +def get_d4s_namespace_controller(): + '''Instance the D4S_Namespaces_Controller and check that the namespaces are not empty reading it from IS and/or using a Caching system. + The ic-proxy-url is built by reading the configurations from production.ini''' + + d4s_extras_controller = D4S_Namespaces_Controller.getInstance() + global ctg_namespace_ctrl + + if ctg_namespace_ctrl is not None: + log.info("ctg_namespace_ctrl with configurations is NOT None") + the_namespaces = d4s_extras_controller.load_namespaces(ctg_namespace_ctrl['ic_proxy_url'], + ctg_namespace_ctrl['resource_id'], + ctg_namespace_ctrl['application_token']) + log.debug("the_namespaces are %s" % the_namespaces) + + if the_namespaces is None or len(the_namespaces) == 0: + log.info("D4S_Namespaces_Controller obj with none or empty namespaces, going to read them") + else: + log.info("d4s_namespaces_controller found and the namespaces property is not empty: %s" % d4s_extras_controller) + return d4s_extras_controller + else: + log.info("ctg_namespace_ctrl with configurations is None, instancing it") + + ic_proxy_url_value = config.get('ckan.d4science_theme.' + ic_proxy_url_field) + + if ic_proxy_url_value is None: + log.info( + "ckan.d4science_theme." + ic_proxy_url_field + " field does not exist in production.ini, returning default value %s" % ic_proxy_url_field_default_value) + ic_proxy_url_value = ic_proxy_url_field_default_value + + application_token_fieldname = config.get('ckan.d4science_theme.' + application_token_field) + + if application_token_fieldname is None: + log.error("ckan.d4science_theme." + application_token_field + " field does not exist in production.ini!!!") + application_token_fieldname = None + + namespaces_gr_id_fieldname_value = config.get('ckan.d4science_theme.' + namespaces_gr_id_fieldname) + + if namespaces_gr_id_fieldname_value is None: + log.error("ckan.d4science_theme." + application_token_field + " field does not exist in production.ini!!!") + namespaces_gr_id_fieldname_value = namespaces_generic_resource_id_default_value + + # filling the ctg_namespace_ctrl with IS configurations to perform the query for loading the namespaces from IS + ctg_namespace_ctrl = {'ic_proxy_url': ic_proxy_url_value, + 'application_token': application_token_fieldname, + 'resource_id': namespaces_gr_id_fieldname_value} + + d4s_extras_controller.load_namespaces(ctg_namespace_ctrl['ic_proxy_url'], ctg_namespace_ctrl['resource_id'], + ctg_namespace_ctrl['application_token']) + + return d4s_extras_controller + + +def get_extras_indexed_for_namespaces(extras): + namespace_dict = get_namespaces_dict() + # log.info("my_namespace_dict %s" % namespace_dict) + my_extra = get_extras(extras) + # log.info("my_extra is %s" % my_extra) + # d4s_extras_controller = D4S_Namespaces_Controller.getInstance() + # extras_indexed_for_categories = d4s_extras_controller.get_extras_indexed_for_namespaces(namespace_dict, my_extra) + + extras_indexed_for_categories = D4S_Namespaces_Extra_Util().get_extras_indexed_for_namespaces(namespace_dict, + my_extra) + return extras_indexed_for_categories + + +def get_namespaces_dict(): + d4s_extras_controller = get_d4s_namespace_controller() + + if d4s_extras_controller is not None: + return d4s_extras_controller.get_dict_ctg_namespaces() + else: + log.info("local_extras_controller is null, returning empty dictionary for namespaces") + return {} + + +def get_extra_for_category(extras_indexed_for_categories, key_category): + if extras_indexed_for_categories.has_key(key_category): + catalogue_namespace = extras_indexed_for_categories[key_category] + return catalogue_namespace.extras + + return [] + + +def get_systemtype_value_from_extras(package, extras=None): + '''Returns the value of metadata fied read from key 'metadatatype' + stored into extra fields if it exists, 'No Type' otherwise''' + systemtype_dict = get_systemtype_field_dict_from_session() + + no_type = 'No Type' + + if extras is None: + return no_type + + for extra in extras: + k, v = extra['key'], extra['value'] + log.debug("key is %s" % k) + log.debug("value is %s" % v) + if k == str(systemtype_dict['id']): + return v + + return no_type + + +def get_namespace_separator_from_session(): + '''Returns the character used to separate namespace from fieldname''' + + separator = session.get(namespaceseparator_field) + + if separator is None: + log.info(namespaceseparator_field + " not found in session, loading from config") + else: + log.debug(namespaceseparator_field + " found in session: %s" % separator) + return separator + + namespace_sep = config.get('ckan.d4science_theme.' + namespaceseparator_field) + + if namespace_sep is None: + log.info( + namespaceseparator_field + " field does not exist in production.ini, returning default value %s" % namespaceseparator_field_default_value) + namespace_sep = namespaceseparator_field_default_value + + log.debug("Setting %s" % namespace_sep + " in session for key %s" % namespaceseparator_field) + session[namespaceseparator_field] = namespace_sep + return namespace_sep + + +def get_extras(package_extras, auto_clean=False, subs=None, exclude=None): + ''' Used for outputting package extras + + :param package_extras: the package extras + :type package_extras: dict + :param auto_clean: If true capitalize and replace -_ with spaces + :type auto_clean: bool + :param subs: substitutes to use instead of given keys + :type subs: dict {'key': 'replacement'} + :param exclude: keys to exclude + :type exclude: list of strings + ''' + + # If exclude is not supplied use values defined in the config + if not exclude: + exclude = g.package_hide_extras + output = [] + for extra in package_extras: + if extra.get('state') == 'deleted': + continue + k, v = extra['key'], extra['value'] + if k in exclude: + continue + if subs and k in subs: + k = subs[k] + elif auto_clean: + k = k.replace('_', ' ').replace('-', ' ').title() + if isinstance(v, (list, tuple)): + v = ", ".join(map(unicode, v)) + output.append((k, v)) + return output + + +def purge_namespace_to_fieldname(fieldname): + separator = get_namespace_separator_from_session() + + if fieldname is None: + return "" + + if separator not in fieldname: + return fieldname + + end = fieldname.index(separator) + 1 + max_l = len(fieldname) + if end < max_l: + return fieldname[end:max_l] + return fieldname + + +def purge_namespace_to_string(facet): + if not c.search_facets or \ + not c.search_facets.get(facet) or \ + not c.search_facets.get(facet).get('items'): + return "" + + facet_name = c.search_facets.get(facet) + print "facet_name " + str(facet_name) + end = str(facet_name).index(":") + if end <= len(facet_name): + return facet_name[:end] + return facet_name + + +def count_facet_items_dict(facet, limit=None, exclude_active=False): + if not c.search_facets or \ + not c.search_facets.get(facet) or \ + not c.search_facets.get(facet).get('items'): + return 0 + facets = [] + for facet_item in c.search_facets.get(facet)['items']: + if not len(facet_item['name'].strip()): + continue + if not (facet, facet_item['name']) in request.params.items(): + facets.append(dict(active=False, **facet_item)) + elif not exclude_active: + facets.append(dict(active=True, **facet_item)) + + # for count, + # print "facets " + str(facets) + total = len(facets) + log.debug("total facet: %s" % facet + " are %d" % total) + return total + + +def random_color(): + rgbl = [255, 0, 0] + random.shuffle(rgbl) + return tuple(rgbl) + + +def check_url(the_url): + try: + urllib2.urlopen(the_url) + return True + except urllib2.HTTPError, e: + # print(e.code) + return False + except urllib2.URLError, e: + # print(e.args) + return False + except Exception as error: + # print(error) + return False + + +def get_color_for_type(systemtype_field_value): + '''Return a color assigned to a system type''' + + systemtypecolors = session.get(systemtype_field_colors) + # log.info("color: getting color for type: %s" %systemtype_field_value) + + if systemtypecolors is None: + log.info("color: " + systemtype_field_colors + " not found in session, creating new one") + systemtypecolors = {} + session[systemtype_field_colors] = systemtypecolors + else: + log.debug("color: " + systemtype_field_colors + " found in session having value: %s" % systemtypecolors) + + e_color = systemtypecolors.get(systemtype_field_value) + + if e_color is None: + usedcolorsLen = len(systemtypecolors) + colorsLen = len(systemtype_rgb_colors) + index = usedcolorsLen if usedcolorsLen < colorsLen else random.randint(0, colorsLen - 1) + e_color = systemtype_rgb_colors[index] + # log.debug("color: adding color %s" %e_color +" index is: "+str(index)) + systemtypecolors[systemtype_field_value] = e_color + session[systemtype_field_colors] = systemtypecolors + + session.save() + # log.debug("color: returning color %s" %e_color +" for type: "+systemtype_field_value) + return e_color + + +def ordered_dictionary(list_to_be_sorted, property='name', ordering="asc"): + # print ("dict %s" %list_to_be_sorted) + + ord = False if ordering == "asc" else True + + if list_to_be_sorted: + return sorted(list_to_be_sorted, key=itemgetter(property), reverse=ord) + + return list_to_be_sorted + + +def qrcode_for_url(url): + if url: + try: + qr_code = D4S_QrCode(url) + image_path = qr_code.get_qrcode_path() + with open(image_path, "rb") as image_file: + return base64.b64encode(image_file.read()) + return "" + except Exception as error: + log.error("Error on getting qrcode for url: " + url + "error: %s" % error) + + return "" + + +def get_list_of_organizations(limit=10, sort='packages'): + to_browse_organizations = [] + try: + data = {} + + if sort: + data['sort'] = sort + + data['limit'] = limit + data['all_fields'] = True + ordered_organizations = [] + ordered_organizations = logic.get_action('organization_list')({}, data) + + for organization in ordered_organizations: + try: + to_browse_obj = {} + + if not organization['name']: + continue + + to_browse_obj['name'] = organization['name'] + + if 'package_count' in organization: + to_browse_obj['package_count'] = organization['package_count'] + + if 'display_name' in organization: + to_browse_obj['display_name'] = organization['display_name'] + + image_url = get_url_to_icon_for_ckan_entity(organization['name'], 'organization', False) + + # Using ICON as first option + if image_url: + to_browse_obj['url'] = image_url + # Using object image_url as second one + elif 'image_url' in organization and organization['image_url']: + to_browse_obj['url'] = organization['image_url'] + # Default placeholder + else: + to_browse_obj['url'] = h.url_for_static('/images/organisations/icon/placeholder-organization.png') + + to_browse_organizations.append(to_browse_obj) + except (logic.NotFound, logic.ValidationError, logic.NotAuthorized) as error: + # SILENT + log.warn("Error on putting organization: %s" % error) + + log.info("browse %d" % len(ordered_organizations) + " organisation/s") + except (logic.NotFound, logic.ValidationError, logic.NotAuthorized) as error: + log.error("Error on getting organizations: %s" % error) + return [] + + return to_browse_organizations + + +def get_list_of_groups(limit=10, sort='package_count'): + to_browse_groups = [] + try: + data = {} + if sort: + data['sort'] = sort + + data['limit'] = limit + data['all_fields'] = True + ordered_groups = [] + ordered_groups = logic.get_action('group_list')({}, data) + + for group in ordered_groups: + # print "\n\ngroup %s" %group + try: + to_browse_obj = {} + + if not group['name']: + continue + + to_browse_obj['name'] = group['name'] + + if 'package_count' in group: + to_browse_obj['package_count'] = group['package_count'] + + if 'display_name' in group: + to_browse_obj['display_name'] = group['display_name'] + + if 'image_url' in group and group['image_url']: + to_browse_obj['url'] = group['image_url'] + else: + to_browse_obj['url'] = get_url_to_icon_for_ckan_entity(group['name'], 'group') + + to_browse_groups.append(to_browse_obj) + except (logic.NotFound, logic.ValidationError, logic.NotAuthorized) as error: + # SILENT + log.warn("Error on putting group: %s" % error) + + log.info("browse %d" % len(ordered_groups) + " organisation/s") + except (logic.NotFound, logic.ValidationError, logic.NotAuthorized) as error: + log.error("Error on getting group: %s" % error) + return [] + + return to_browse_groups + + +def get_browse_info_for_organisations_or_groups(type='organization', limit=10, sort_field=None): + sort = None + if sort_field: + sort = sort_field + + if type == 'organization': + if sort: + return get_list_of_organizations(limit, sort) + else: + return get_list_of_organizations(limit) + + elif type == 'group': + if sort: + return get_list_of_groups(limit, sort) + else: + return get_list_of_groups(limit) + + return [] + + +def get_image_display_for_group(item_id): + if item_id: + try: + item_obj = model.Group.get(item_id) + + if item_obj and item_obj.image_url: + return item_obj.image_url + else: + return h.url_for_static('/images/groups/icon/placeholder-group.png') + + except Exception as error: + log.error("Error on getting item obj: %s" % item_id + "error: %s" % error) + + +def get_application_path(): + if getattr(sys, 'frozen', False): + # If the application is run as a bundle, the pyInstaller bootloader + # extends the sys module by a flag frozen=True and sets the app + # path into variable _MEIPASS'. + application_path = sys._MEIPASS + else: + application_path = os.path.dirname(os.path.abspath(__file__)) + + return application_path + + +''' +Get icon url for input entity type +@:param default_placeholder if True returns the URL of default image, otherwise None. +''' + + +def get_url_to_icon_for_ckan_entity(item_name, entity_type=None, default_placeholder=True): + if not entity_type or not item_name: + return None + + dir_images_full_path = get_application_path() + "/public/images" + dir_images_relative_path = "/images" + + if entity_type == 'group': + dir_images_full_path += "/groups" + dir_images_relative_path += "/groups" + placeholder_icon = "placeholder-group.png" + elif entity_type == 'organization': + dir_images_full_path += "/organisations" + dir_images_relative_path += "/organisations" + placeholder_icon = "placeholder-organization.png" + elif entity_type == 'type': + dir_images_full_path += "/types" + dir_images_relative_path += "/types" + placeholder_icon = "placeholder-type.png" + else: + return None + + icon_path = dir_images_full_path + "/icon/" + item_name.lower() + ".png" + if os.path.isfile(icon_path): + return h.url_for_static(dir_images_relative_path + "/icon/" + item_name.lower() + ".png") + elif default_placeholder: + return h.url_for_static(dir_images_relative_path + "/icon/" + placeholder_icon) + + return None + + +def get_user_info(user_id_or_name): + if user_id_or_name: + try: + + item_obj = model.User.get(user_id_or_name) + + if item_obj: + return item_obj + + return None + except Exception as error: + log.error("Error on getting item obj: %s" % user_id_or_name + "error: %s" % error) + + return None + + +''' +Search the value of my_search_string into input file {ckan_po_file} or the default file ckan.po provided as CKAN language +and returns its translate +''' + + +def get_ckan_translate_for(ckan_po_file, my_search_string): + my_translate = session.get(TRANSLATE_OF_ + my_search_string) + + if not my_search_string: + return "" + + if my_translate: + log.info("Translate of '%s' " % my_search_string + " found in session as: %s" % my_translate) + return my_translate + + if not ckan_po_file: + ckan_po_file = "/usr/lib/ckan/default/src/ckan/ckan/i18n/en_gcube/LC_MESSAGES/ckan.po" + + numlines = 0 + numfound = 0 + found = 0 + line_text = "" + + try: + infile = open(ckan_po_file, "r") + + for line in infile: + numlines += 1 + if found > 0: + numfound += 1 + line_text += str(line) + found = 0 # reset found + + # found += line.upper().count(my_search_string.upper()) + found += line.count(my_search_string) + + if found > 0: + log.debug("The search string '%s'" % my_search_string + " was found. Read the line: %s" % str(line)) + + infile.close() + + except Exception as e: + print "Exception during parsing the file %s" % ckan_po_file, e + + log.info("Recap: '%s' was found" % my_search_string + " %i times " % numfound + "in %i lines" % numlines) + log.debug("Line text is: %s" % line_text) + + pattern = '"([A-Za-z0-9_ \./\\-]*)"' + m = re.search(pattern, line_text) + + try: + my_translate = m.group() + except Exception as e: + print "Pattern %s" % my_search_string + " not found ", e + + if my_translate: + log.debug("Replacing quotas...") + my_translate = my_translate.replace("\"", "") + + log.info("Found the string '%s'" % my_translate + " that translating '%s'" % my_search_string) + + session[TRANSLATE_OF_ + my_search_string] = my_translate + session.save() + + return my_translate + + +def get_location_to_bboxes(): + config = ConfigParser.ConfigParser() + config.optionxform = str + location_to_bboxes = {} + try: + bboxes_file = get_application_path() + "/public/location_to_bboxes.ini" + log.debug("bboxes_file is: '%s'" % bboxes_file) + config.read(bboxes_file) + for section_name in config.sections(): + log.debug('Location to bboxes Section: ' + section_name) + # print ' Options:', parser.options(section_name) + for name, value in config.items(section_name): + location_to_bboxes[name] = value.replace(",", "%2C") + + ordDictBboxes = collections.OrderedDict(sorted(location_to_bboxes.items())) + log.debug("Ordered 'bboxes_file' dict: '%s'" % ordDictBboxes) + return ordDictBboxes + except Exception as error: + log.error("Error on reading file: %s" % bboxes_file + "error: %s" % error) + +def get_content_moderator_system_placeholder(): + return systemtype_cms_fields_placeholders + diff --git a/ckanext/d4science_theme/plugin.py b/ckanext/d4science_theme/plugin.py new file mode 100644 index 0000000..e9040f5 --- /dev/null +++ b/ckanext/d4science_theme/plugin.py @@ -0,0 +1,424 @@ +# encoding: utf-8 +from logging import getLogger + +import ckan.plugins as plugins +from ckanext.d4science_theme import helpers +import ckan.plugins.toolkit as toolkit +import ckan.lib.dictization.model_save as model_save +import ckan.model as model +import ckan.lib.helpers as h +import sqlalchemy as sa +from ckan.controllers.home import HomeController +from ckanext.d4science_theme.controllers.organization import OrganizationVREController +from ckanext.d4science_theme.controllers.home import d4SHomeController +from ckan.config.middleware.common_middleware import TrackingMiddleware +from ckan.common import session +from ckan.plugins import IRoutes + +from ckan.common import ( + g +) + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + +log = getLogger(__name__) + +d4s_ctg_namespaces_controller = None + +def remove_check_replicated_custom_key(schema): + if schema is not None: + schema.pop('__before', None) + + return schema + +#CREATED BY FRANCESCO MANGIACRAPA FOR OVERRIDING THE package_extras_save FROM dictization.model_save.py +def _package_extras_save(extra_dicts, obj, context): + ''' It can save repeated extras as key-value ''' + allow_partial_update = context.get("allow_partial_update", False) + if extra_dicts is None and allow_partial_update: + return + + model = context["model"] + session = context["session"] + + #ADDED BY FRANCESCO MANGIACRAPA + log.debug("extra_dicts: "+unicode(str(extra_dicts)).encode('utf-8')) + #print "extra_dicts: "+str(extra_dicts) + + extras_list = obj.extras_list + #extras = dict((extra.key, extra) for extra in extras_list) + old_extras = {} + extras = {} + for extra in extras_list or []: + old_extras.setdefault(extra.key, []).append(extra.value) + extras.setdefault(extra.key, []).append(extra) + + #ADDED BY FRANCESCO MANGIACRAPA + #print "old_extras: "+str(old_extras) + + new_extras = {} + for extra_dict in extra_dicts or []: + #print 'extra_dict key: '+extra_dict["key"] + ', value: '+extra_dict["value"] + #new_extras.setdefault(extra_dict["key"], []).append(extra_dict["value"]) + if extra_dict.get("deleted"): + log.debug("extra_dict deleted: "+unicode(extra_dict["key"]).encode('utf-8')) + #print 'extra_dict deleted: '+extra_dict["key"] + continue + + #if extra_dict['value'] is not None and not extra_dict["value"] == "": + if extra_dict['value'] is not None: + new_extras.setdefault(extra_dict["key"], []).append(extra_dict["value"]) + + #ADDED BY FRANCESCO MANGIACRAPA + log.debug("new_extras: "+unicode(str(new_extras)).encode('utf-8')) + #print "new_extras: "+str(new_extras) + + #new + for key in set(new_extras.keys()) - set(old_extras.keys()): + state = 'active' + log.debug("adding key: "+unicode(key).encode('utf-8')) + #print "adding key: "+str(key) + extra_lst = new_extras[key] + for extra in extra_lst: + extra = model.PackageExtra(state=state, key=key, value=extra) + session.add(extra) + extras_list.append(extra) + + #deleted + for key in set(old_extras.keys()) - set(new_extras.keys()): + log.debug("deleting key: "+unicode(key).encode('utf-8')) + #print "deleting key: "+str(key) + extra_lst = extras[key] + for extra in extra_lst: + state = 'deleted' + extra.state = state + extras_list.remove(extra) + + #changed + for key in set(new_extras.keys()) & set(old_extras.keys()): + #for each value of new list + for value in new_extras[key]: + old_occur = old_extras[key].count(value) + new_occur = new_extras[key].count(value) + log.debug("value: "+unicode(value).encode('utf-8') + ", new_occur: "+unicode(new_occur).encode('utf-8')+ ", old_occur: "+unicode(old_occur).encode('utf-8')) + #print "value: "+str(value) + ", new_occur: "+str(new_occur) + ", old_occur: "+str(old_occur) + # it is an old value deleted or not + if value in old_extras[key]: + if old_occur == new_occur: + #print "extra - occurrences of: "+str(value) +", are equal into both list" + log.debug("extra - occurrences of: "+unicode(value).encode('utf-8') +", are equal into both list") + #there is a little bug, this code return always the first element, so I'm fixing with #FIX-STATUS + extra_values = get_package_for_value(extras[key], value) + #extras_list.append(extra) + for extra in extra_values: + state = 'active' + extra.state = state + session.add(extra) + #print "extra updated: "+str(extra) + log.debug("extra updated: "+unicode(extra).encode('utf-8')) + + elif new_occur > old_occur: + #print "extra - a new occurrence of: "+str(value) +", is present into new list, adding it to old list" + log.debug("extra - a new occurrence of: "+unicode(value).encode('utf-8') +", is present into new list, adding it to old list") + state = 'active' + extra = model.PackageExtra(state=state, key=key, value=value) + extra.state = state + session.add(extra) + extras_list.append(extra) + old_extras[key].append(value) + log.debug("old extra values updated: "+unicode(old_extras[key]).encode('utf-8')) + #print "old extra values updated: "+str(old_extras[key]) + + else: + #remove all occurrences deleted - this code could be optimized, it is run several times but could be performed one shot + countDelete = old_occur-new_occur + log.debug("extra - occurrence of: "+unicode(value).encode('utf-8')+", is not present into new list, removing "+unicode(countDelete).encode('utf-8')+" occurrence/s from old list") + #print "extra - occurrence of: "+str(value) +", is not present into new list, removing "+str(countDelete)+" occurrence/s from old list" + extra_values = get_package_for_value(extras[key], value) + for idx, extra in enumerate(extra_values): + if idx < countDelete: + #print "extra - occurrence of: "+str(value) +", is not present into new list, removing it from old list" + log.debug("pkg extra deleting: "+unicode(extra.value).encode('utf-8')) + #print "pkg extra deleting: "+str(extra.value) + state = 'deleted' + extra.state = state + + else: + #print "pkg extra reactivating: "+str(extra.value) + log.debug("pkg extra reactivating: "+unicode(extra.value).encode('utf-8')) + state = 'active' + extra.state = state + session.add(extra) + + else: + #print "extra new value: "+str(value) + log.debug("extra new value: "+unicode(value).encode('utf-8')) + state = 'active' + extra = model.PackageExtra(state=state, key=key, value=value) + extra.state = state + session.add(extra) + extras_list.append(extra) + + + #for each value of old list + for value in old_extras[key]: + #if value is not present in new list + if value not in new_extras[key]: + extra_values = get_package_for_value(extras[key], value) + for extra in extra_values: + #print "not present extra deleting: "+str(extra) + log.debug("not present extra deleting: "+unicode(extra).encode('utf-8')) + state = 'deleted' + extra.state = state + + +#ADDED BY FRANCESCO MANGIACRAPA +def get_package_for_value(list_package, value): + ''' Returns a list of packages containing the value passed in input + ''' + lst = [] + for x in list_package: + if x.value == value: + lst.append(x) + else: + return lst + + return lst + +#OVERRIDING BASE SQL ALCHEMY ENGINE INSTANCE +def _init_TrackingMiddleware(self, app, config): + self.app = app + log.debug('TrackingMiddleware d4Science instance') + sqlalchemy_url = config.get('sqlalchemy.url') + log.debug('sqlalchemy_url read: '+str(sqlalchemy_url)) + + sqlalchemy_pool = config.get('sqlalchemy.pool_size') + if sqlalchemy_pool is None: + sqlalchemy_pool = 5 + + log.debug('sqlalchemy_pool read: '+str(sqlalchemy_pool)) + sqlalchemy_overflow = config.get('sqlalchemy.max_overflow') + + if sqlalchemy_overflow is None: + sqlalchemy_overflow = 10; + + log.debug('sqlalchemy_overflow read: '+str(sqlalchemy_overflow)) + + try: + self.engine = sa.create_engine(sqlalchemy_url, pool_size=int(sqlalchemy_pool), max_overflow=int(sqlalchemy_overflow)) + except TypeError as e: + log.error('pool size does not work: ' +str(e.args)) + self.engine = sa.create_engine(sqlalchemy_url) + + + +class D4Science_ThemePlugin(plugins.SingletonPlugin, toolkit.DefaultDatasetForm): + plugins.implements(plugins.IConfigurer) + plugins.implements(plugins.IDatasetForm) + plugins.implements(plugins.ITemplateHelpers) + plugins.implements(plugins.IFacets) + plugins.implements(IRoutes, inherit=True) + + # IConfigurer + def update_config(self, config_): + # Add this plugin's templates dir to CKAN's extra_template_paths, so + # that CKAN will use this plugin's custom templates. + toolkit.add_template_directory(config_, 'templates') + + # Add this plugin's public dir to CKAN's extra_public_paths, so + # that CKAN will use this plugin's custom static files. + toolkit.add_public_directory(config_, 'public') + + # Register this plugin's fanstatic directory with CKAN. + # Here, 'fanstatic' is the path to the fanstatic directory + # (relative to this plugin.py file), and 'example_theme' is the name + # that we'll use to refer to this fanstatic directory from CKAN + # templates. + toolkit.add_resource('fanstatic', 'd4science_theme') + + #IDatasetForm + def create_package_schema(self): + # let's grab the default schema in our plugin + schema = super(D4Science_ThemePlugin, self).create_package_schema() + schema = remove_check_replicated_custom_key(schema) + #d.package_dict_save = _package_dict_save + return schema + + #IDatasetForm + def update_package_schema(self): + schema = super(D4Science_ThemePlugin, self).update_package_schema() + schema = remove_check_replicated_custom_key(schema) + return schema + + #IDatasetForm + def show_package_schema(self): + schema = super(D4Science_ThemePlugin, self).show_package_schema() + schema = remove_check_replicated_custom_key(schema) + return schema + + #IDatasetForm + def is_fallback(self): + # Return True to register this plugin as the default handler for package types not handled by any other IDatasetForm plugin + return False + + #IDatasetForm + def package_types(self): + # This plugin doesn't handle any special package types, it just + # registers itself as the default (above). + return [] + + + #ITemplateHelpers + def get_helpers(self): + log.info("get_helpers called...") + '''Register functions as a template + helper function. + ''' + # Template helper function names should begin with the name of the + # extension they belong to, to avoid clashing with functions from + # other extensions. + return { + 'd4science_theme_get_user_role_for_group_or_org': helpers.get_user_role_for_group_or_org, + 'd4science_theme_get_parents_for_group': helpers.get_parents_for_group, + 'get_header_param': helpers.get_header_param, + 'get_request_param': helpers.get_request_param, + 'get_cookie_value': helpers.get_cookie_value, + 'd4science_theme_markdown_extract_html' : helpers.markdown_extract_html, + 'd4science_theme_get_systemtype_value_from_extras' : helpers.get_systemtype_value_from_extras, + 'd4science_theme_get_systemtype_field_dict_from_session' : helpers.get_systemtype_field_dict_from_session, + 'd4science_theme_get_namespace_separator_from_session' : helpers.get_namespace_separator_from_session, + 'd4science_theme_get_extras' : helpers.get_extras, + 'd4science_theme_count_facet_items_dict' : helpers.count_facet_items_dict, + 'd4science_theme_purge_namespace_to_facet': helpers.purge_namespace_to_fieldname, + 'd4science_get_color_for_type': helpers.get_color_for_type, + 'd4science_get_d4s_namespace_controller': helpers.get_d4s_namespace_controller, + 'd4science_get_extras_indexed_for_namespaces': helpers.get_extras_indexed_for_namespaces, + 'd4science_get_namespaces_dict': helpers.get_namespaces_dict, + 'd4science_get_extra_for_category' : helpers.get_extra_for_category, + 'd4science_get_ordered_dictionary': helpers.ordered_dictionary, + 'd4science_get_qrcode_for_url': helpers.qrcode_for_url, + 'd4science_get_list_of_organizations': helpers.get_list_of_organizations, + 'd4science_get_image_display_for_group': helpers.get_image_display_for_group, + 'd4science_get_list_of_groups': helpers.get_list_of_groups, + 'd4science_get_browse_info_for_organisations_or_groups': helpers.get_browse_info_for_organisations_or_groups, + 'd4science_get_user_info': helpers.get_user_info, + 'd4science_get_url_to_icon_for_ckan_entity' : helpers.get_url_to_icon_for_ckan_entity, + 'd4science_get_ckan_translate_for' : helpers.get_ckan_translate_for, + 'd4science_get_location_to_bboxes' : helpers.get_location_to_bboxes, + 'd4science_get_content_moderator_system_placeholder': helpers.get_content_moderator_system_placeholder, + } + + #Overriding package_extras_save method + model_save.package_extras_save = _package_extras_save + + #Overriding index home controller + d4sHC = d4SHomeController() + HomeController.index = d4sHC.index + + #OVERRIDING BASE SQL ALCHEMY ENGINE INSTANCE + TrackingMiddleware.__init__ = _init_TrackingMiddleware + + global d4s_ctg_namespaces_controller + + #if d4s_ctg_namespaces_controller is None: + # log.info("d4s_ctg_namespaces_controller instancing...") + # d4s_ctg_namespaces_controller = helpers.get_d4s_namespace_controller() + # log.info("d4s_ctg_namespaces_controller instancied %s" % d4s_ctg_namespaces_controller) + + + #IFacets + def dataset_facets(self, facets_dict, package_type): + facets_dict = self._update_facets(facets_dict) + return facets_dict + + def group_facets(self, facets_dict, group_type, package_type): + facets_dict = self._update_facets(facets_dict) + return facets_dict + + def organization_facets(self, facets_dict, organization_type, package_type): + facets_dict = self._update_facets(facets_dict) + return facets_dict + + def _update_facets(self, facets_dict): + '''Add 'metadatatype' to facets if not already present.''' + + log.debug("facets_dict: ") + log.debug(', '.join(facets_dict)) + + metadatatype = helpers.get_systemtype_field_dict_from_session() + + '''Adding system:type''' + facet_title = helpers.purge_namespace_to_fieldname(str(metadatatype['id'])) + facet_title = plugins.toolkit._(facet_title.capitalize() + 's') + facets_dict = self._add_or_update_facet(metadatatype['name'],facet_title, facets_dict) + + log.info("site_url is: "+g.site_url) + + #ADD IT IN THE CUSTOMIZATION? + if g.site_url: + + dev_sites = ['https://ckan-d-d4s.d4science.org'] + grsf_sites = ['https://ckan-grsf-admin2.d4science.org', 'https://ckan-grsf.pre.d4science.org'] + sbd_sites = ['https://ckan.sobigdata.d4science.net', 'https://ckan-sobigdata.d4science.org', + 'https://ckan-sobigdata2.d4science.org'] + + if g.site_url in dev_sites: + '''Adding Status of the GRSF record''' + facets_dict = self._add_or_update_facet("StatusoftheRecord", "Status of the Record", facets_dict, + display_after_facet='groups') + elif g.site_url in grsf_sites: + '''Adding Status of the GRSF record''' + # facets_dict = self._add_or_update_facet("StatusoftheGRSFrecord", "Status of the GRSF record", facets_dict, display_after_facet='groups') + # Fixing #23348 + facets_dict = self._add_or_update_facet("StatusoftheRecord", "Status of the Record", facets_dict, + display_after_facet='groups') + elif g.site_url in sbd_sites: + '''Adding the field Availability ''' + facets_dict = self._add_or_update_facet("Availability", "Availability", facets_dict, + display_after_facet='groups') + + return facets_dict + + def before_map(self, map): + """This IRoutes implementation overrides the standard + ``/user/register`` behaviour with a custom controller. You + might instead use it to provide a completely new page, for + example. + Note that we have also provided a custom register form + template at ``theme/templates/user/register.html``. + """ + # Hook in our custom user controller at the points of creation + # and edition. + # + #map.connect('/type', controller='ckanext.d4science_theme.controllers.type::d4STypeController', action='index') + map.connect('/type', controller='ckanext.d4science_theme.controllers.systemtype:d4STypeController', action='index') + ''' Added by Francesco Mangiacrapa, see: #8964 ''' + organization_vre = OrganizationVREController() + map.connect('/organization_vre', controller='ckanext.d4science_theme.controllers.organization:OrganizationVREController', action='index') + map.connect('/organization_vre/{id}', controller='ckanext.d4science_theme.controllers.organization:OrganizationVREController', action='read') + map.redirect('/types', "/type") + return map + + + def _add_or_update_facet(self, facet_key, facet_value, facets_dict, display_after_facet='organization'): + + #Updating ordering of facets_dict OrderedDict + if str(facet_key) not in facets_dict: + + new_orderded_facets_dict=facets_dict.__class__() + for key, value in facets_dict.items(): + new_orderded_facets_dict[key]=value + # #the field 'metadatatype' will be inserted after following key + if key==display_after_facet: + new_orderded_facets_dict[facet_key]=facet_value + + facets_dict.clear() + facets_dict.update(new_orderded_facets_dict) + log.debug("facets_dict ordered: ") + log.debug(', '.join(facets_dict)) + + return facets_dict + + diff --git a/ckanext/d4science_theme/public/.gitignore b/ckanext/d4science_theme/public/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/ckanext/d4science_theme/public/D4ScienceDataCataloguelogo.png b/ckanext/d4science_theme/public/D4ScienceDataCataloguelogo.png new file mode 100644 index 0000000..27dce14 Binary files /dev/null and b/ckanext/d4science_theme/public/D4ScienceDataCataloguelogo.png differ diff --git a/ckanext/d4science_theme/public/D4ScienceDataCataloguelogo2.png b/ckanext/d4science_theme/public/D4ScienceDataCataloguelogo2.png new file mode 100644 index 0000000..1c378c5 Binary files /dev/null and b/ckanext/d4science_theme/public/D4ScienceDataCataloguelogo2.png differ diff --git a/ckanext/d4science_theme/public/bg-noise.png b/ckanext/d4science_theme/public/bg-noise.png new file mode 100644 index 0000000..40828c6 Binary files /dev/null and b/ckanext/d4science_theme/public/bg-noise.png differ diff --git a/ckanext/d4science_theme/public/bg-pattern.svg b/ckanext/d4science_theme/public/bg-pattern.svg new file mode 100644 index 0000000..0a3e7c8 --- /dev/null +++ b/ckanext/d4science_theme/public/bg-pattern.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ckanext/d4science_theme/public/ckan-logo-footer.png b/ckanext/d4science_theme/public/ckan-logo-footer.png new file mode 100644 index 0000000..09aa4ca Binary files /dev/null and b/ckanext/d4science_theme/public/ckan-logo-footer.png differ diff --git a/ckanext/d4science_theme/public/d4ScienceDataCatalogue.png b/ckanext/d4science_theme/public/d4ScienceDataCatalogue.png new file mode 100644 index 0000000..8b7d380 Binary files /dev/null and b/ckanext/d4science_theme/public/d4ScienceDataCatalogue.png differ diff --git a/ckanext/d4science_theme/public/d4s_tagcloud.js b/ckanext/d4science_theme/public/d4s_tagcloud.js new file mode 100644 index 0000000..aa3c487 --- /dev/null +++ b/ckanext/d4science_theme/public/d4s_tagcloud.js @@ -0,0 +1,58 @@ +/*! + * d4s_tagcloud.js + * D4science Tag Cloud which using Tag Cloud Plugin for JQuery + * + * jquery.tagcloud.js + * created by Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it + */ +loadTagCloudJS = function (elementIDtoCloud, rgb_start, rgb_end) { + + //console.log('start: '+rgb_start) + //console.log('end: '+rgb_end) + + if(!rgb_start) + rgb_start = '#C0C0C0'; + + if(!rgb_end) + rgb_end = '#000066'; + + var script = document.createElement('script'); + script.onload = function() { + /*console.log("TagCloud json loaded and ready");*/ + $.fn.tagcloud.defaults = { + size: {start: 13, end: 20, unit: 'px'}, + color: {start: rgb_start, end: rgb_end} + } + $('#'+elementIDtoCloud +' a').tagcloud(); + }; + + script.type = "text/javascript"; + script.src = "jquery.tagcloud.js"; + document.getElementsByTagName('head')[0].appendChild(script); +} + +loadCloud = function (elementIDtoCloud, rgb_start, rgb_end) { + + if(!window.jQuery){ + var script = document.createElement('script'); + script.onload = function() { + /*console.log("JQuery loaded and ready");*/ + loadTagCloudJS(elementIDtoCloud,rgb_start,rgb_end); + }; + + script.type = "text/javascript"; + script.src = "https://code.jquery.com/jquery-1.11.0.min.js"; + document.getElementsByTagName('head')[0].appendChild(script); + + }else { + loadTagCloudJS(elementIDtoCloud,rgb_start,rgb_end); + } + + /*SHUFFLE TAGS*/ + var cloud = document.querySelector('#'+elementIDtoCloud); + if (cloud == null) + return; + for (var i = cloud.children.length; i >= 0; i--) { + cloud.appendChild(cloud.children[Math.random() * i | 0]); + } +} \ No newline at end of file diff --git a/ckanext/d4science_theme/public/d4science.ico b/ckanext/d4science_theme/public/d4science.ico new file mode 100644 index 0000000..718bf5d Binary files /dev/null and b/ckanext/d4science_theme/public/d4science.ico differ diff --git a/ckanext/d4science_theme/public/d4science_logo.png b/ckanext/d4science_theme/public/d4science_logo.png new file mode 100644 index 0000000..3b87305 Binary files /dev/null and b/ckanext/d4science_theme/public/d4science_logo.png differ diff --git a/ckanext/d4science_theme/public/favicon.ico b/ckanext/d4science_theme/public/favicon.ico new file mode 100644 index 0000000..718bf5d Binary files /dev/null and b/ckanext/d4science_theme/public/favicon.ico differ diff --git a/ckanext/d4science_theme/public/gCube_70.png b/ckanext/d4science_theme/public/gCube_70.png new file mode 100644 index 0000000..018d52c Binary files /dev/null and b/ckanext/d4science_theme/public/gCube_70.png differ diff --git a/ckanext/d4science_theme/public/gcubedatacataloguelogo.png b/ckanext/d4science_theme/public/gcubedatacataloguelogo.png new file mode 100644 index 0000000..1b4bf52 Binary files /dev/null and b/ckanext/d4science_theme/public/gcubedatacataloguelogo.png differ diff --git a/ckanext/d4science_theme/public/grsf/GRSF_for_admins_logo.png b/ckanext/d4science_theme/public/grsf/GRSF_for_admins_logo.png new file mode 100644 index 0000000..dbf83de Binary files /dev/null and b/ckanext/d4science_theme/public/grsf/GRSF_for_admins_logo.png differ diff --git a/ckanext/d4science_theme/public/images/groups/icon/placeholder-group.png b/ckanext/d4science_theme/public/images/groups/icon/placeholder-group.png new file mode 100644 index 0000000..1ece150 Binary files /dev/null and b/ckanext/d4science_theme/public/images/groups/icon/placeholder-group.png differ diff --git a/ckanext/d4science_theme/public/images/organisations/d4sciencelabs.png b/ckanext/d4science_theme/public/images/organisations/d4sciencelabs.png new file mode 100644 index 0000000..7d1a75e Binary files /dev/null and b/ckanext/d4science_theme/public/images/organisations/d4sciencelabs.png differ diff --git a/ckanext/d4science_theme/public/images/organisations/emodnet.png b/ckanext/d4science_theme/public/images/organisations/emodnet.png new file mode 100644 index 0000000..0724a33 Binary files /dev/null and b/ckanext/d4science_theme/public/images/organisations/emodnet.png differ diff --git a/ckanext/d4science_theme/public/images/organisations/fao.png b/ckanext/d4science_theme/public/images/organisations/fao.png new file mode 100644 index 0000000..13d5ef0 Binary files /dev/null and b/ckanext/d4science_theme/public/images/organisations/fao.png differ diff --git a/ckanext/d4science_theme/public/images/organisations/grsf.png b/ckanext/d4science_theme/public/images/organisations/grsf.png new file mode 100644 index 0000000..91ccbbb Binary files /dev/null and b/ckanext/d4science_theme/public/images/organisations/grsf.png differ diff --git a/ckanext/d4science_theme/public/images/organisations/icon/d4sciencelabs.png b/ckanext/d4science_theme/public/images/organisations/icon/d4sciencelabs.png new file mode 100644 index 0000000..e0b8d80 Binary files /dev/null and b/ckanext/d4science_theme/public/images/organisations/icon/d4sciencelabs.png differ diff --git a/ckanext/d4science_theme/public/images/organisations/icon/emodnet.png b/ckanext/d4science_theme/public/images/organisations/icon/emodnet.png new file mode 100644 index 0000000..4eb8091 Binary files /dev/null and b/ckanext/d4science_theme/public/images/organisations/icon/emodnet.png differ diff --git a/ckanext/d4science_theme/public/images/organisations/icon/fao.png b/ckanext/d4science_theme/public/images/organisations/icon/fao.png new file mode 100644 index 0000000..aa815b4 Binary files /dev/null and b/ckanext/d4science_theme/public/images/organisations/icon/fao.png differ diff --git a/ckanext/d4science_theme/public/images/organisations/icon/grsf.png b/ckanext/d4science_theme/public/images/organisations/icon/grsf.png new file mode 100644 index 0000000..4343813 Binary files /dev/null and b/ckanext/d4science_theme/public/images/organisations/icon/grsf.png differ diff --git a/ckanext/d4science_theme/public/images/organisations/icon/imarine.png b/ckanext/d4science_theme/public/images/organisations/icon/imarine.png new file mode 100644 index 0000000..9d7a311 Binary files /dev/null and b/ckanext/d4science_theme/public/images/organisations/icon/imarine.png differ diff --git a/ckanext/d4science_theme/public/images/organisations/icon/placeholder-organization.png b/ckanext/d4science_theme/public/images/organisations/icon/placeholder-organization.png new file mode 100644 index 0000000..30616f2 Binary files /dev/null and b/ckanext/d4science_theme/public/images/organisations/icon/placeholder-organization.png differ diff --git a/ckanext/d4science_theme/public/images/organisations/icon/rprototypinglab.png b/ckanext/d4science_theme/public/images/organisations/icon/rprototypinglab.png new file mode 100644 index 0000000..743f19c Binary files /dev/null and b/ckanext/d4science_theme/public/images/organisations/icon/rprototypinglab.png differ diff --git a/ckanext/d4science_theme/public/images/organisations/imarine.png b/ckanext/d4science_theme/public/images/organisations/imarine.png new file mode 100644 index 0000000..875348a Binary files /dev/null and b/ckanext/d4science_theme/public/images/organisations/imarine.png differ diff --git a/ckanext/d4science_theme/public/images/organisations/rprototypinglab.png b/ckanext/d4science_theme/public/images/organisations/rprototypinglab.png new file mode 100644 index 0000000..472294b Binary files /dev/null and b/ckanext/d4science_theme/public/images/organisations/rprototypinglab.png differ diff --git a/ckanext/d4science_theme/public/images/types/icon/codelist.png b/ckanext/d4science_theme/public/images/types/icon/codelist.png new file mode 100644 index 0000000..5cb017a Binary files /dev/null and b/ckanext/d4science_theme/public/images/types/icon/codelist.png differ diff --git a/ckanext/d4science_theme/public/images/types/icon/dataset.png b/ckanext/d4science_theme/public/images/types/icon/dataset.png new file mode 100644 index 0000000..8ded500 Binary files /dev/null and b/ckanext/d4science_theme/public/images/types/icon/dataset.png differ diff --git a/ckanext/d4science_theme/public/images/types/icon/dsd.png b/ckanext/d4science_theme/public/images/types/icon/dsd.png new file mode 100644 index 0000000..101975b Binary files /dev/null and b/ckanext/d4science_theme/public/images/types/icon/dsd.png differ diff --git a/ckanext/d4science_theme/public/images/types/icon/metadata.png b/ckanext/d4science_theme/public/images/types/icon/metadata.png new file mode 100644 index 0000000..84d395e Binary files /dev/null and b/ckanext/d4science_theme/public/images/types/icon/metadata.png differ diff --git a/ckanext/d4science_theme/public/images/types/icon/placeholder-type.png b/ckanext/d4science_theme/public/images/types/icon/placeholder-type.png new file mode 100644 index 0000000..1ca5afb Binary files /dev/null and b/ckanext/d4science_theme/public/images/types/icon/placeholder-type.png differ diff --git a/ckanext/d4science_theme/public/images/types/icon/researchobject.png b/ckanext/d4science_theme/public/images/types/icon/researchobject.png new file mode 100644 index 0000000..cab2b45 Binary files /dev/null and b/ckanext/d4science_theme/public/images/types/icon/researchobject.png differ diff --git a/ckanext/d4science_theme/public/images/types/icon/series.png b/ckanext/d4science_theme/public/images/types/icon/series.png new file mode 100644 index 0000000..573d43f Binary files /dev/null and b/ckanext/d4science_theme/public/images/types/icon/series.png differ diff --git a/ckanext/d4science_theme/public/images/types/icon/service.png b/ckanext/d4science_theme/public/images/types/icon/service.png new file mode 100644 index 0000000..54dd849 Binary files /dev/null and b/ckanext/d4science_theme/public/images/types/icon/service.png differ diff --git a/ckanext/d4science_theme/public/images/types/icon/trainingmaterial.png b/ckanext/d4science_theme/public/images/types/icon/trainingmaterial.png new file mode 100644 index 0000000..38ea713 Binary files /dev/null and b/ckanext/d4science_theme/public/images/types/icon/trainingmaterial.png differ diff --git a/ckanext/d4science_theme/public/images/types/icon/virtualresearchenvironment.png b/ckanext/d4science_theme/public/images/types/icon/virtualresearchenvironment.png new file mode 100644 index 0000000..91a8a97 Binary files /dev/null and b/ckanext/d4science_theme/public/images/types/icon/virtualresearchenvironment.png differ diff --git a/ckanext/d4science_theme/public/images/types/placeholder-type.png b/ckanext/d4science_theme/public/images/types/placeholder-type.png new file mode 100644 index 0000000..d09e87e Binary files /dev/null and b/ckanext/d4science_theme/public/images/types/placeholder-type.png differ diff --git a/ckanext/d4science_theme/public/jquery.tagcloud.js b/ckanext/d4science_theme/public/jquery.tagcloud.js new file mode 100644 index 0000000..4e5d5a3 --- /dev/null +++ b/ckanext/d4science_theme/public/jquery.tagcloud.js @@ -0,0 +1,92 @@ +/*! + * jquery.tagcloud.js + * A Simple Tag Cloud Plugin for JQuery + * + * https://github.com/addywaddy/jquery.tagcloud.js + * created by Adam Groves + */ +(function($) { + + /*global jQuery*/ + "use strict"; + + var compareWeights = function(a, b) + { + return a - b; + }; + + // Converts hex to an RGB array + var toRGB = function(code) { + if (code.length === 4) { + code = code.replace(/(\w)(\w)(\w)/gi, "\$1\$1\$2\$2\$3\$3"); + } + var hex = /(\w{2})(\w{2})(\w{2})/.exec(code); + return [parseInt(hex[1], 16), parseInt(hex[2], 16), parseInt(hex[3], 16)]; + }; + + // Converts an RGB array to hex + var toHex = function(ary) { + return "#" + jQuery.map(ary, function(i) { + var hex = i.toString(16); + hex = (hex.length === 1) ? "0" + hex : hex; + return hex; + }).join(""); + }; + + var colorIncrement = function(color, range) { + return jQuery.map(toRGB(color.end), function(n, i) { + return (n - toRGB(color.start)[i])/range; + }); + }; + + var tagColor = function(color, increment, weighting) { + var rgb = jQuery.map(toRGB(color.start), function(n, i) { + var ref = Math.round(n + (increment[i] * weighting)); + if (ref > 255) { + ref = 255; + } else { + if (ref < 0) { + ref = 0; + } + } + return ref; + }); + return toHex(rgb); + }; + + $.fn.tagcloud = function(options) { + + var opts = $.extend({}, $.fn.tagcloud.defaults, options); + var tagWeights = this.map(function(){ + return $(this).attr("rel"); + }); + tagWeights = jQuery.makeArray(tagWeights).sort(compareWeights); + var lowest = tagWeights[0]; + var highest = tagWeights.pop(); + var range = highest - lowest; + if(range === 0) {range = 1;} + // Sizes + var fontIncr, colorIncr; + if (opts.size) { + fontIncr = (opts.size.end - opts.size.start)/range; + } + // Colors + if (opts.color) { + colorIncr = colorIncrement (opts.color, range); + } + return this.each(function() { + var weighting = $(this).attr("rel") - lowest; + if (opts.size) { + $(this).css({"font-size": opts.size.start + (weighting * fontIncr) + opts.size.unit}); + } + if (opts.color) { + $(this).css({"color": tagColor(opts.color, colorIncr, weighting)}); + } + }); + }; + + $.fn.tagcloud.defaults = { + size: {start: 14, end: 18, unit: "pt"} + }; + +})(jQuery); diff --git a/ckanext/d4science_theme/public/location_to_bboxes.ini b/ckanext/d4science_theme/public/location_to_bboxes.ini new file mode 100644 index 0000000..e7f14c2 --- /dev/null +++ b/ckanext/d4science_theme/public/location_to_bboxes.ini @@ -0,0 +1,16 @@ +[location_to_bboxes_epsg_4326] +Antarctica=-180,-90,180,-63.2706604895 +Brazil=-73.9872354804,-33.7683777809,-34.7299934555,5.24448639569 +France=-54.5247541978,2.05338918702,9.56001631027,51.1485061713 +Greece=20.1500159034,34.9199876979,26.6041955909,41.8269046087 +Italy=6.7499552751,36.619987291,18.4802470232,47.1153931748 +Ivory Coast=-8.60288021487,4.33828847902,-2.56218950033,10.5240607772 +Mexico=-117.12776,14.5388286402,-86.811982388,32.72083 +Nigeria=2.69170169436,4.24059418377,14.5771777686,13.8659239771 +Philippines=117.17427453,5.58100332277,126.537423944,18.5052273625 +Portugal=-9.52657060387,36.838268541,-6.3890876937,42.280468655 +Puerto Rico=-67.2424275377,17.946553453,-65.5910037909,18.5206011011 +Slovenia=13.6981099789,45.4523163926,16.5648083839,46.8523859727 +Thailand=97.3758964376,5.69138418215,105.589038527,20.4178496363 +United Kingdom=-7.57216793459,49.959999905,1.68153079591,58.6350001085 +United States=-171.791110603,18.91619,-66.96466,71.3577635769 \ No newline at end of file diff --git a/ckanext/d4science_theme/public/oai2_style.xsl b/ckanext/d4science_theme/public/oai2_style.xsl new file mode 100644 index 0000000..2a41373 --- /dev/null +++ b/ckanext/d4science_theme/public/oai2_style.xsl @@ -0,0 +1,690 @@ + + + + + + + + + + + + + + + +td.value { + vertical-align: top; + padding-left: 1em; + padding: 3px; +} +td.key { + background-color: #e0e0ff; + padding: 3px; + text-align: right; + border: 1px solid #c0c0c0; + white-space: nowrap; + font-weight: bold; + vertical-align: top; +} +.dcdata td.key { + background-color: #ffffe0; +} +body { + margin: 1em 2em 1em 2em; +} +h1, h2, h3 { + font-family: sans-serif; + clear: left; +} +h1 { + padding-bottom: 2px; + margin-bottom: 0px; +} +h2 { + margin-bottom: 0.5em; +} +h3 { + margin-bottom: 0.3em; + font-size: medium; +} + +h5 { + color: gray; + font-size: 12px; + margin: 0; + padding-top: 5px; +} + +.about-xsl { + font-size: 12px; + font-family: "Arial"; + color: gray; +} + +.link { + border: 1px outset #88f; + background-color: #c0c0ff; + padding: 1px 4px 1px 4px; + font-size: 80%; + text-decoration: none; + font-weight: bold; + font-family: sans-serif; + color: black; +} +.link:hover { + color: red; +} +.link:active { + color: red; + border: 1px inset #88f; + background-color: #a0a0df; +} +.oaiRecord, .oaiRecordTitle { + background-color: #f0f0ff; + border-style: solid; + border-color: #d0d0d0; +} +h2.oaiRecordTitle { + background-color: #e0e0ff; + font-size: medium; + font-weight: bold; + padding: 10px; + border-width: 2px 2px 0px 2px; + margin: 0px; +} +.oaiRecord { + margin-bottom: 3em; + border-width: 2px; + padding: 10px; +} + +.results { + margin-bottom: 1.5em; +} +ul.quicklinks { + margin-top: 3px; + padding: 4px; + text-align: left; + border-bottom: 1px solid #ccc; + border-top: 1px solid #ccc; + clear: left; + list-style-type: none; +} +ul.quicklinks li { + font-size: 80%; + #display: inline; + list-stlye: none; + font-family: sans-serif; + padding-left: 12px; +} + +.oai-footer{ + border-top: 1px solid #ccc; +} + +p.intro { + font-size: 12px; + font-family: "Arial"; + color: gray; +} + + + + + + + + + OAI 2.0 Request Results + + + +

OAI 2.0 Request Results

+

You are viewing an HTML version of the XML OAI response. More information about this XSLT.
Return to OAI-PMH 2.0 Home for this Repository

+ + + + + +
+ + +
OAI-PMH Requests:
+ +
+ + + + + + + + + + + + + + +
Datestamp of response
Request URL
+ + + +

OAI Error(s)

+

The request could not be completed due to the following error or errors.

+
+ +
+
+ +

Request was of type:

+
+ + + + + + +
+
+
+
+ + + + + + + + +
Error Code
+

+
+ + + + + + + + + + + + + + + + + + +
Repository Name
Base URL
Protocol Version
Earliest Datestamp
Deleted Record Policy
Granularity
+ + +
+ + + Admin Email + + + + + + +

Unsupported Description Type

+

The XSL currently does not support this type of description.

+
+ +
+
+ + + + + +

OAI-Identifier

+ + + + + + + + + +
Scheme
Repository Identifier
Delimiter
Sample OAI Identifier
+
+ + + + + +

EPrints Description

+

Content

+ + +

Submission Policy

+ +
+

Metadata Policy

+ +

Data Policy

+ + +

Content

+ +
+ +
+ + + +

+
+ +
+
+
+ + +

Comment

+
+
+ + + + + +

Friends

+
    + +
+
+ + +
  • + +Identify
  • +
    + + + + + +

    Branding

    + + +
    + + +

    Icon

    + + + {br:title} + + + {br:title} + + +
    + + +

    Metadata Rendering Rule

    + + + + + + + +
    URL
    Namespace
    Mime Type
    +
    + + + + + + +

    Gateway Information

    + + + + + + + + + + + + + + +
    Source
    Description
    URL
    Notes
    +
    + + + Admin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Set

    + + + + +
    setName
    +
    + + + + + + +

    This is a list of metadata formats available for the record "". Use these links to view the metadata:

    +
    + +

    This is a list of metadata formats available from this archive.

    +
    +
    + +
    + + +

    Metadata Format

    + + + + + + + +
    metadataPrefix
    metadataNamespace
    schema
    +
    + + + + + + + + +

    OAI Record:

    +
    + + + +
    +
    + + +

    OAI Record Header

    + + + + + + +
    OAI Identifier + + oai_dc + rdf +
    Datestamp
    + +

    This record has been deleted.

    +
    +
    + + + +

    "about" part of record container not supported by the XSL

    +
    + + +   + + + + + + + + + + setSpec + + Identifiers + Records + + + + + + + + +

    There are more results.

    + + + +
    resumptionToken: + +Resume
    +
    + + + + +

    Unknown Metadata Format

    +
    + +
    +
    + + + + +
    +

    Dublin Core Metadata (oai_dc)

    + + +
    +
    +
    + + +Title + + +Author or Creator + + +Subject and Keywords + + +Description + + +Publisher + + +Other Contributor + + +Date + + +Resource Type + + +Format + + +Resource Identifier + + +Source + + +Language + + +Relation + + + + + URL + URL not shown as it is very long. + + + + + + + + + + + + + +Coverage + + +Rights Management + + + + +
    + <></> +
    +
    + + + + + ="" + + + +.xmlSource { + font-size: 70%; + border: solid #c0c0a0 1px; + background-color: #ffffe0; + padding: 2em 2em 2em 0em; +} +.xmlBlock { + padding-left: 2em; +} +.xmlTagName { + color: #800000; + font-weight: bold; +} +.xmlAttrName { + font-weight: bold; +} +.xmlAttrValue { + color: #0000c0; +} + + +
    + diff --git a/ckanext/d4science_theme/public/pageloading.gif b/ckanext/d4science_theme/public/pageloading.gif new file mode 100644 index 0000000..ea92a4c Binary files /dev/null and b/ckanext/d4science_theme/public/pageloading.gif differ diff --git a/ckanext/d4science_theme/public/parthenos/logo-parthenos.png b/ckanext/d4science_theme/public/parthenos/logo-parthenos.png new file mode 100644 index 0000000..7fd8e9b Binary files /dev/null and b/ckanext/d4science_theme/public/parthenos/logo-parthenos.png differ diff --git a/ckanext/d4science_theme/public/placeholder_types.png b/ckanext/d4science_theme/public/placeholder_types.png new file mode 100644 index 0000000..cc33636 Binary files /dev/null and b/ckanext/d4science_theme/public/placeholder_types.png differ diff --git a/ckanext/d4science_theme/qrcodelink/__init__.py b/ckanext/d4science_theme/qrcodelink/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ckanext/d4science_theme/qrcodelink/generate_qrcode.py b/ckanext/d4science_theme/qrcodelink/generate_qrcode.py new file mode 100644 index 0000000..1909226 --- /dev/null +++ b/ckanext/d4science_theme/qrcodelink/generate_qrcode.py @@ -0,0 +1,80 @@ +import os +import tempfile +import logging +import pyqrcode +import time + +# Created by Francesco Mangiacrapa +# francesco.mangiacrapa@isti.cnr.it +# ISTI-CNR Pisa (ITALY) + +CATALINA_HOME = 'CATALINA_HOME' +log = logging.getLogger(__name__) + +temp_dir = None +qr_code_dir = None +qr_code_dir_name = "qr_code_for_catalogue" + + +class D4S_QrCode(): + def __init__(self, qr_code_url=None): + self._qr_code_url = qr_code_url + global temp_dir + if temp_dir is None: + D4S_QrCode.init_temp_dir() + if temp_dir is None: + raise Exception('No temp directory found!') + + def get_qrcode_path(self): + image_name = self._qr_code_url.rsplit('/', 1)[-1] + image_name+=".svg" + image_path = os.path.join(qr_code_dir, image_name) + # ONLY IF QRCODE DOES NOT EXIST THEN IT WILL BE CREATED + if not os.path.isfile(image_path): + url = pyqrcode.create(self._qr_code_url) + url.svg(image_path, scale=3) + log.debug("Created QRCode image: " + image_name) + + attempt = 0 + while not os.path.exists(image_path) and attempt < 3: + time.sleep(1) + attempt += 1 + + if os.path.isfile(image_path): + log.info("QRcode image exists at: " + image_path) + else: + log.error("%s isn't a file!" % image_path) + + return image_path + + @classmethod + def init_temp_dir(cls): + global temp_dir + global qr_code_dir_name + global qr_code_dir + try: + temp_dir = str(os.environ[CATALINA_HOME]) + temp_dir = os.path.join(temp_dir, "temp") + except KeyError as error: + log.error("No environment variable for: %s" % CATALINA_HOME) + + if temp_dir is None: + temp_dir = tempfile.gettempdir() # using system tmp dir + + log.debug("Temp dir is: %s" % temp_dir) + + qr_code_dir = os.path.join(temp_dir, qr_code_dir_name) + + if not os.path.exists(qr_code_dir): + os.makedirs(qr_code_dir) + + def get_temp_directory(self): + return temp_dir + + def get_qr_code_dir(self): + return qr_code_dir + + +# D4S_QrCode.init_temp_dir() +#qr_code = D4S_QrCode("http://data.d4science.org/ctlg/BiodiversityLab/distribution_of_the_giant_squid_architeuthis") +#print qr_code.get_qrcode_path() diff --git a/ckanext/d4science_theme/templates/.gitignore b/ckanext/d4science_theme/templates/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/ckanext/d4science_theme/templates/base.html b/ckanext/d4science_theme/templates/base.html new file mode 100644 index 0000000..6cc7bc0 --- /dev/null +++ b/ckanext/d4science_theme/templates/base.html @@ -0,0 +1,201 @@ +{# Allows the DOCTYPE to be set on a page by page basis #} +{%- block doctype %}{% endblock -%} + +{# Allows custom attributes to be added to the tag #} +{%- block htmltag -%} +{% set lang = h.lang() %} + + + + +{%- endblock -%} + +{# Added by Francesco Mangiacrapa see #12286 #} +{% set my_search_string = "msgid \"Groups\"" %} +{% set translating_groups = h.d4science_get_ckan_translate_for(my_file, my_search_string) %} +{% set my_search_string = "msgid \"Datasets\"" %} +{% set translating_datasets = h.d4science_get_ckan_translate_for(my_file, my_search_string) %} +{% set my_search_string = "msgid \"Organizations\"" %} +{% set translating_organizations = h.d4science_get_ckan_translate_for(my_file, my_search_string) %} +{% set my_search_string = "msgid \"Types\"" %} +{% set translating_types = h.d4science_get_ckan_translate_for(my_file, my_search_string) %} + + {# Allows custom attributes to be added to the tag #} + + {# + Add custom meta tags to the page. Call super() to get the default tags + such as charset, viewport and generator. + + Example: + + {% block meta %} + {{ super() }} + + {% endblock %} + + #} + {%- block meta -%} + + {% block meta_generator %}{% endblock %} + {% block meta_viewport %}{% endblock %} + {%- endblock -%} + + {# + Add a custom title to the page by extending the title block. Call super() + to get the default page title. + + Example: + + {% block title %}My Subtitle - {{ super() }}{% endblock %} + + #} + + {%- block title -%} + {%- block subtitle %}{% endblock -%} + {%- if self.subtitle()|trim %} {{ g.template_title_deliminater }} {% endif -%} + {{ g.site_title }} + {%- endblock -%} + + + + + {# + The links block allows you to add additonal content before the stylesheets + such as rss feeds and favicons in the same way as the meta block. + #} + {% block links -%} + + + {% endblock -%} + + {# + The styles block allows you to add additonal stylesheets to the page in + the same way as the meta block. Use super() to include the default + stylesheets before or after your own. + + Example: + + {% block styles %} + {{ super() }} + + {% endblock %} + #} + + {% block styles %} + {% resource g.main_css[6:] %} + {# Import d4science_theme.css using Fanstatic. + 'example_theme/' is the name that the example_theme/fanstatic directory + was registered with when the toolkit.add_resource() function was called. + 'example_theme.css' is the path to the CSS file, relative to the root of + the fanstatic directory. #} + {% resource 'd4science_theme/d4science_theme.css' %} + {% resource 'd4science_theme/d4science_scripts.js' %} + {# Importing font-awesome.min.css #} + {% endblock %} + + {% block head_extras %} + {# defined in the config.ini under "ckan.template_head_end" #} + {{ g.template_head_end | safe }} + {% endblock %} + + {%- block custom_styles %} + {%- if g.site_custom_css -%} + + {%- endif %} + {% endblock %} + + + + {# Allows custom attributes to be added to the tag #} + +
    + {# + The page block allows you to add content to the page. Most of the time it is + recommended that you extend one of the page.html templates in order to get + the site header and footer. If you need a clean page then this is the + block to use. + + Example: + + {% block page %} +
    Some other page content
    + {% endblock %} + #} + {%- block page %}{% endblock -%} + + {# + DO NOT USE THIS BLOCK FOR ADDING SCRIPTS + Scripts should be loaded by the {% resource %} tag except in very special + circumstances + #} + {%- block scripts %} + {% endblock -%} + + {% block body_extras -%} + {# defined in the config.ini under "ckan.template_footer_end" #} + {{ g.template_footer_end | safe }} + {%- endblock %} + + + diff --git a/ckanext/d4science_theme/templates/footer.html b/ckanext/d4science_theme/templates/footer.html new file mode 100644 index 0000000..f149c21 --- /dev/null +++ b/ckanext/d4science_theme/templates/footer.html @@ -0,0 +1,20 @@ +{% block header_hide_container_content %} +{% set hideParameter = h.get_request_param('hh', None) %} +{% set hide = h.get_cookie_value('ckan_hide_header') %} +
    +{% if hide=='true' %} +{# Updated and unified the footer, see #18126 #} +
    +gCube Catalogue powered by CKAN + |  +Access this catalogue using the gCat APIs +
    +{% else %} +
    +gCube Catalogue powered by CKAN + |  +Access this catalogue using the gCat APIs +
    +{% endif %} +
    +{% endblock %} diff --git a/ckanext/d4science_theme/templates/group/read_base.html b/ckanext/d4science_theme/templates/group/read_base.html new file mode 100644 index 0000000..6e29fae --- /dev/null +++ b/ckanext/d4science_theme/templates/group/read_base.html @@ -0,0 +1,35 @@ +{% extends "page.html" %} + +{% block subtitle %}{{ c.group_dict.display_name }} - {{ _('Groups') }}{% endblock %} + +{% block breadcrumb_content %} +
  • {% link_for _('Groups'), controller='group', action='index' %}
  • +
  • {% link_for c.group_dict.display_name|truncate(35), controller='group', action='read', id=c.group_dict.name %}
  • +{% endblock %} + +{% block content_action %} + {% if h.check_access('group_update', {'id': c.group_dict.id}) %} + {% link_for _('Manage'), controller='group', action='edit', id=c.group_dict.name, class_='btn', icon='wrench' %} + {% endif %} +{% endblock %} + +{% block content_primary_nav %} + {{ h.build_nav_icon('group_read', _('Datasets'), id=c.group_dict.name) }} + + {% if h.check_access('group_update', {'id': c.group_dict.id}) %} + {% set role_for_user = h.d4science_theme_get_user_role_for_group_or_org(c.group_dict.id, c.userobj.name) %} + {% if (role_for_user and role_for_user == 'admin') or c.userobj.sysadmin %} + {{ h.build_nav_icon('group_activity', _('Activity Stream'), id=c.group_dict.name, offset=0) }} + {% endif %} + {% endif %} + {{ h.build_nav_icon('group_about', _('About'), id=c.group_dict.name) }} +{% endblock %} + +{% block secondary_content %} + {% snippet "group/snippets/info.html", group=c.group_dict, show_nums=true %} +{% endblock %} + +{% block links %} + {{ super() }} + {% include "group/snippets/feeds.html" %} +{% endblock %} diff --git a/ckanext/d4science_theme/templates/group/snippets/group_form.html b/ckanext/d4science_theme/templates/group/snippets/group_form.html new file mode 100644 index 0000000..e126fca --- /dev/null +++ b/ckanext/d4science_theme/templates/group/snippets/group_form.html @@ -0,0 +1,107 @@ +{% import 'macros/form.html' as form %} + +{# SCRIPT ADDED BY FRACESCO MANGIACRAPA, SEE 20425 #} + + +
    + {% block error_summary %} + {{ form.errors(error_summary) }} + {% endblock %} + + {% block basic_fields %} + {% set attrs = {'data-module': 'slug-preview-target'} %} + {# DIV ADDED BY FRACESCO MANGIACRAPA, SEE 20425 #} +
    + {{ form.input('title', label=_('Name'), id='field-name', placeholder=_('My Group'), value=data.title, error=errors.title, classes=['control-full'], attrs=attrs) }} +
    + {# Perhaps these should be moved into the controller? #} + {% set prefix = h.url_for(controller='group', action='read', id='') %} + {% set domain = h.url_for(controller='group', action='read', id='', qualified=true) %} + {% set domain = domain|replace("http://", "")|replace("https://", "") %} + {% set attrs = {'data-module': 'slug-preview-slug', 'data-module-prefix': domain, 'data-module-placeholder': ''} %} + + {# CODE ADDED BY FRACESCO MANGIACRAPA, SEE 20425 #} + {% set hide = h.get_cookie_value('ckan_hide_header') %} + {% if hide=='true' %} + + {% endif %} + + {{ form.prepend('name', label=_('URL'), prepend=prefix, id='field-url', placeholder=_('my-group'), value=data.name, error=errors.name, attrs=attrs, is_required=true) }} + + {{ form.markdown('description', label=_('Description'), id='field-description', placeholder=_('A little information about my group...'), value=data.description, error=errors.description) }} + + {% set is_upload = data.image_url and not data.image_url.startswith('http') %} + {% set is_url = data.image_url and data.image_url.startswith('http') %} + + {{ form.image_upload(data, errors, is_upload_enabled=h.uploads_enabled(), is_url=is_url, is_upload=is_upload) }} + + {% endblock %} + + {% block custom_fields %} + {% for extra in data.extras %} + {% set prefix = 'extras__%d__' % loop.index0 %} + {{ form.custom( + names=(prefix ~ 'key', prefix ~ 'value', prefix ~ 'deleted'), + id='field-extras-%d' % loop.index, + label=_('Custom Field'), + values=(extra.key, extra.value, extra.deleted), + error=errors[prefix ~ 'key'] or errors[prefix ~ 'value'] + ) }} + {% endfor %} + + {# Add a max if 3 empty columns #} + {% for extra in range(data.extras|count, 3) %} + {% set index = (loop.index0 + data.extras|count) %} + {% set prefix = 'extras__%d__' % index %} + {{ form.custom( + names=(prefix ~ 'key', prefix ~ 'value', prefix ~ 'deleted'), + id='field-extras-%d' % index, + label=_('Custom Field'), + values=(extra.key, extra.value, extra.deleted), + error=errors[prefix ~ 'key'] or errors[prefix ~ 'value'] + ) }} + {% endfor %} + {% endblock %} + + {{ form.required_message() }} + +
    + {% block delete_button %} + {% if h.check_access('group_delete', {'id': data.id}) %} + {% set locale = h.dump_json({'content': _('Are you sure you want to delete this Group?')}) %} + {% block delete_button_text %}{{ _('Delete') }}{% endblock %} + {% endif %} + {% endblock %} + +
    + \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/group/snippets/group_item.html b/ckanext/d4science_theme/templates/group/snippets/group_item.html new file mode 100644 index 0000000..3f9e5ad --- /dev/null +++ b/ckanext/d4science_theme/templates/group/snippets/group_item.html @@ -0,0 +1,65 @@ +{# +Renders a media item for a group. This should be used in a list. + +group - A group dict. + +Example: + +
      + {% for group in groups %} + {% snippet "group/snippets/group_item.html", group=group %} + {% endfor %} +
    +#} + + +{# Updated By Francesco Mangiacrapa, related to breadcrumb for Group #} +{% set type = group.type or 'group' %} +{% set url = h.url_for(type ~ '_read', action='read', id=group.name) %} +{% block item %} +
  • + {% block breadcrumb %} +
    + {% set parents = h.d4science_theme_get_parents_for_group(group.name) %} + {% for parent in parents recursive %} + + {% link_for parent.title, controller='group', action='read', id=parent.name %} + {% if loop.last == False %} + {% endif %} + + {% endfor %} +
    + {% endblock %} + {% block item_inner %} + {% block image %} + {{ group.name }} + {% endblock %} + {% block title %} +

    {{ group.display_name }}

    + {% endblock %} + {% block description %} + {% if group.description %} +

    {{ h.d4science_theme_markdown_extract_html(group.description, extract_length=80, allow_html=True) }}

    + {% endif %} + {% endblock %} + {% block datasets %} + {% if group.package_count %} + {{ ungettext('{num} Dataset', '{num} Datasets', group.package_count).format(num=group.package_count) }} + {% elif group.package_count == 0 %} + + {% endif %} + {% endblock %} + {% if group.user_member %} + {# Added By Francesco Mangiacrapa, related to Task #5196 #} + {% set username_id = c.userobj.id %} + {% set role_for_user = h.d4science_theme_get_user_role_for_group_or_org(group.id, username_id) %} + {% if role_for_user and role_for_user == 'admin' %} + + {% endif %} + {% endif %} + {% endblock %} +
  • +{% endblock %} +{% if position is divisibleby 3 %} +
  • +{% endif %} diff --git a/ckanext/d4science_theme/templates/group/snippets/group_list.html b/ckanext/d4science_theme/templates/group/snippets/group_list.html new file mode 100644 index 0000000..ab7e73e --- /dev/null +++ b/ckanext/d4science_theme/templates/group/snippets/group_list.html @@ -0,0 +1,60 @@ +{# CREATED BY FRANCESCO MANGIACRAPA +Display a grid of group items. + +groups - A list of groups. + +Example: + + {% snippet "group/snippets/group_list.html" %} + +#} + + + +{# +Display a hierarchical tree of groups + + +Example: + + {% snippet "group/snippets/group_tree.html" %} + +#} + +{# CKAN 2.6.X #} +{% set top_nodes = h.group_tree(type_='group') %} +{# CKAN 2.5.X +{% set top_nodes=h.get_action('group_tree', {'type': 'group'}) %} +#} + + + +{% block group_list %} +
      + {% block group_list_inner %} + {% for group in groups %} + {% snippet "group/snippets/group_item.html", group=group, position=loop.index, top_nodes=top_nodes %} + {% endfor %} + {% endblock %} +
    +{% endblock %} diff --git a/ckanext/d4science_theme/templates/group/snippets/group_list_simple.html b/ckanext/d4science_theme/templates/group/snippets/group_list_simple.html new file mode 100644 index 0000000..7dcfe47 --- /dev/null +++ b/ckanext/d4science_theme/templates/group/snippets/group_list_simple.html @@ -0,0 +1,20 @@ +{# ADDED BY FRANCESCO MANGIACRAPA IT'S CALLED BY + snippet 'package/group_list.html', groups=c.pkg_dict.groups +Display a grid of group items. + +groups - A list of groups. + +Example: + + {% snippet "group/snippets/group_list_simple.html" %} + +#} +{% block group_list %} +
      + {% block group_list_inner %} + {% for group in groups %} + {% snippet "group/snippets/group_item.html", group=group, position=loop.index %} + {% endfor %} + {% endblock %} +
    +{% endblock %} diff --git a/ckanext/d4science_theme/templates/group/snippets/group_tree.html b/ckanext/d4science_theme/templates/group/snippets/group_tree.html new file mode 100644 index 0000000..233bde2 --- /dev/null +++ b/ckanext/d4science_theme/templates/group/snippets/group_tree.html @@ -0,0 +1,32 @@ +{# +Displays a tree of organzations + +NB This template can be slow because it is recursive and uses link_for. At +DGU we speeded up display of the tree 10 times (necessary as we have 1000 +organizations) by replacing this template with a recursive code routine: +https://github.com/datagovuk/ckanext-dgu/blob/5fb78b354517c2198245bdc9c98fb5d6c82c6bcc/ckanext/dgu/lib/helpers.py#L140 + +orgs - List of organizations + +Example: + + {% snippet 'group/snippets/group_tree.html', top_nodes=h.get_action('group_tree', {'type': 'group'}) %} + +#} +
      + {% for node in top_nodes recursive %} +
    • + {% if node.highlighted %} + + {% endif %} + {% link_for node.title, controller='group', action='read', id=node.name %} + {% if node.highlighted %} + + {% endif %} + + {% if node.children %} +
        {{ loop(node.children) }}
      + {% endif %} +
    • + {% endfor %} +
    diff --git a/ckanext/d4science_theme/templates/header.html b/ckanext/d4science_theme/templates/header.html new file mode 100644 index 0000000..521696b --- /dev/null +++ b/ckanext/d4science_theme/templates/header.html @@ -0,0 +1,141 @@ +{# FOLLOWING BLOCK IS ADDED BY FRANCESCO MANGIACRAPA #} +{% block header_hide_container_content %} +{% set hide = h.get_cookie_value('ckan_hide_header') %} +{% if hide=='true' %} + {# HIDE HEADER #} +{% else %} +{% block header_wrapper %} +{% block header_account %} + + +{% endblock %} + +{% endblock %} +{% endif %} +{% endblock %} \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/home/index.html b/ckanext/d4science_theme/templates/home/index.html new file mode 100644 index 0000000..4e308a5 --- /dev/null +++ b/ckanext/d4science_theme/templates/home/index.html @@ -0,0 +1 @@ +{% ckan_extends %} \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/home/layout2.html b/ckanext/d4science_theme/templates/home/layout2.html new file mode 100644 index 0000000..047d6aa --- /dev/null +++ b/ckanext/d4science_theme/templates/home/layout2.html @@ -0,0 +1,108 @@ + + + + +
    +
    +
    + {% block promoted %} + {% snippet 'home/snippets/promoted.html' %} + {% endblock %} +
    +
    +
    + +
    +
    +
    +
    + {% block search %} + {% snippet 'home/snippets/search.html' %} + {% endblock %} +
    +
    + {% block stats %} + {% snippet 'home/snippets/stats.html' %} + {% endblock %} +
    +
    +
    +
    + + + + + +{% block search_for_organizations %} +{# Added by Francesco Mangiacrapa, see: #8964 #} + + + {% snippet 'home/snippets/search_for_organisations.html' %} +{% endblock %} + +{% block search_for_groups %} + {% snippet 'home/snippets/search_for_groups.html' %} +{% endblock %} + +{% block search_for_types %} + {% snippet 'home/snippets/search_for_types.html' %} +{% endblock %} + + +{# + {% block search_for_location %} + {% snippet 'home/snippets/search_for_location.html' %} + {% endblock %} + +#} + + + + + diff --git a/ckanext/d4science_theme/templates/home/snippets/featured_organization.html b/ckanext/d4science_theme/templates/home/snippets/featured_organization.html new file mode 100644 index 0000000..7cf9ddb --- /dev/null +++ b/ckanext/d4science_theme/templates/home/snippets/featured_organization.html @@ -0,0 +1,7 @@ +{% set organizations = h.get_featured_organizations() %} + +{% for organization in organizations %} +
    + {% snippet 'snippets/organization_item.html', organization=organization, truncate=50, truncate_title=35 %} +
    +{% endfor %} diff --git a/ckanext/d4science_theme/templates/home/snippets/popular_formats.html b/ckanext/d4science_theme/templates/home/snippets/popular_formats.html new file mode 100644 index 0000000..525ab89 --- /dev/null +++ b/ckanext/d4science_theme/templates/home/snippets/popular_formats.html @@ -0,0 +1,27 @@ +{% set formats = h.get_facet_items_dict('res_format', limit=30) %} + +
    +

    Popular Formats

    +
    + + {% for tag in formats %} + {% set weight = 30 - loop.index %} + {{ h.truncate(tag.display_name, 26) }} + {% endfor %} +
    +
    + + \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/home/snippets/popular_groups.html b/ckanext/d4science_theme/templates/home/snippets/popular_groups.html new file mode 100644 index 0000000..a5d99e1 --- /dev/null +++ b/ckanext/d4science_theme/templates/home/snippets/popular_groups.html @@ -0,0 +1,25 @@ +{% set groups = h.get_facet_items_dict('groups', limit=30) %} + +
    +

    Popular Groups

    +
    + {% for group in groups %} + {% set weight = 30 - loop.index %} + {{ h.truncate(group.display_name, 26) }} + {% endfor %} +
    +
    + + \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/home/snippets/popular_metadatatypes.html b/ckanext/d4science_theme/templates/home/snippets/popular_metadatatypes.html new file mode 100644 index 0000000..5220af2 --- /dev/null +++ b/ckanext/d4science_theme/templates/home/snippets/popular_metadatatypes.html @@ -0,0 +1,31 @@ +{% set metadatatype = h.d4science_theme_get_systemtype_field_dict_from_session() %} +{% set metadatatypes = h.get_facet_items_dict(metadatatype['name'], limit=30) %} + + + + +
    +

    Popular {{ metadatatype['title'].capitalize() }}s

    +
    + {% for type in metadatatypes %} + {% set weight = 30 - loop.index %} + {{ h.truncate(type.display_name, 26) }} + {% endfor %} +
    +
    + + diff --git a/ckanext/d4science_theme/templates/home/snippets/popular_tags.html b/ckanext/d4science_theme/templates/home/snippets/popular_tags.html new file mode 100644 index 0000000..c9dc22e --- /dev/null +++ b/ckanext/d4science_theme/templates/home/snippets/popular_tags.html @@ -0,0 +1,30 @@ +{% set tags = h.get_facet_items_dict('tags', limit=30) %} + +
    +

    {{ _('Popular Tags') }}

    +
    + + {% for tag in tags %} + {% set weight = 30 - loop.index %} + {{ h.truncate(tag.display_name, 26) }} + {% endfor %} +
    +

    + See All {{_('Tags')}} +

    +
    + + \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/home/snippets/promoted.html b/ckanext/d4science_theme/templates/home/snippets/promoted.html new file mode 100644 index 0000000..ab4dcd3 --- /dev/null +++ b/ckanext/d4science_theme/templates/home/snippets/promoted.html @@ -0,0 +1,27 @@ +{% set intro = g.site_intro_text %} + +
    +
    + {% if intro %} + {{ h.render_markdown(intro) }} + {% else %} + {% block home_image %} + + {% endblock %} +
    +

    Welcome to the {{g.site_title}}!

    +

    +Here you will find data and other resources hosted by the D4Science.org infrastructure.

    +

    The catalogue contains a wealth of resources resulting from several activities, projects and communities including BlueBRIDGE (www.bluebridge-vres.eu), i-Marine (www.i-marine.eu), SoBigData.eu (www.sobigdata.eu), and (FAO www.fao.org). +

    +

    All the products are accompanied with rich descriptions capturing general attributes, e.g. title and creator(s), as well as usage policies and licences.

    +
    + {% endif %} +
    +
    diff --git a/ckanext/d4science_theme/templates/home/snippets/search.html b/ckanext/d4science_theme/templates/home/snippets/search.html new file mode 100644 index 0000000..f142228 --- /dev/null +++ b/ckanext/d4science_theme/templates/home/snippets/search.html @@ -0,0 +1,25 @@ +{#{% set tags = h.get_facet_items_dict('tags', limit=3) %}#} +{% set placeholder = _('Insert keywords here') %} + + diff --git a/ckanext/d4science_theme/templates/home/snippets/search_for_groups.html b/ckanext/d4science_theme/templates/home/snippets/search_for_groups.html new file mode 100644 index 0000000..6f31bfd --- /dev/null +++ b/ckanext/d4science_theme/templates/home/snippets/search_for_groups.html @@ -0,0 +1,35 @@ +{% set groups = h.d4science_get_browse_info_for_organisations_or_groups(type='group', limit=10) %} +{% set type = 'group' %} +{% if groups|length > 0 %} +
    +
    +

    Browse by {{_('Groups')}}

    + +
    + + {% for index in range(0,groups|length) %} + {% set offset = 5 %} + {% set group = groups[index] %} + {% if index % offset == 0 %} + + {% endif %} + + {% if (index+offset+1) % offset == 0 %} + + {% endif %} + {% endfor %} +
    + {% set url = h.url_for(type ~ '_read', action='read', id=group['name']) %} + + + {{ group['name'] }} +

    {{ group['display_name'] }} ({{group['package_count']}})

    +
    +
    +
    +

    + See All {{_('Groups')}} +

    +
    +
    +{% endif %} \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/home/snippets/search_for_location.html b/ckanext/d4science_theme/templates/home/snippets/search_for_location.html new file mode 100644 index 0000000..a04f7d3 --- /dev/null +++ b/ckanext/d4science_theme/templates/home/snippets/search_for_location.html @@ -0,0 +1,44 @@ +{% set alternative_url_dataset = h.url_for(controller='package', action='search') %} +{% set locations = h.d4science_get_location_to_bboxes() %} +
    +
    +

    Browse by Location Extent

    +
    + + {% set offset = 5 %} + {% for key, value in locations.items() %} + {% set index = loop.index0 %} + {% if index % offset == 0 %} + + {% endif %} + + {% if (index+offset+1) % offset == 0 %} + + {% endif %} + {% endfor %} +
    + {% set loc = key %} + {% set bbox = value %} + + {{ loc }} +
    +
    +
    + {# ADDED BY FRANCESCO MANGIACRAPA SEE #12651 #} + {% snippet 'spatial/snippets/spatial_query.html', alternative_url=alternative_url_dataset %} + {# END #} +
    +
    + +
    \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/home/snippets/search_for_organisations.html b/ckanext/d4science_theme/templates/home/snippets/search_for_organisations.html new file mode 100644 index 0000000..65b8acb --- /dev/null +++ b/ckanext/d4science_theme/templates/home/snippets/search_for_organisations.html @@ -0,0 +1,33 @@ +{% set organizations = h.d4science_get_browse_info_for_organisations_or_groups(type='organization', limit=10) %} +{% set type = 'organization' %} +{% if organizations|length > 1 %} +
    +
    +

    Browse by {{_('Organizations')}}

    +
    + + {% for index in range(0,organizations|length) %} + {% set offset = 5 %} + {% set organization = organizations[index] %} + {% if index % offset == 0 %} + + {% endif %} + + {% if (index+offset+1) % offset == 0 %} + + {% endif %} + {% endfor %} +
    + {% set url = h.url_for(type ~ '_read', action='read', id=organization['name']) %} + + {{ organization['name'] }} +

    {{ organization['display_name'] }} ({{organization['package_count']}})

    +
    +
    +
    +

    + See All {{_('Organizations')}} +

    +
    +
    +{% endif %} diff --git a/ckanext/d4science_theme/templates/home/snippets/search_for_types.html b/ckanext/d4science_theme/templates/home/snippets/search_for_types.html new file mode 100644 index 0000000..df8d839 --- /dev/null +++ b/ckanext/d4science_theme/templates/home/snippets/search_for_types.html @@ -0,0 +1,37 @@ +{% set metadatatype = h.d4science_theme_get_systemtype_field_dict_from_session() %} +{% set metadatatypes = h.get_facet_items_dict(metadatatype['name'], limit=10) %} +{% if metadatatypes|length > 0 %} +
    +
    +

    Browse by {{_('Types')}}

    + +
    + + {% for index in range(0,metadatatypes|length) %} + {% set offset = 5 %} + {% set type = metadatatypes[index] %} + {% if index % offset == 0 %} + + {% endif %} + + {% if (index+offset+1) % offset == 0 %} + + {% endif %} + {% endfor %} +
    + {% set img_url = h.d4science_get_url_to_icon_for_ckan_entity(type.name, entity_type='type') %} + + {{ type.display_name }} +

    + {{ h.truncate(type.display_name, 26) }} + ({{type.count}}) + +

    +
    +
    +

    + See All {{_('Types')}} +

    +
    +
    +{% endif %} \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/home/snippets/stats.html b/ckanext/d4science_theme/templates/home/snippets/stats.html new file mode 100644 index 0000000..fefe05e --- /dev/null +++ b/ckanext/d4science_theme/templates/home/snippets/stats.html @@ -0,0 +1,43 @@ +{% set stats = h.get_site_statistics() %} +{% set systemtypefacet = h.d4science_theme_get_systemtype_field_dict_from_session() %} +{% set count_systemtypefacet = h.d4science_theme_count_facet_items_dict(systemtypefacet['name']) %} + + diff --git a/ckanext/d4science_theme/templates/organization/read.html b/ckanext/d4science_theme/templates/organization/read.html new file mode 100644 index 0000000..62be1ca --- /dev/null +++ b/ckanext/d4science_theme/templates/organization/read.html @@ -0,0 +1,47 @@ +{% extends "organization/read_base.html" %} + +{% block page_primary_action %} + {% if h.check_access('package_create', {'owner_org': c.group_dict.id}) %} + {# CODE ADDED BY Francesco Mangiacrapa #} + {% set hide = h.get_cookie_value('ckan_hide_header') %} + {% if hide=='true' %} + {# NOT SHOW 'Manage' #} + {% else %} + {% link_for _('Add Dataset'), controller='package', action='new', group=c.group_dict.id, class_='btn btn-primary', icon='plus-sign-alt' %} + {% endif %} + {% endif %} +{% endblock %} + +{% block primary_content_inner %} + {% block groups_search_form %} + {% set facets = { + 'fields': c.fields_grouped, + 'search': c.search_facets, + 'titles': c.facet_titles, + 'translated_fields': c.translated_fields, + 'remove_field': c.remove_field } + %} + {% set sorting = [ + (_('Relevance'), 'score desc, metadata_modified desc'), + (_('Name Ascending'), 'title_string asc'), + (_('Name Descending'), 'title_string desc'), + (_('Last Modified'), 'metadata_modified desc'), + (_('Popular'), 'views_recent desc') if g.tracking_enabled else (false, false) ] + %} + {% snippet 'snippets/search_form.html', form_id='organization-datasets-search-form', type='dataset', query=c.q, sorting=sorting, sorting_selected=c.sort_by_selected, count=c.page.item_count, facets=facets, placeholder=_('Search datasets...'), show_empty=request.params, fields=c.fields %} + {% endblock %} + {% block packages_list %} + {% if c.page.items %} + {{ h.snippet('snippets/package_list.html', packages=c.page.items) }} + {% endif %} + {% endblock %} + {% block page_pagination %} + {{ c.page.pager(q=c.q) }} + {% endblock %} +{% endblock %} + +{% block organization_facets %} + {% for facet in c.facet_titles %} + {{ h.snippet('snippets/facet_list.html', title=c.facet_titles[facet], name=facet, extras={'id':c.group_dict.id}) }} + {% endfor %} +{% endblock %} diff --git a/ckanext/d4science_theme/templates/organization/read_base.html b/ckanext/d4science_theme/templates/organization/read_base.html new file mode 100644 index 0000000..9c62884 --- /dev/null +++ b/ckanext/d4science_theme/templates/organization/read_base.html @@ -0,0 +1,34 @@ +{% extends "page.html" %} + +{% block subtitle %}{{ c.group_dict.display_name }} - {{ _('Organizations') }}{% endblock %} + +{% block breadcrumb_content %} +
  • {% link_for _('Organizations'), controller='organization', action='index' %}
  • +
  • {% link_for c.group_dict.display_name|truncate(35), controller='organization', action='read', id=c.group_dict.name %}
  • +{% endblock %} + +{% block content_action %} + {% if h.check_access('organization_update', {'id': c.group_dict.id}) %} + {# CODE ADDED BY Francesco Mangiacrapa #} + {% set hide = h.get_cookie_value('ckan_hide_header') %} + {% if hide=='true' %} + {# NOT SHOW 'Manage' #} + {% else %} + {% link_for _('Manage'), controller='organization', action='edit', id=c.group_dict.name, class_='btn', icon='wrench' %} + {% endif %} + {% endif %} +{% endblock %} + +{% block secondary_content %} + {% snippet 'snippets/organization.html', organization=c.group_dict, show_nums=true %} + {# ADDED BY FRANCESCO MANGIACRAPA SEE #12651 #} + {% set alternative_url = h.url(controller='organization', action='read', id=c.group_dict.name) %} + {% snippet 'spatial/snippets/spatial_query.html', alternative_url=alternative_url %} + {# END #} + {% block organization_facets %}{% endblock %} +{% endblock %} + +{% block links %} + {{ super() }} + {% include "organization/snippets/feeds.html" %} +{% endblock %} diff --git a/ckanext/d4science_theme/templates/organization/snippets/organization_item.html b/ckanext/d4science_theme/templates/organization/snippets/organization_item.html new file mode 100644 index 0000000..2f1da6e --- /dev/null +++ b/ckanext/d4science_theme/templates/organization/snippets/organization_item.html @@ -0,0 +1,44 @@ +{# +Renders a media item for a organization. This should be used in a list. + +organization - A organization dict. + +Example: + +
      + {% for organization in organizations %} + {% snippet "organization/snippets/organization_item.html", organization=organization %} + {% endfor %} +
    +#} +{% set url = h.url_for(organization.type ~ '_read', action='read', id=organization.name) %} +{% block item %} +
  • + {% block item_inner %} + {% block image %} + {{ organization.name }} + {% endblock %} + {% block title %} +

    {{ organization.display_name }}

    + {% endblock %} + {% block description %} + {% if organization.description %} +

    {{ h.markdown_extract(organization.description, extract_length=80) }}

    + {% endif %} + {% endblock %} + {% block datasets %} + {% if organization.package_count %} + {{ ungettext('{num} Dataset', '{num} Datasets', organization.package_count).format(num=organization.package_count) }} + {% endif %} + {% endblock %} + {% block link %} + + {{ _('View {organization_name}').format(organization_name=organization.display_name) }} + + {% endblock %} + {% endblock %} +
  • +{% endblock %} +{% if position is divisibleby 3 %} +
  • +{% endif %} diff --git a/ckanext/d4science_theme/templates/organization_vre/index.html b/ckanext/d4science_theme/templates/organization_vre/index.html new file mode 100644 index 0000000..f172f9a --- /dev/null +++ b/ckanext/d4science_theme/templates/organization_vre/index.html @@ -0,0 +1,47 @@ +{% extends "page.html" %} + +{# Added by Francesco Mangiacrapa; see: 8964 #} +{% block toolbar %} +{% endblock %} + +{% block subtitle %}{{ _('Organizations') }}{% endblock %} + +{% block breadcrumb_content %} +
  • {% link_for _('Organizations'), controller='organization', action='index' %}
  • +{% endblock %} + +{% block page_header %}{% endblock %} + +{% block page_primary_action %} + {% if h.check_access('organization_create') %} + {% link_for _('Add Organization'), controller='organization', action='new', class_='btn btn-primary', icon='plus-sign-alt' %} + {% endif %} +{% endblock %} + +{% block primary_content_inner %} +

    {% block page_heading %}{{ _('Organizations') }}{% endblock %}

    + {% block organizations_search_form %} + {% snippet 'snippets/search_form.html', form_id='organization-search-form', type='organization', query=c.q, sorting_selected=c.sort_by_selected, count=c.page.item_count, placeholder=_('Search organizations...'), show_empty=request.params, no_bottom_border=true if c.page.items %} + {% endblock %} + {% block organizations_list %} + {% if c.page.items or request.params %} + {% if c.page.items %} + {% snippet "organization/snippets/organization_list.html", organizations=c.page.items %} + {% endif %} + {% else %} +

    + {{ _('There are currently no organizations for this site') }}. + {% if h.check_access('organization_create') %} + {% link_for _('How about creating one?'), controller='organization', action='new' %}. + {% endif %} +

    + {% endif %} + {% endblock %} + {% block page_pagination %} + {{ c.page.pager(q=c.q or '', sort=c.sort_by_selected or '') }} + {% endblock %} +{% endblock %} + +{% block secondary_content %} + {% snippet "organization/snippets/helper.html" %} +{% endblock %} diff --git a/ckanext/d4science_theme/templates/organization_vre/read.html b/ckanext/d4science_theme/templates/organization_vre/read.html new file mode 100644 index 0000000..e84093c --- /dev/null +++ b/ckanext/d4science_theme/templates/organization_vre/read.html @@ -0,0 +1,61 @@ +{% extends "organization/read_base.html" %} + +{% block page_primary_action %} + {#Added by Francesco Mangiacrapa; see: 8964 #} + + + {% if h.check_access('package_create', {'owner_org': c.group_dict.id}) %} + {# CODE ADDED BY Francesco Mangiacrapa #} + {% set hide = h.get_cookie_value('ckan_hide_header') %} + {% if hide=='true' %} + {# NOT SHOW 'Manage' #} + {% else %} + {% link_for _('Add Dataset'), controller='package', action='new', group=c.group_dict.id, class_='btn btn-primary', icon='plus-sign-alt' %} + {% endif %} + {% endif %} +{% endblock %} + +{% block primary_content_inner %} + {% block groups_search_form %} + {% set facets = { + 'fields': c.fields_grouped, + 'search': c.search_facets, + 'titles': c.facet_titles, + 'translated_fields': c.translated_fields, + 'remove_field': c.remove_field } + %} + {% set sorting = [ + (_('Relevance'), 'score desc, metadata_modified desc'), + (_('Name Ascending'), 'title_string asc'), + (_('Name Descending'), 'title_string desc'), + (_('Last Modified'), 'metadata_modified desc'), + (_('Popular'), 'views_recent desc') if g.tracking_enabled else (false, false) ] + %} + {% snippet 'snippets/search_form.html', form_id='organization-datasets-search-form', type='dataset', query=c.q, sorting=sorting, sorting_selected=c.sort_by_selected, count=c.page.item_count, facets=facets, placeholder=_('Search datasets...'), show_empty=request.params, fields=c.fields %} + {% endblock %} + {% block packages_list %} + {% if c.page.items %} + {{ h.snippet('snippets/package_list.html', packages=c.page.items) }} + {% endif %} + {% endblock %} + {% block page_pagination %} + {{ c.page.pager(q=c.q) }} + {% endblock %} +{% endblock %} + +{% block organization_facets %} + {% for facet in c.facet_titles %} + {{ h.snippet('snippets/facet_list.html', title=c.facet_titles[facet], name=facet, extras={'id':c.group_dict.id}) }} + {% endfor %} +{% endblock %} diff --git a/ckanext/d4science_theme/templates/package/base.html b/ckanext/d4science_theme/templates/package/base.html new file mode 100644 index 0000000..20dd0b1 --- /dev/null +++ b/ckanext/d4science_theme/templates/package/base.html @@ -0,0 +1,24 @@ +{% extends "page.html" %} + +{% set pkg = c.pkg_dict or pkg_dict %} + +{% block breadcrumb_content_selected %} class="active"{% endblock %} + +{% block subtitle %}{{ _('Datasets') }}{% endblock %} + +{% block breadcrumb_content %} + {% if pkg %} + {% set dataset = pkg.title or pkg.name %} + {% if pkg.organization %} + {% set organization = pkg.organization.title or pkg.organization.name %} +
  • {% link_for _('Organizations'), controller='organization', action='index' %}
  • +
  • {% link_for organization|truncate(30), controller='organization', action='read', id=pkg.organization.name %}
  • + {% else %} +
  • {% link_for _('Datasets'), controller='package', action='search' %}
  • + {% endif %} + {% link_for dataset|truncate(30), controller='package', action='read', id=pkg.name %} + {% else %} +
  • {% link_for _('Datasets'), controller='package', action='search' %}
  • +
  • {{ _('Create Dataset') }}
  • + {% endif %} +{% endblock %} diff --git a/ckanext/d4science_theme/templates/package/group_list.html b/ckanext/d4science_theme/templates/package/group_list.html new file mode 100644 index 0000000..fe23b46 --- /dev/null +++ b/ckanext/d4science_theme/templates/package/group_list.html @@ -0,0 +1,44 @@ +{% extends "package/read_base.html" %} +{% import 'macros/form.html' as form %} + +{% block primary_content_inner %} +

    {{ _('Groups') }}

    + {% if c.group_dropdown %} + {# ADDED BY FRANCESCO MANGIACRAPA, related to TASK #5196 #} + {% if c.userobj %} + {% set username_id = c.userobj.id %} + {% set whereAdmin = [] %} + {% for option in c.group_dropdown %} + {% set role_for_user = h.d4science_theme_get_user_role_for_group_or_org(option[0], username_id) %} + {% if role_for_user and role_for_user == 'admin' %} + {% do whereAdmin.append(option) %} + {% else %} + {# SYSADMIN #} + {% if c.userobj.sysadmin %} + {% do whereAdmin.append(option) %} + {% endif %} + {% endif %} + {% endfor %} + {% if whereAdmin %} +
    + + +
    + {% endif %} + {% endif %} + {% endif %} + + + {% if c.pkg_dict.groups %} +
    + {% snippet 'group/snippets/group_list_simple.html', groups=c.pkg_dict.groups %} +
    + {% else %} +

    {{ _('There are no groups associated with this dataset') }}

    + {% endif %} + +{% endblock %} diff --git a/ckanext/d4science_theme/templates/package/read.html b/ckanext/d4science_theme/templates/package/read.html new file mode 100644 index 0000000..a851298 --- /dev/null +++ b/ckanext/d4science_theme/templates/package/read.html @@ -0,0 +1,59 @@ +{% ckan_extends %} +{% set dataset_extent = h.get_pkg_dict_extra(c.pkg_dict, 'spatial', '') %} +{% set d4science_cms_obj_placeholders = h.d4science_get_content_moderator_system_placeholder() %} +{% set moderation_item_status = h.get_pkg_dict_extra(c.pkg_dict,d4science_cms_obj_placeholders.item_status,'') %} + +{% block primary_content_inner %} +{% if moderation_item_status %} + + {{ moderation_item_status }} + +{% endif %} + {% block package_description %} + {% if pkg.private %} + + + {{ _('Private') }} + + {% endif %} +
    + {% block page_heading %} + {{ pkg.title or pkg.name }} + {% if pkg.state.startswith('draft') %} + [{{ _('Draft') }}] + {% endif %} + {% if pkg.state == 'deleted' %} + [{{ _('Deleted') }}] + {% endif %} + {% endblock %} +
    + {% block package_notes %} + {% if pkg.notes %} +
    + {{ h.render_markdown(pkg.notes) }} +
    + {% endif %} + {% endblock %} + {# FIXME why is this here? seems wrong #} + + {% endblock %} + + + {% if dataset_extent %} + {% snippet "spatial/snippets/dataset_map.html", extent=dataset_extent %} + {% endif %} + + {% block package_tags %} +
    {{_('Tags')}}
    + {% snippet "package/snippets/tags.html", tags=pkg.tags %} + {% endblock %} + + {% block package_resources %} + {% snippet "package/snippets/resources_list.html", pkg=pkg, resources=pkg.resources %} + {% endblock %} + + {% block package_additional_info %} + {% snippet "package/snippets/additional_info.html", pkg_dict=pkg %} + {% endblock %} + +{% endblock %} \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/package/read_base.html b/ckanext/d4science_theme/templates/package/read_base.html new file mode 100644 index 0000000..4b650c3 --- /dev/null +++ b/ckanext/d4science_theme/templates/package/read_base.html @@ -0,0 +1,116 @@ +{# CODE UPDATED BY Francesco Mangiacrapa + USE TO DEBUG + {% print "role for user: "+role_for_user %} + {% print "role for user:" +role_for_user %} + {% print "username_id = "+username_id %} + {% print "pkg_creator_user_id= "+pkg_creator_user_id %} +#} + + +{% extends "package/base.html" %} + +{% block subtitle %}{{ pkg.title or pkg.name }} - {{ super() }}{% endblock %} + +{% block head_extras -%} + {{ super() }} + {% set description = h.d4science_theme_markdown_extract_html(pkg.notes, extract_length=200)|forceescape %} + + +{% endblock -%} + +{% block content_action %} + + + + {% if h.check_access('package_update', {'id':pkg.id }) %} + {# CODE ADDED BY Francesco Mangiacrapa #} + {% set hide = h.get_cookie_value('ckan_hide_header') %} + {# INTO PORTAL - FROM D4SCIENCE PORTAL #} + {% if hide and hide == 'true' %} + {% set username_id = c.userobj.id %} + {% set pkg_creator_user_id = pkg.creator_user_id %} + {% set role_for_user = h.d4science_theme_get_user_role_for_group_or_org(pkg.organization.id, username_id) %} + {% if role_for_user %} + {% if role_for_user == 'admin' %} + {% link_for _('Manage'), controller='package', action='edit', id=pkg.name, class_='btn', icon='wrench' %} + {% else %} + {% if role_for_user == 'editor' %} + {# IF THE USER HAS ROLE EDITOR HE/SHE CAN EDIT ONLY ITS DATASET, see related ticket #5119 #} + {% if username_id == pkg_creator_user_id %} + {% link_for _('Manage'), controller='package', action='edit', id=pkg.name, class_='btn', icon='wrench' %} + {% endif %} + {% endif %} + {# NOT SHOW 'Manage' #} + {% endif %} + {% endif %} + {% else %} + {% link_for _('Manage'), controller='package', action='edit', id=pkg.name, class_='btn', icon='wrench' %} + {% endif %} + {% endif %} +{% endblock %} + +{% block content_primary_nav %} + {{ h.build_nav_icon('dataset_read', _('Dataset'), id=pkg.name) }} + {{ h.build_nav_icon('dataset_groups', _('Groups'), id=pkg.name) }} + + {% if h.check_access('package_update', {'id':pkg.id }) %} + {% set role_for_user = h.d4science_theme_get_user_role_for_group_or_org(pkg.organization.id, c.userobj.name) %} + {% if role_for_user and role_for_user == 'admin' %} + {{ h.build_nav_icon('dataset_activity', _('Activity Stream'), id=pkg.name) }} + {% endif %} + {% endif %} +{% endblock %} + +{% block primary_content_inner %} + {% block package_revision_info %} + {% if c.revision_date %} +
    +

    + {% set timestamp = h.render_datetime(c.revision_date, with_hours=True) %} + {% set url = h.url(controller='package', action='read', id=pkg.name) %} + + {% trans timestamp=timestamp, url=url %}This is an old revision of this dataset, as edited at {{ timestamp }}. It may differ significantly from the current revision.{% endtrans %} +

    +
    + {% endif %} + {% endblock %} +{% endblock %} + +{% block secondary_content %} + + {% block secondary_help_content %}{% endblock %} + + {% block package_info %} + {% snippet 'package/snippets/info.html', pkg=pkg %} + {% endblock %} + + {% block package_organization %} + {% if pkg.organization %} + {% set org = h.get_organization(pkg.organization.name) %} + {% snippet "snippets/organization.html", organization=org, has_context_title=true %} + {% endif %} + {% endblock %} + + {% block package_social %} + {# See: #7055 + {% snippet "snippets/social.html" %} + #} + {% endblock %} + + {% block package_license %} + {% snippet "snippets/license.html", pkg_dict=pkg %} + {% endblock %} + +{% endblock %} diff --git a/ckanext/d4science_theme/templates/package/resource_edit_base.html b/ckanext/d4science_theme/templates/package/resource_edit_base.html new file mode 100644 index 0000000..6ef2547 --- /dev/null +++ b/ckanext/d4science_theme/templates/package/resource_edit_base.html @@ -0,0 +1,51 @@ +{% extends "package/base.html" %} + +{% set logged_in = true if c.userobj else false %} +{% set res = c.resource %} + +{% block breadcrumb_content_selected %}{% endblock %} + +{% block breadcrumb_content %} + {{ super() }} + {% if res %} +
  • {% link_for h.resource_display_name(res)|truncate(30), controller='package', action='resource_read', id=pkg.name, resource_id=res.id %}
  • + {{ _('Edit') }} + {% endif %} +{% endblock %} + +{% block content_action %} + {% link_for _('All resources'), controller='package', action='resources', id=pkg.name, class_='btn', icon='arrow-left' %} + {% if res %} + {% link_for _('View resource'), controller='package', action='resource_read', id=pkg.name, resource_id=res.id, class_='btn', icon='eye-open' %} + {% endif %} +{% endblock %} + +{% block content_primary_nav %} + {{ h.build_nav_icon('resource_edit', _('Edit resource'), id=pkg.name, resource_id=res.id) }} + {# Updated by Francesco Mangiacrapa #11303 #} + {# if 'datapusher' in g.plugins #} + {# {{ h.build_nav_icon('resource_data', _('DataStore'), id=pkg.name, resource_id=res.id) }} #} + {# {% endif %} #} + {# {{ h.build_nav_icon('views', _('Views'), id=pkg.name, resource_id=res.id) }} #} + {% set is_sys_admin = true if (c.userobj and c.userobj.sysadmin) else false %} + {% if is_sys_admin %} + {% if 'datapusher' in g.plugins %} + {{ h.build_nav_icon('resource_data', _('DataStore'), id=pkg.name, resource_id=res.id) }} + {% endif %} + {{ h.build_nav_icon('views', _('Views'), id=pkg.name, resource_id=res.id) }} + {% endif %} +{% endblock %} + +{% block primary_content_inner %} +

    {% block form_title %}{{ _('Edit resource') }}{% endblock %}

    + {% block form %}{% endblock %} +{% endblock %} + +{% block secondary_content %} + {% snippet 'package/snippets/resource_info.html', res=res %} +{% endblock %} + +{% block scripts %} + {{ super() }} + {% resource 'vendor/fileupload' %} +{% endblock %} diff --git a/ckanext/d4science_theme/templates/package/resource_read.html b/ckanext/d4science_theme/templates/package/resource_read.html new file mode 100644 index 0000000..3344f08 --- /dev/null +++ b/ckanext/d4science_theme/templates/package/resource_read.html @@ -0,0 +1,187 @@ +{% extends "package/base.html" %} + +{% set res = c.resource %} + +{% block head_extras -%} + {{ super() }} + {% set description = h.markdown_extract(res.description, extract_length=200) if res.description else h.markdown_extract(c.package.notes, extract_length=200) %} + + +{% endblock -%} + +{% block subtitle %}{{ h.dataset_display_name(c.package) }} - {{ h.resource_display_name(res) }}{% endblock %} + +{% block breadcrumb_content_selected %}{% endblock %} + +{% block breadcrumb_content %} + {{ super() }} +
  • {{ h.resource_display_name(res)|truncate(30) }}
  • +{% endblock %} + +{% block pre_primary %} +{# Added by Francesco Mangiacrapa #} + + {% block resource %} +
    + {% block resource_inner %} +
    +
    + {% block resource_actions %} + + {% endblock %} +
    + {% block resource_content %} + {% block resource_read_title %}

    {{ h.resource_display_name(res) | truncate(50) }}

    {% endblock %} + {% block resource_read_url %} + {% if res.url and h.is_url(res.url) %} +

    {{ _('URL:') }} {{ res.url }}

    + {% elif res.url %} +

    {{ _('URL:') }} {{ res.url }}

    + {% endif %} + {% endblock %} +
    + {% if res.description %} + {{ h.render_markdown(res.description) }} + {% endif %} + {% if not res.description and c.package.notes %} +

    {{ _('From the dataset abstract') }}

    +
    {{ h.d4science_theme_markdown_extract_html(c.package.get('notes')) }}
    +

    {% trans dataset=c.package.title, url=h.url_for(controller='package', action='read', id=c.package['name']) %}Source: {{ dataset }}{% endtrans %} + {% endif %} +

    + {% endblock %} +
    + {% block data_preview %} + {% block resource_view %} + {% block resource_view_nav %} + {% set resource_preview = h.resource_preview(c.resource, c.package) %} + {% snippet "package/snippets/resource_views_list.html", + views=resource_views, + pkg=pkg, + is_edit=false, + view_id=current_resource_view['id'], + resource_preview=resource_preview, + resource=c.resource, + extra_class="nav-tabs-plain" + %} + {% endblock %} +
    + {% block resource_view_content %} +
    + {% set resource_preview = h.resource_preview(c.resource, c.package) %} + {% set views_created = res.has_views or resource_preview %} + {% if views_created %} + {% if resource_preview and not current_resource_view %} + {{ h.resource_preview(c.resource, c.package) }} + {% else %} + {% for resource_view in resource_views %} + {% if resource_view == current_resource_view %} + {% snippet 'package/snippets/resource_view.html', + resource_view=resource_view, + resource=c.resource, + package=c.package + %} + {% endif %} + {% endfor %} + {% endif %} + {# REMOVED View not created cases by Francesco Mangiacrapa #} + {% endif %} +
    + {% endblock %} +
    + {% endblock %} + {% endblock %} + {% endblock %} +
    + {% endblock %} +{% endblock %} + +{% block primary_content %} + {% block resource_additional_information %} + {% if res %} +
    + {% block resource_additional_information_inner %} +
    +

    {{ _('Additional Information') }}

    + + + + + + + + + + + {# {{ h.render_datetime(res.last_modified) or h.render_datetime(res.revision_timestamp) or h.render_datetime(res.created) or _('unknown') }} #} + + + + + + {# {{ h.render_datetime(res.Created) or h.render_datetime(res.created) or _('unknown') }} #} + + + + + + + + + + + + {% for key, value in h.format_resource_items(res.items()) %} + + {% endfor %} + +
    {{ _('Field') }}{{ _('Value') }}
    {{ _('Last updated') }}{{ h.render_datetime(res.last_modified) or h.render_datetime(res.revision_timestamp) or h.render_datetime(res.Created) or h.render_datetime(res.created) or _('unknown') }}
    {{ _('Created') }}{{ h.render_datetime(res.Created) or h.render_datetime(res.created) or _('unknown') }}
    {{ _('Format') }}{{ res.mimetype_inner or res.mimetype or res.format or _('unknown') }}
    {{ _('License') }}{% snippet "snippets/license.html", pkg_dict=pkg, text_only=True %}
    {{ key }}{{ value }}
    +
    + {% endblock %} +
    + {% endif %} + {% endblock %} +{% endblock %} + +{% block secondary_content %} + + {% block resources_list %} + {% snippet "package/snippets/resources.html", pkg=pkg, active=res.id %} + {% endblock %} + + {% block resource_license %} + {# See: #7055 + {% snippet "snippets/social.html" %} + #} + {% endblock %} +{% endblock %} \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/package/search.html b/ckanext/d4science_theme/templates/package/search.html new file mode 100644 index 0000000..4e2ef1d --- /dev/null +++ b/ckanext/d4science_theme/templates/package/search.html @@ -0,0 +1,90 @@ +{% extends "page.html" %} +{% import 'macros/form.html' as form %} + +{% block subtitle %}{{ _("Datasets") }}{% endblock %} + +{% block breadcrumb_content %} +
  • {{ h.nav_link(_('Datasets'), controller='package', action='search', highlight_actions = 'new index') }}
  • +{% endblock %} + +{% block primary_content %} +
    +
    + {% block page_primary_action %} + {% if h.check_access('package_create') %} + {# ADDED BY FRANCESCO MANGIACRAPA, 'ADD DATASET' IS SHOWN ONLY TO USER SYSADMIN' #7188 #} + {% if c.userobj and c.userobj.sysadmin %} +
    + {% link_for _('Add Dataset'), controller='package', action='new', class_='btn btn-primary', icon='plus-sign-alt' %} +
    + {% endif %} + {% endif %} + {% endblock %} + {% block form %} + {% set facets = { + 'fields': c.fields_grouped, + 'search': c.search_facets, + 'titles': c.facet_titles, + 'translated_fields': c.translated_fields, + 'remove_field': c.remove_field } + %} + {% set sorting = [ + (_('Relevance'), 'score desc, metadata_modified desc'), + (_('Name Ascending'), 'title_string asc'), + (_('Name Descending'), 'title_string desc'), + (_('Last Modified'), 'metadata_modified desc'), + (_('Popular'), 'views_recent desc') if g.tracking_enabled else (false, false) ] + %} + {% snippet 'snippets/search_form.html', form_id='dataset-search-form', type='dataset', query=c.q, sorting=sorting, sorting_selected=c.sort_by_selected, count=c.page.item_count, facets=facets, show_empty=request.params, error=c.query_error, fields=c.fields %} + {% endblock %} + {% block package_search_results_list %} + {{ h.snippet('snippets/package_list.html', packages=c.page.items) }} + {% endblock %} +
    + + {% block page_pagination %} + {{ c.page.pager(q=c.q) }} + {% endblock %} +
    + + {% block package_search_results_api %} +
    +
    + {% block package_search_results_api_inner %} + + {# Commented by Francesco, see Support #18126 #} + {# + {% set api_link = h.link_to(_('API'), h.url_for(controller='api', action='get_api', ver=3)) %} + {% set api_doc_link = h.link_to(_('API Docs'), 'http://docs.ckan.org/en/{0}/api/'.format(g.ckan_doc_version)) %} + {% if g.dumps_url -%} + {% set dump_link = h.link_to(_('full {format} dump').format(format=g.dumps_format), g.dumps_url) %} + {% trans %} + You can also access this registry using the {{ api_link }} (see {{ api_doc_link }}) or download a {{ dump_link }}. + {% endtrans %} + {% else %} + {% trans %} + You can also access this registry using the {{ api_link }} (see {{ api_doc_link}}). + {% endtrans %} + {%- endif %} + #} + + {% endblock %} +
    +
    + {% endblock %} +{% endblock %} + + +{% block secondary_content %} +
    +
    + + {% snippet "spatial/snippets/spatial_query.html" %} + + {% for facet in c.facet_titles %} + {{ h.snippet('snippets/facet_list.html', title=c.facet_titles[facet], name=facet) }} + {% endfor %} +
    + close +
    +{% endblock %} diff --git a/ckanext/d4science_theme/templates/package/snippets/additional_info.html b/ckanext/d4science_theme/templates/package/snippets/additional_info.html new file mode 100644 index 0000000..e058199 --- /dev/null +++ b/ckanext/d4science_theme/templates/package/snippets/additional_info.html @@ -0,0 +1,150 @@ +{% set key_item_url = _('Item') + ' URL' %} + + + + + +
    + {% block extras scoped %} + {# + This performs a sort + {% for extra in h.sorted_extras(pkg_dict.extras) %} + #} + {% if pkg_dict.extras %} + {# Added by Francesco Mangiacrapa, see 17901 #} + {% set extra_item_url = h.get_pkg_dict_extra(pkg_dict,key_item_url) %} + {% if extra_item_url %} +
    {{ key_item_url }}
    + + + + + +
    {{ extra_item_url }}{% snippet "package/snippets/qrcode_show.html", package_url=extra_item_url %}
    + {% endif %} + {% set extras_indexed_for_categories = h.d4science_get_extras_indexed_for_namespaces(pkg_dict.extras) %} + {% for k_cat in extras_indexed_for_categories %} + {% set category_idx = extras_indexed_for_categories[k_cat] %} + {% if(k_cat!='nocategory') %} +
    {{category_idx.category.title}}
    + {% if category_idx.category.description %} +

    Description: {{category_idx.category.description}}

    + {% endif %} + + + + + + + + + {% set my_extras = h.d4science_get_extra_for_category(extras_indexed_for_categories, k_cat) %} + {% snippet "package/snippets/extras_table.html", my_extras=my_extras, key_item_url=key_item_url %} + +
    {{ _('Field') }}{{ _('Value') }}
    +
    + {% endif %} + {% endfor %} + {% set my_extras = h.d4science_get_extra_for_category(extras_indexed_for_categories, 'nocategory') %} + {% if my_extras|length > 0 %} +
    {{ _('Additional Info') }}
    + + + + + + + + + {% snippet "package/snippets/extras_table.html", my_extras=my_extras, key_item_url=key_item_url %} + +
    {{ _('Field') }}{{ _('Value') }}
    +
    + {% endif %} + {% endif %} + {% endblock %} +
    {{ _('Management Info') }}
    + + + + + + + + + {% block package_additional_info %} + {% if pkg_dict.url %} + + + {% if h.is_url(pkg_dict.url) %} + + {% else %} + + {% endif %} + + {% endif %} + + {% if pkg_dict.author_email %} + + + + + {% elif pkg_dict.author %} + + + + + {% endif %} + {# Added by Francesco Mangiacrapa #} + {% set user_maintainer = h.d4science_get_user_info(pkg_dict.maintainer) %} + {% if pkg_dict.maintainer_email %} + + + + + {% elif pkg_dict.maintainer %} + + + + + {% endif %} + + {% if pkg_dict.version %} + + + + + {% endif %} + + {% if h.check_access('package_update',{'id':pkg_dict.id}) %} + + + + + {% endif %} + {% if pkg_dict.metadata_modified %} + + + + + {% endif %} + {% if pkg_dict.metadata_created %} + + + + + + {% endif %} + +
    {{ _('Field') }}{{ _('Value') }}
    {{ _('Source') }}{{ h.link_to(pkg_dict.url, pkg_dict.url, rel='foaf:homepage', target='_blank') }}{{ pkg_dict.url }}
    {{ _("Author") }}{{ h.mail_to(email_address=pkg_dict.author_email, name=pkg_dict.author) }}
    {{ _("Author") }}{{ pkg_dict.author }}
    {{ _('Maintainer') }}{{ h.mail_to(email_address=pkg_dict.maintainer_email, name=user_maintainer.fullname if (user_maintainer and user_maintainer.fullname) else pkg_dict.maintainer) }}
    {{ _('Maintainer') }}{{ user_maintainer.fullname if (user_maintainer and user_maintainer.fullname) else pkg_dict.maintainer }}
    {{ _("Version") }}{{ pkg_dict.version }}
    {{ _("State") }}{{ _(pkg_dict.state) }}
    {{ _("Last Updated") }} + {% snippet 'snippets/local_friendly_datetime.html', datetime_obj=pkg_dict.metadata_modified %} +
    {{ _("Created") }} + {% snippet 'snippets/local_friendly_datetime.html', datetime_obj=pkg_dict.metadata_created %} +
    + {% endblock %} +
    \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/package/snippets/extras_table.html b/ckanext/d4science_theme/templates/package/snippets/extras_table.html new file mode 100644 index 0000000..062ac19 --- /dev/null +++ b/ckanext/d4science_theme/templates/package/snippets/extras_table.html @@ -0,0 +1,59 @@ + + + +{% set d4science_cms_obj_placeholders = h.d4science_get_content_moderator_system_placeholder() %} +{% for extra_lnk in my_extras %} +{% set index = loop.index %} + {% for k in extra_lnk.keys() %} + {# Added by Francesco Mangiacrapa, see: #21701 #} + {% set extra_value = extra_lnk[k] %} + + {% if extra_value is defined and extra_value|length %} + {# Added by Francesco Mangiacrapa, see: #7055 #} + {% set isHttp = extra_value.startswith(('http://', 'https://')) %} + + + {% if k != key_item_url and (not k.startswith(d4science_cms_obj_placeholders.prefix)) %} + {{ _(k) }} + {% if isHttp %} + {% if k == 'graphic-preview-file'%} + {{ + {% else %} + {{ extra_value }} + {% endif %} + {% elif k == 'responsible-party' %} +
    {{ extra_value }}
    + {% elif k == 'dataset-reference-date' %} +
    {{ extra_value }}
    + {% elif k == 'coupled-resource' %} +
    {{ extra_value }}
    + {% elif k.startswith('Zenodo') %} + + {% elif k == 'spatial' %} +
    {{ extra_value }}
    + {% else %} + {{ extra_value }} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} +{% endfor %} \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/package/snippets/info.html b/ckanext/d4science_theme/templates/package/snippets/info.html new file mode 100644 index 0000000..2658c11 --- /dev/null +++ b/ckanext/d4science_theme/templates/package/snippets/info.html @@ -0,0 +1,47 @@ +{# +Displays a sidebard module with information for given package + +pkg - The package dict that owns the resources. + +Example: + + {% snippet "package/snippets/info.html", pkg=pkg %} + +#} +{% block package_info %} + {% if pkg %} +
    +
    +
    + {% block package_info_inner %} + {% block heading %} +
    {{ h.dataset_display_name(pkg) }}
    + {% endblock %} + {% if pkg.extras %} + {% for extra in pkg.extras if extra['key'] == 'graphic-preview-file' %} + + {% endfor %} + {% endif %} + {% block nums %} +
    +
    +
    {{ _('Followers') }}
    +
    {{ h.SI_number_span(h.follow_count('dataset', pkg.id)) }}
    +
    +
    + {% endblock %} + {% block follow_button %} + {% if not hide_follow_button %} + + {% endif %} + {% endblock %} + {% endblock %} +
    +
    +
    + {% endif %} +{% endblock %} diff --git a/ckanext/d4science_theme/templates/package/snippets/qrcode_show.html b/ckanext/d4science_theme/templates/package/snippets/qrcode_show.html new file mode 100644 index 0000000..a0ec361 --- /dev/null +++ b/ckanext/d4science_theme/templates/package/snippets/qrcode_show.html @@ -0,0 +1,6 @@ +{% set qr_code_image = h.d4science_get_qrcode_for_url(package_url) %} +{% block package_qrcode_for_url %} +
    {{
    +{% endblock %} + + \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/package/snippets/resource_form.html b/ckanext/d4science_theme/templates/package/snippets/resource_form.html new file mode 100644 index 0000000..3f0ef0b --- /dev/null +++ b/ckanext/d4science_theme/templates/package/snippets/resource_form.html @@ -0,0 +1,96 @@ +{% import 'macros/form.html' as form %} + +{% set data = data or {} %} +{% set errors = errors or {} %} +{% set action = form_action or h.url_for(controller='package', action='new_resource', id=pkg_name) %} + +
    + {% block stages %} + {# An empty stages variable will not show the stages #} + {% if stage %} + {{ h.snippet('package/snippets/stages.html', stages=stage, pkg_name=pkg_name) }} + {% endif %} + {% endblock %} + + {% block errors %}{{ form.errors(error_summary) }}{% endblock %} + + + + {% block basic_fields %} + {% block basic_fields_url %} + {% set is_upload = (data.url_type == 'upload') %} + + {# Updated by Francesco Mangiacrapa #11303 #} + {% set is_sys_admin = true if (c.userobj and c.userobj.sysadmin) else false %} + {% set enabling_upload = true if(is_sys_admin and h.uploads_enabled()) else false %} + {{ form.image_upload(data, errors, field_url='url', field_upload='upload', field_clear='clear_upload', + is_upload_enabled=enabling_upload, is_url=data.url and not is_upload, is_upload=is_upload, + upload_label=_('Data'), url_label=_('URL'), placeholder=_('http://example.com/external-data.csv')) }} + + {# OLD CODE + {{ form.image_upload(data, errors, field_url='url', field_upload='upload', field_clear='clear_upload', + is_upload_enabled=h.uploads_enabled(), is_url=data.url and not is_upload, is_upload=is_upload, + upload_label=_('Data'), url_label=_('URL'), placeholder=_('http://example.com/external-data.csv')) }} + #} + {% endblock %} + + {% block basic_fields_name %} + {{ form.input('name', id='field-name', label=_('Name'), placeholder=_('eg. January 2011 Gold Prices'), value=data.name, error=errors.name, classes=['control-full']) }} + {% endblock %} + + {% block basic_fields_description %} + {{ form.markdown('description', id='field-description', label=_('Description'), placeholder=_('Some useful notes about the data'), value=data.description, error=errors.description) }} + {% endblock %} + + {% block basic_fields_format %} + {% set format_attrs = {'data-module': 'autocomplete', 'data-module-source': '/api/2/util/resource/format_autocomplete?incomplete=?'} %} + {% call form.input('format', id='field-format', label=_('Format'), placeholder=_('eg. CSV, XML or JSON'), value=data.format, error=errors.format, classes=['control-medium'], attrs=format_attrs) %} + + + {{ _('This will be guessed automatically. Leave blank if you wish') }} + + {% endcall %} + {% endblock %} + {% endblock basic_fields %} + + {% block metadata_fields %} + {% if include_metadata %} + {# TODO: Where do these come from, they don't exist in /package/new_package_form.html #} + {# {{ form.select('resource_type', id='field-type', label=_('Resource Type'), options=[{'value': 'empty', 'text': _('Select a type…')}], selected="empty", error=errors.type) }} #} + + {{ form.input('last_modified', id='field-last-modified', label=_('Last Modified'), placeholder=_('eg. 2012-06-05'), value=data.last_modified, error=errors.last_modified, classes=[]) }} + + {{ form.input('size', id='field-size', label=_('File Size'), placeholder=_('eg. 1024'), value=data.size, error=errors.size, classes=[]) }} + + {{ form.input('mimetype', id='field-mimetype', label=_('MIME Type'), placeholder=_('eg. application/json'), value=data.mimetype, error=errors.mimetype, classes=[]) }} + + {{ form.input('mimetype_inner', id='field-mimetype-inner', label=_('MIME Type'), placeholder=_('eg. application/json'), value=data.mimetype_inner, error=errors.mimetype_inner, classes=[]) }} + {% endif %} + {% endblock %} + +
    + {% block delete_button %} + {% if data.id %} + {% if h.check_access('resource_delete', {'id': data.id}) %} + {% set locale = h.dump_json({'content': _('Are you sure you want to delete this resource?')}) %} + {% block delete_button_text %}{{ _('Delete') }}{% endblock %} + {% endif %} + {% endif %} + {% endblock %} + {% if stage %} + {% block previous_button %} + + {% endblock %} + {% block again_button %} + + {% endblock %} + {% block save_button %} + + {% endblock %} + {% else %} + {% block add_button %} + + {% endblock %} + {% endif %} +
    +
    \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/package/snippets/resource_item.html b/ckanext/d4science_theme/templates/package/snippets/resource_item.html new file mode 100644 index 0000000..9103f5b --- /dev/null +++ b/ckanext/d4science_theme/templates/package/snippets/resource_item.html @@ -0,0 +1,106 @@ +{% set can_edit = h.check_access('package_update', {'id':pkg.id }) %} +{% set url_action = 'resource_edit' if url_is_edit and can_edit else 'resource_read' %} +{% set url = h.url_for(controller='package', action=url_action, id=pkg.name, resource_id=res.id) %} +
  • +{# Added by Francesco Mangiacrapa block custom_view_on_resources see:4851 #} +{% block custom_view_on_resources %} +{% set user = c.user %} +{% if user %} + {% block resource_item_title %} + + {{ h.resource_display_name(res) | truncate(50) }}{{ res.format }} + {{ h.popular('views', res.tracking_summary.total, min=10) }} + + {% endblock %} + {% block resource_item_description %} +

    + {% if res.description %} + {{ h.markdown_extract(res.description, extract_length=80) }} + {% endif %} +

    + {% endblock %} + {% block resource_item_explore %} + {% if not url_is_edit %} + {# Only if can edit, explorer button is shown with several facility #} + {% if can_edit %} + + {% else %} + + {{ _('Go to resource') }} + + {% endif %} + {% endif %} + {% endblock %} +{% else %} + {% block resource_item_title2 %} + {# Updated by Francesco Mangiacrapa, see: #10056 #} + + {{ h.resource_display_name(res) | truncate(50) }}{{ res.format }} + {{ h.popular('views', res.tracking_summary.total, min=10) }} + + {% endblock %} +
    + {% block resource_item_description2 %} +

    + {% if res.description %} + {{ h.markdown_extract(res.description, extract_length=80) }} + {% endif %} +

    + {% endblock %} + The resource: '{{ h.resource_display_name(res) | truncate(30) }}' is not accessible as guest user. You must login to access it! +
    +{% endif %} +{% endblock %} +
  • + diff --git a/ckanext/d4science_theme/templates/package/snippets/resources.html b/ckanext/d4science_theme/templates/package/snippets/resources.html new file mode 100644 index 0000000..2422175 --- /dev/null +++ b/ckanext/d4science_theme/templates/package/snippets/resources.html @@ -0,0 +1,34 @@ +{# +Displays a sidebard module with navigation containing the provided resources. +If no resources are provided then the module will not be displayed. + +pkg - The package dict that owns the resources. +active - The id of the currently displayed resource. +action - The controller action to use (default: 'resource_read'). + +Example: + + {% snippet "package/snippets/resources.html", pkg=pkg, active=res.id %} + +#} +{% set resources = pkg.resources or [] %} +{% if resources %} + {% block resources %} +
    + {% block resources_inner %} + {% block resources_title %} +

    All {{ _("Resources") }}

    + {% endblock %} + {% block resources_list %} + + {% endblock %} + {% endblock %} +
    + {% endblock %} +{% endif %} diff --git a/ckanext/d4science_theme/templates/package/snippets/resources_list.html b/ckanext/d4science_theme/templates/package/snippets/resources_list.html new file mode 100644 index 0000000..4b064c2 --- /dev/null +++ b/ckanext/d4science_theme/templates/package/snippets/resources_list.html @@ -0,0 +1,76 @@ +{# +Renders a list of resources with icons and view links. + +resources - A list of resources to render +pkg - A package object that the resources belong to. + +Example: + + {% snippet "package/snippets/resources_list.html", pkg=pkg, resources=pkg.resources %} + +#} + + + +
    +
    {{ _('Data and Resources') }}
    + {% set user = c.user %} + {# Added by Francesco Mangiacrapa #10389 #} + {% if not user %} +
    To access the resources you must log in
    + {% endif %} + {# end #} + {% block resource_list %} + {% if resources %} +
      + {% block resource_list_inner %} + {% for resource in resources %} + {% snippet 'package/snippets/resource_item.html', pkg=pkg, res=resource %} + {% endfor %} + {% endblock %} +
    + {% else %} + {% if h.check_access('resource_create', {'package_id': pkg['id']}) %} + {% trans url=h.url_for(controller='package', action='new_resource', id=pkg.name) %} +

    This dataset has no data, why not add some?

    + {% endtrans %} + {% else %} +

    {{ _('This dataset has no data') }}

    + {% endif %} + {% endif %} + {% endblock %} +
    diff --git a/ckanext/d4science_theme/templates/page.html b/ckanext/d4science_theme/templates/page.html new file mode 100644 index 0000000..a255d0b --- /dev/null +++ b/ckanext/d4science_theme/templates/page.html @@ -0,0 +1,155 @@ +{% extends "base.html" %} + +{%- block page -%} + + {% block skip %} + + {% endblock %} + + {# + Override the header on a page by page basis by extending this block. If + making sitewide header changes it is preferable to override the header.html + file. + #} + {%- block header %} + {% include "header.html" %} + {% endblock -%} + + {# The content block allows you to replace the content of the page if needed #} + {%- block content %} + + {% block maintag %}
    {% endblock %} +
    + {% block main_content %} + {% block flash %} +
    + {% block flash_inner %} + {% for message in h.flash.pop_messages() | list %} +
    + {{ h.literal(message) }} +
    + {% endfor %} + {% endblock %} +
    + {% endblock %} + + {% block toolbar %} + +
    + {% block breadcrumb %} + {% if self.breadcrumb_content() | trim %} + + {% endif %} + {% endblock %} +
    + + {#Added by Francesco Mangiacrapa; see: 8964 #} + + + {% endblock %} + +
    + + {# + The pre_primary block can be used to add content to before the + rendering of the main content columns of the page. + #} + {% block pre_primary %} + {% endblock %} + + {% block primary %} +
    + {# + The primary_content block can be used to add content to the page. + This is the main block that is likely to be used within a template. + + Example: + + {% block primary_content %} +

    My page content

    +

    Some content for the page

    + {% endblock %} + #} + {% block primary_content %} +
    + {% block page_header %} + + {% endblock %} +
    + {% if self.page_primary_action() | trim %} +
    + {% block page_primary_action %}{% endblock %} +
    + {% endif %} + {% block primary_content_inner %} + {% endblock %} +
    +
    + {% endblock %} +
    + {% endblock %} + + {% block secondary %} + + {% endblock %} +
    + {% endblock %} +
    +
    + {% endblock -%} + + {# + Override the footer on a page by page basis by extending this block. If + making sitewide header changes it is preferable to override the footer.html-u + file. + #} + {%- block footer %} + {% include "footer.html" %} + {% endblock -%} +{%- endblock -%} + +{%- block scripts %} + {% resource 'base/main' %} + {% resource 'base/ckan' %} + {% if g.tracking_enabled %} + {% resource 'base/tracking.js' %} + {% endif %} + {{ super() }} +{% endblock -%} diff --git a/ckanext/d4science_theme/templates/snippets/custom_form_fields.html b/ckanext/d4science_theme/templates/snippets/custom_form_fields.html new file mode 100644 index 0000000..f0af62b --- /dev/null +++ b/ckanext/d4science_theme/templates/snippets/custom_form_fields.html @@ -0,0 +1,51 @@ +{# +Adds a block of custom form fields. + +extras - The fields to add. +errors - A dict of errors for the fields. +limit - The total number of fields that should be output. +Example: + + {% snippet 'snippets/custom_form_fields.html', extras=data.extras, errors=errors, limit=3 %} + +#} +{% import "macros/form.html" as form %} + +{% set d4science_cms_obj_placeholders = h.d4science_get_content_moderator_system_placeholder() %} +{% set d4science_system_type_obj = h.d4science_theme_get_systemtype_field_dict_from_session() %} +
    + + {% for extra in extras %} + {% set is_system_field = extra.key.startswith(d4science_cms_obj_placeholders.prefix) or extra.key.startswith(d4science_system_type_obj.id) %} + {% set apply_classes = [] %} + {% if is_system_field %} + {% set apply_classes = ['disabled-div'] %} + {% endif %} + {% set prefix = 'extras__%d__' % loop.index0 %} + {{ form.custom( + names=(prefix ~ 'key', prefix ~ 'value', prefix ~ 'deleted'), + id='field-extras-%d' % loop.index, + label=_('Custom Field'), + values=(extra.key, extra.value, extra.deleted), + classes=apply_classes, + error=errors[prefix ~ 'key'] or errors[prefix ~ 'value'] + ) }} + {% endfor %} + + {# Add a max of 3 empty columns #} + {% set total_extras = extras|count %} + {% set empty_extras = (limit or 3) - total_extras %} + {% if empty_extras <= 0 %}{% set empty_extras = 1 %}{% endif %} + + {% for extra in range(total_extras, total_extras + empty_extras) %} + {% set index = loop.index0 + (extras|count) %} + {% set prefix = 'extras__%d__' % index %} + {{ form.custom( + names=(prefix ~ 'key', prefix ~ 'value', prefix ~ 'deleted'), + id='field-extras-%d' % index, + label=_('Custom Field'), + values=(extra.key, extra.value, extra.deleted), + error=errors[prefix ~ 'key'] or errors[prefix ~ 'value'] + ) }} + {% endfor %} +
    diff --git a/ckanext/d4science_theme/templates/snippets/facet_list.html b/ckanext/d4science_theme/templates/snippets/facet_list.html new file mode 100644 index 0000000..e985503 --- /dev/null +++ b/ckanext/d4science_theme/templates/snippets/facet_list.html @@ -0,0 +1,99 @@ +{# +Construct a facet module populated with links to filtered results. + +name + The field name identifying the facet field, eg. "tags" + +title + The title of the facet, eg. "Tags", or "Tag Cloud" + +label_function + Renders the human-readable label for each facet value. + If defined, this should be a callable that accepts a `facet_item`. + eg. lambda facet_item: facet_item.display_name.upper() + By default it displays the facet item's display name, which should + usually be good enough + +if_empty + A string, which if defined, and the list of possible facet items is empty, + is displayed in lieu of an empty list. + +count_label + A callable which accepts an integer, and returns a string. This controls + how a facet-item's count is displayed. + +extras + Extra info passed into the add/remove params to make the url + +alternative_url + URL to use when building the necessary URLs, instead of the default + ones returned by url_for. Useful eg for dataset types. + +hide_empty + Do not show facet if there are none, Default: false. + +within_tertiary + Boolean for when a facet list should appear in the the right column of the + page and not the left column. + +#} +{% block facet_list %} + {% set hide_empty = hide_empty or false %} + {% with items = items or h.get_facet_items_dict(name) %} + {% if items or not hide_empty %} + {% if within_tertiary %} + {% set nav_class = 'nav nav-pills nav-stacked' %} + {% set nav_item_class = ' ' %} + {% set wrapper_class = 'nav-facet nav-facet-tertiary' %} + {% endif %} + {% block facet_list_item %} +
    + {% block facet_list_heading %} +

    + + {% set title = title or h.get_facet_title(name) %} + {{ title }} +

    + {% endblock %} + {% block facet_list_items %} + {% with items = items or h.get_facet_items_dict(name) %} + {% if items %} + + + + {% else %} +

    {{ _('There are no {facet_type} that match this search').format(facet_type=title) }}

    + {% endif %} + {% endwith %} + {% endblock %} +
    + {% endblock %} + {% endif %} + {% endwith %} +{% endblock %} diff --git a/ckanext/d4science_theme/templates/snippets/package_item.html b/ckanext/d4science_theme/templates/snippets/package_item.html new file mode 100644 index 0000000..05c49ed --- /dev/null +++ b/ckanext/d4science_theme/templates/snippets/package_item.html @@ -0,0 +1,133 @@ +{# +Displays a single of dataset. + +package - A package to display. +item_class - The class name to use on the list item. +hide_resources - If true hides the resources (default: false). +banner - If true displays a popular banner (default: false). +truncate - The length to trucate the description to (default: 180) +truncate_title - The length to truncate the title to (default: 80). + +Example: + + {% snippet 'snippets/package_item.html', package=c.datasets[0] %} + +#} + +{% set truncate = truncate or 180 %} +{% set truncate_title = truncate_title or 80 %} +{% set title = package.title or package.name %} +{% set notes = h.markdown_extract(package.notes, extract_length=truncate) %} +{% set acquired = h.is_dataset_acquired(package) %} +{% set owner = h.is_owner(package) %} + +{# +{% resource 'd4science_theme/custom.css' %} +CHANGED BY FRANCESCO.MANGIACRAPA +#} + +{% block package_item_content %} + +{% if package.private and not h.can_read(package) %} +
  • +
    +

    + {% if package.private and not h.can_read(package) %} + + + {{ _('Private') }} + + {% endif %} + {% if acquired and not owner %} + + + {{ _('Acquired') }} + + {% endif %} + + + {% if package.private and not h.can_read(package) %} + {# {{ _(h.truncate(title, truncate_title)) }} #} + Dataset +
    + {{ h.acquire_button(package) }} + {% else %} + {{ h.link_to(h.truncate(title, truncate_title), h.url_for(controller='package', action='read', id=package.name)) }} + {% endif %} + + + {% if package.get('state', '').startswith('draft') %} + {{ _('Draft') }} + {% elif package.get('state', '').startswith('deleted') %} + {{ _('Deleted') }} + {% endif %} + {{ h.popular('recent views', package.tracking_summary.recent, min=10) if package.tracking_summary }} +

    + {% if banner %} + + {% endif %} + {% if notes %} + + {% endif %} +
    +
  • +{% else %} +
  • +
    +

    + {% if package.private and not h.can_read(package) %} + + + {{ _('Private') }} + + {% endif %} + {% if acquired and not owner %} + + + {{ _('Acquired') }} + + {% endif %} + {% if owner %} + + + {{ _('Owner') }} + + {% endif %} + + + {% if package.private and not h.can_read(package) %} + {{ _(h.truncate(title, truncate_title)) }} +
    + {{ h.acquire_button(package) }} + {% else %} + {{ h.link_to(h.truncate(title, truncate_title), h.url_for(controller='package', action='read', id=package.name)) }} + {% endif %} + + + {% if package.get('state', '').startswith('draft') %} + {{ _('Draft') }} + {% elif package.get('state', '').startswith('deleted') %} + {{ _('Deleted') }} + {% endif %} + {{ h.popular('recent views', package.tracking_summary.recent, min=10) if package.tracking_summary }} +

    + {% if banner %} + + {% endif %} + {% if notes %} +
    {{ notes|urlize }}
    + {% endif %} +
    + {% if package.resources and not hide_resources %} +
      + {% for resource in h.dict_list_reduce(package.resources, 'format') %} +
    • + {{ resource }} +
    • + {% endfor %} +
    + {% endif %} + +
  • +{% endif %} +{% endblock %} diff --git a/ckanext/d4science_theme/templates/snippets/tag_list.html b/ckanext/d4science_theme/templates/snippets/tag_list.html new file mode 100644 index 0000000..3e79862 --- /dev/null +++ b/ckanext/d4science_theme/templates/snippets/tag_list.html @@ -0,0 +1,18 @@ +{# +render a list of tags linking to the dataset search page +tags: list of tags + +Removed truncate function by Francesco Mangiacrapa + {{ h.truncate(tag.display_name, 22) }} + +#} +{% set _class = _class or 'tag-list' %} +{% block tag_list %} + +{% endblock %} diff --git a/ckanext/d4science_theme/templates/type/index.html b/ckanext/d4science_theme/templates/type/index.html new file mode 100644 index 0000000..bb27080 --- /dev/null +++ b/ckanext/d4science_theme/templates/type/index.html @@ -0,0 +1,41 @@ +{% extends "page.html" %} + +{% block subtitle %}{{ _('Types') }}{% endblock %} + +{% block breadcrumb_content %} +
  • {% link_for _('Types'), controller='d4STypeController', action='index' %}
  • +{% endblock %} + +{% block page_header %}{% endblock %} + +{% set metadatatype = h.d4science_theme_get_systemtype_field_dict_from_session() %} +{% set metadatatypes = h.get_facet_items_dict(metadatatype['name']) %} +{% set sortby = h.get_request_param('sort') %} +{% if sortby %} +{% set list = sortby.split('_') %} +{% else %} +{% set list = ['name', 'asc'] %} +{% endif %} +{% set metadatatypes = h.d4science_get_ordered_dictionary(metadatatypes, list[0], list[1]) %} + + +{% block primary_content_inner %} + +

    {{ _('Types') }}

    +{% block type_form %} + {% snippet "type/snippets/type_form.html", metadatatypes=metadatatypes, sorting_selected=sortby %} +{% endblock %} + +{% block type_list %} + {% if metadatatypes|length >= 1 %} + {% snippet "type/snippets/type_list.html", metadatatypes=metadatatypes %} + {% else %} +

    There are no {{ _('Types') }}

    + {% endif %} +{% endblock %} + +{% endblock %} + +{% block secondary_content %} + {% snippet "type/snippets/helper.html" %} +{% endblock %} \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/type/snippets/helper.html b/ckanext/d4science_theme/templates/type/snippets/helper.html new file mode 100644 index 0000000..20e827e --- /dev/null +++ b/ckanext/d4science_theme/templates/type/snippets/helper.html @@ -0,0 +1,14 @@ +
    +

    + + {{ _('What are Types?') }} +

    +
    +

    + {% trans %} + Types are used to filter catalogue items by their typology, e.g. datasets, methods, services. + Every typology is characterised by a specific set of attributes, controlled vocabularies and formats carefully describing the specific class of items. + {% endtrans %} +

    +
    +
    \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/type/snippets/type_form.html b/ckanext/d4science_theme/templates/type/snippets/type_form.html new file mode 100644 index 0000000..00f5d25 --- /dev/null +++ b/ckanext/d4science_theme/templates/type/snippets/type_form.html @@ -0,0 +1,52 @@ +{% import 'macros/form.html' as form %} + +{% set sorting = [(_('Name Ascending'), 'name_asc'), (_('Name Descending'), 'name_desc'), (_('Number Of Ascending'), 'count_asc'), (_('Number Of Descending'), 'count_desc')] %} +{% set search_class = search_class if search_class else 'search-giant' %} +{% set no_bottom_border = no_bottom_border if no_bottom_border else false %} +{% set form_id = form_id if form_id else false %} + +
    + + {% block search_sortby %} + {% if sorting %} +
    + + + {% block search_sortby_button %} + + {% endblock %} +
    + {% endif %} + {% endblock %} + + {% block search_title %} +

    + {{metadatatypes|length}} + {% if metadatatypes|length > 1 %} + {{ _('Types') }} + {% else %} + {{ _('Type') }} + {% endif %} + found +

    + {% endblock %} + +
    + +{% if show_empty and count == 0 and not error %} + {% trans %} +

    Please try another search.

    + {% endtrans %} +{% endif %} + +{% if error %} + {% trans %} +

    There was an error while searching. Please try again.

    + {% endtrans %} +{% endif %} diff --git a/ckanext/d4science_theme/templates/type/snippets/type_item.html b/ckanext/d4science_theme/templates/type/snippets/type_item.html new file mode 100644 index 0000000..29eb598 --- /dev/null +++ b/ckanext/d4science_theme/templates/type/snippets/type_item.html @@ -0,0 +1,39 @@ +{# +Renders a media item for a type. This should be used in a list. + +type - A type dict. + +Example: + + +
      + {% for type in types %} + {% snippet "type/snippets/type_item.html", type=type %} + {% endfor %} +
    +#} +{% block item %} + +
  • + {% block item_inner %} + {% block image %} + {% set img_url = h.d4science_get_url_to_icon_for_ckan_entity(type.name, entity_type='type') %} +
    {{ type.name }}
    + {% endblock %} + {% block title %} + + {% endblock %} + {% block link %} +

    {{ h.truncate(type.display_name, 26) }} + ({{type.count}})

    + {% endblock %} + {% endblock %} +
  • +{% endblock %} diff --git a/ckanext/d4science_theme/templates/type/snippets/type_list.html b/ckanext/d4science_theme/templates/type/snippets/type_list.html new file mode 100644 index 0000000..2b5845c --- /dev/null +++ b/ckanext/d4science_theme/templates/type/snippets/type_list.html @@ -0,0 +1,19 @@ +{# +Display a grid of type items. + +groups - A list of types. + +Example: + + {% snippet "type/snippets/type_item.htm" %} + +#} +{% block type_list %} +
      + {% block type_list_inner %} + {% for type in metadatatypes %} + {% snippet "type/snippets/type_item.html", type=type, position=loop.index %} + {% endfor %} + {% endblock %} +
    +{% endblock %} diff --git a/ckanext/d4science_theme/templates/user/dashboard.html b/ckanext/d4science_theme/templates/user/dashboard.html new file mode 100644 index 0000000..7a8ecbd --- /dev/null +++ b/ckanext/d4science_theme/templates/user/dashboard.html @@ -0,0 +1,54 @@ +{% ckan_extends %} + +{% set user = c.userobj %} + +{% block breadcrumb_content %} +
  • {{ _('Dashboard') }}
  • +{% endblock %} + +{% block secondary %}{% endblock %} + +{% block primary %} +
    + {% block page_header %} + {# CODE ADDED BY Francesco Mangiacrapa #} + {% set hide = h.get_cookie_value('ckan_hide_header') %} + {% if hide=='true' %} + {# NOT SHOW 'Edit settings' #} + {% else %} + + {% endif %} + {% endblock %} +
    + {% if self.page_primary_action() | trim %} +
    + {% block page_primary_action %}{% endblock %} +
    + {% endif %} + {% block primary_content_inner %} +
    + {% snippet 'user/snippets/followee_dropdown.html', context=c.dashboard_activity_stream_context, followees=c.followee_list %} +

    + {% block page_heading %} + {{ _('News feed') }} + {% endblock %} + {{ _("Activity from items that I'm following") }} +

    + {% block activity_stream %} + {{ c.dashboard_activity_stream }} + {% endblock %} +
    + {% endblock %} +
    +
    +{% endblock %} \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/user/dashboard_datasets.html b/ckanext/d4science_theme/templates/user/dashboard_datasets.html new file mode 100644 index 0000000..8b29e1c --- /dev/null +++ b/ckanext/d4science_theme/templates/user/dashboard_datasets.html @@ -0,0 +1,65 @@ +{#{% extends "user/dashboard.html" %}#} +{# CREATED BY FRANCESCO MANGIACRAPA #} + +{% ckan_extends %} +{% set user = c.userobj %} + +{% block breadcrumb_content %} +{% endblock %} + +{% block primary %} +
    + {% block page_header %} + {# CODE ADDED BY Francesco Mangiacrapa #} + {% set hide = h.get_cookie_value('ckan_hide_header') %} + {% if hide=='true' %} + {# NOT SHOW 'Edit settings' #} + {% else %} + + {% endif %} + {% endblock %} +
    + {% if self.page_primary_action() | trim %} +
    + {% block page_primary_action %} + {% set hide = h.get_cookie_value('ckan_hide_header') %} + {% if hide=='true' %} + {# NOT SHOW 'Edit settings' #} + {% else %} + {% if h.check_access('package_create') %} + {% link_for _('Add Dataset'), controller='package', action='new', class_="btn btn-primary", icon="plus-sign-alt" %} + {% endif %} + {% endif %} + {% endblock %} +
    + {% endif %} + {% block primary_content_inner %} +

    {{ _('My Datasets') }}

    + {% if c.user_dict.datasets %} + {% snippet 'snippets/package_list.html', packages=c.user_dict.datasets %} + {% else %} +

    + {{ _('You haven\'t created any datasets.') }} + {% if h.check_access('package_create') %} + {#{% link_for _('Create one now?'), controller='package', action='new' %}#} + {% endif %} +

    + {% endif %} + {% endblock %} +
    +
    +{% endblock %} + +{% block dashboard_activity_stream_context %}{% endblock %} + +{% block secondary %}{% endblock %} \ No newline at end of file diff --git a/ckanext/d4science_theme/templates/user/dashboard_groups.html b/ckanext/d4science_theme/templates/user/dashboard_groups.html new file mode 100644 index 0000000..ecbd041 --- /dev/null +++ b/ckanext/d4science_theme/templates/user/dashboard_groups.html @@ -0,0 +1,65 @@ +{#{% extends "user/dashboard.html" %}#} + +{#{% extends "user/dashboard.html" %}#} +{# CREATED BY FRANCESCO MANGIACRAPA #} + +{% ckan_extends %} +{% set user = c.userobj %} + +{% block breadcrumb_content %} +{% endblock %} + +{% block primary %} +
    + {% block page_header %} + {# CODE ADDED BY Francesco Mangiacrapa #} + {% set hide = h.get_cookie_value('ckan_hide_header') %} + {% if hide=='true' %} + {# NOT SHOW 'Edit settings' #} + {% else %} + + {% endif %} + {% endblock %} +
    + {% if self.page_primary_action() | trim %} +
    + {% block page_primary_action %} + {% if h.check_access('group_create') %} + {% link_for _('Add Group'), controller='group', action='new', class_="btn btn-primary", icon="plus-sign-alt" %} + {% endif %} +{% endblock %} +
    + {% endif %} + {% block primary_content_inner %} +

    {{ _('My Groups') }}

    + {% set groups = h.groups_available(am_member=True) %} + {% if groups %} +
    + {% snippet "group/snippets/group_list_simple.html", groups=groups %} +
    + {% else %} +

    + {{ _('You are not a member of any groups.') }} + {% if h.check_access('group_create') %} + {% link_for _('Create one now?'), controller='group', action='new' %} + {% endif %} +

    + {% endif %} +{% endblock %} +
    +
    +{% endblock %} + +{% block dashboard_activity_stream_context %}{% endblock %} + +{% block secondary %}{% endblock %} diff --git a/ckanext/d4science_theme/templates/user/dashboard_organizations.html b/ckanext/d4science_theme/templates/user/dashboard_organizations.html new file mode 100644 index 0000000..1d2f8d7 --- /dev/null +++ b/ckanext/d4science_theme/templates/user/dashboard_organizations.html @@ -0,0 +1,66 @@ +{#{% extends "user/dashboard.html" %}#} + +{#{% extends "user/dashboard.html" %}#} +{# CREATED BY FRANCESCO MANGIACRAPA #} + +{% ckan_extends %} +{% set user = c.userobj %} + +{% block breadcrumb_content %} +{% endblock %} + +{% block primary %} +
    + {% block page_header %} + {# CODE ADDED BY Francesco Mangiacrapa #} + {% set hide = h.get_cookie_value('ckan_hide_header') %} + {% if hide=='true' %} + {# NOT SHOW 'Edit settings' #} + {% else %} + + {% endif %} + {% endblock %} +
    + {% if self.page_primary_action() | trim %} +
    +{% block page_primary_action %} + {% if h.check_access('organization_create') %} + {% link_for _('Add Organization'), controller='organization', action='new', class_="btn btn-primary", icon="plus-sign-alt" %} + {% endif %} +{% endblock %} +
    + {% endif %} + +{% block primary_content_inner %} +

    {{ _('My Organizations') }}

    + {% set organizations = h.organizations_available() %} + {% if organizations %} +
    + {% snippet "organization/snippets/organization_list.html", organizations=organizations %} +
    + {% else %} +

    + {{ _('You are not a member of any organizations.') }} + {% if h.check_access('organization_create') %} + {% link_for _('Create one now?'), controller='organization', action='new' %} + {% endif %} +

    + {% endif %} +{% endblock %} +
    +
    +{% endblock %} + +{% block dashboard_activity_stream_context %}{% endblock %} + +{% block secondary %}{% endblock %} diff --git a/ckanext/d4science_theme/tests/__init__.py b/ckanext/d4science_theme/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ckanext/d4science_theme/tests/test_plugin.py b/ckanext/d4science_theme/tests/test_plugin.py new file mode 100644 index 0000000..2a75bc2 --- /dev/null +++ b/ckanext/d4science_theme/tests/test_plugin.py @@ -0,0 +1,5 @@ +"""Tests for plugin.py.""" +import ckanext.d4science_theme.plugin as plugin + +def test_plugin(): + pass \ No newline at end of file diff --git a/ckanext_d4science_theme.egg-info/PKG-INFO b/ckanext_d4science_theme.egg-info/PKG-INFO new file mode 100644 index 0000000..68c460f --- /dev/null +++ b/ckanext_d4science_theme.egg-info/PKG-INFO @@ -0,0 +1,185 @@ +Metadata-Version: 1.1 +Name: ckanext-d4science-theme +Version: 0.0.1 +Summary: "D4Science Data Catalog extension for CKAN", + D4Science offers services for seamless access and analysis to a wide spectrum of data including biological and ecological data, + geospatial data, statistical data and semi-structured data from multiple authoritative data providers and information systems. + These services can be exploited both via web based graphical user interfaces and web based protocols for programmatic access, + e.g. OAI-PMH, CSW, WFS, SDMX. This offering nicely complements specific and community-specific applications. +Home-page: https://github.com//ckanext-d4science_theme +Author: Francesco Mangiacrapa +Author-email: francesco.mangiacrapa@isti.cnr.it +License: AGPL +Description: .. You should enable this project on travis-ci.org and coveralls.io to make + these badges work. The necessary Travis and Coverage config files have been + generated for you. + + .. image:: https://travis-ci.org//ckanext-d4science_theme.svg?branch=master + :target: https://travis-ci.org//ckanext-d4science_theme + + .. image:: https://coveralls.io/repos//ckanext-d4science_theme/badge.svg + :target: https://coveralls.io/r//ckanext-d4science_theme + + .. image:: https://pypip.in/download/ckanext-d4science_theme/badge.svg + :target: https://pypi.python.org/pypi//ckanext-d4science_theme/ + :alt: Downloads + + .. image:: https://pypip.in/version/ckanext-d4science_theme/badge.svg + :target: https://pypi.python.org/pypi/ckanext-d4science_theme/ + :alt: Latest Version + + .. image:: https://pypip.in/py_versions/ckanext-d4science_theme/badge.svg + :target: https://pypi.python.org/pypi/ckanext-d4science_theme/ + :alt: Supported Python versions + + .. image:: https://pypip.in/status/ckanext-d4science_theme/badge.svg + :target: https://pypi.python.org/pypi/ckanext-d4science_theme/ + :alt: Development Status + + .. image:: https://pypip.in/license/ckanext-d4science_theme/badge.svg + :target: https://pypi.python.org/pypi/ckanext-d4science_theme/ + :alt: License + + ============= + ckanext-d4science_theme + ============= + + .. Put a description of your extension here: + What does it do? What features does it have? + Consider including some screenshots or embedding a video! + + + ------------ + Requirements + ------------ + + For example, you might want to mention here which versions of CKAN this + extension works with. + + + ------------ + Installation + ------------ + + .. Add any additional install steps to the list below. + For example installing any non-Python dependencies or adding any required + config settings. + + To install ckanext-d4science_theme: + + 1. Activate your CKAN virtual environment, for example:: + + . /usr/lib/ckan/default/bin/activate + + 2. Install the ckanext-d4science_theme Python package into your virtual environment:: + + pip install ckanext-d4science_theme + + 3. Add ``d4science_theme`` to the ``ckan.plugins`` setting in your CKAN + config file (by default the config file is located at + ``/etc/ckan/default/production.ini``). + + 4. Restart CKAN. For example if you've deployed CKAN with Apache on Ubuntu:: + + sudo service apache2 reload + + + --------------- + Config Settings + --------------- + + Document any optional config settings here. For example:: + + # The minimum number of hours to wait before re-checking a resource + # (optional, default: 24). + ckanext.d4science_theme.some_setting = some_default_value + + + ------------------------ + Development Installation + ------------------------ + + To install ckanext-d4science_theme for development, activate your CKAN virtualenv and + do:: + + git clone https://github.com//ckanext-d4science_theme.git + cd ckanext-d4science_theme + python setup.py develop + pip install -r dev-requirements.txt + + + ----------------- + Running the Tests + ----------------- + + To run the tests, do:: + + nosetests --nologcapture --with-pylons=test.ini + + To run the tests and produce a coverage report, first make sure you have + coverage installed in your virtualenv (``pip install coverage``) then run:: + + nosetests --nologcapture --with-pylons=test.ini --with-coverage --cover-package=ckanext.d4science_theme --cover-inclusive --cover-erase --cover-tests + + + --------------------------------- + Registering ckanext-d4science_theme on PyPI + --------------------------------- + + ckanext-d4science_theme should be availabe on PyPI as + https://pypi.python.org/pypi/ckanext-d4science_theme. If that link doesn't work, then + you can register the project on PyPI for the first time by following these + steps: + + 1. Create a source distribution of the project:: + + python setup.py sdist + + 2. Register the project:: + + python setup.py register + + 3. Upload the source distribution to PyPI:: + + python setup.py sdist upload + + 4. Tag the first release of the project on GitHub with the version number from + the ``setup.py`` file. For example if the version number in ``setup.py`` is + 0.0.1 then do:: + + git tag 0.0.1 + git push --tags + + + ---------------------------------------- + Releasing a New Version of ckanext-d4science_theme + ---------------------------------------- + + ckanext-d4science_theme is availabe on PyPI as https://pypi.python.org/pypi/ckanext-d4science_theme. + To publish a new version to PyPI follow these steps: + + 1. Update the version number in the ``setup.py`` file. + See `PEP 440 `_ + for how to choose version numbers. + + 2. Create a source distribution of the new version:: + + python setup.py sdist + + 3. Upload the source distribution to PyPI:: + + python setup.py sdist upload + + 4. Tag the new release of the project on GitHub with the version number from + the ``setup.py`` file. For example if the version number in ``setup.py`` is + 0.0.2 then do:: + + git tag 0.0.2 + git push --tags + +Keywords: CKAN "D4Science Data Catalogue" gCube +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+) +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 diff --git a/ckanext_d4science_theme.egg-info/SOURCES.txt b/ckanext_d4science_theme.egg-info/SOURCES.txt new file mode 100644 index 0000000..8e00ddf --- /dev/null +++ b/ckanext_d4science_theme.egg-info/SOURCES.txt @@ -0,0 +1,40 @@ +MANIFEST.in +README.rst +setup.cfg +setup.py +ckanext/__init__.py +ckanext/d4science_theme/__init__.py +ckanext/d4science_theme/plugin.py +ckanext/d4science_theme/fanstatic/d4science_theme.css +ckanext/d4science_theme/templates/base.html +ckanext/d4science_theme/templates/footer.html +ckanext/d4science_theme/templates/header.html +ckanext/d4science_theme/templates/group/snippets/group_form.html +ckanext/d4science_theme/templates/group/snippets/group_item.html +ckanext/d4science_theme/templates/group/snippets/group_list.html +ckanext/d4science_theme/templates/group/snippets/group_list_simple.html +ckanext/d4science_theme/templates/group/snippets/group_tree.html +ckanext/d4science_theme/templates/home/index.html +ckanext/d4science_theme/templates/home/layout2.html +ckanext/d4science_theme/templates/home/snippets/promoted.html +ckanext/d4science_theme/templates/organization/read.html +ckanext/d4science_theme/templates/organization/read_base.html +ckanext/d4science_theme/templates/package/base.html +ckanext/d4science_theme/templates/package/group_list.html +ckanext/d4science_theme/templates/package/read.html +ckanext/d4science_theme/templates/package/read_base.html +ckanext/d4science_theme/templates/package/resource_read.html +ckanext/d4science_theme/templates/package/search.html +ckanext/d4science_theme/templates/package/snippets/resource_item.html +ckanext/d4science_theme/templates/snippets/package_item.html +ckanext/d4science_theme/templates/user/dashboard.html +ckanext/d4science_theme/templates/user/dashboard_datasets.html +ckanext/d4science_theme/templates/user/dashboard_groups.html +ckanext/d4science_theme/templates/user/dashboard_organizations.html +ckanext/d4science_theme/tests/__init__.py +ckanext/d4science_theme/tests/test_plugin.py +ckanext_d4science_theme.egg-info/PKG-INFO +ckanext_d4science_theme.egg-info/SOURCES.txt +ckanext_d4science_theme.egg-info/dependency_links.txt +ckanext_d4science_theme.egg-info/entry_points.txt +ckanext_d4science_theme.egg-info/top_level.txt \ No newline at end of file diff --git a/ckanext_d4science_theme.egg-info/dependency_links.txt b/ckanext_d4science_theme.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ckanext_d4science_theme.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/ckanext_d4science_theme.egg-info/entry_points.txt b/ckanext_d4science_theme.egg-info/entry_points.txt new file mode 100644 index 0000000..e0d553e --- /dev/null +++ b/ckanext_d4science_theme.egg-info/entry_points.txt @@ -0,0 +1,6 @@ + + [ckan.plugins] + d4science_theme=ckanext.d4science_theme.plugin:D4Science_ThemePlugin + [babel.extractors] + ckan = ckan.lib.extract:extract_ckan + \ No newline at end of file diff --git a/ckanext_d4science_theme.egg-info/top_level.txt b/ckanext_d4science_theme.egg-info/top_level.txt new file mode 100644 index 0000000..0cd8d39 --- /dev/null +++ b/ckanext_d4science_theme.egg-info/top_level.txt @@ -0,0 +1 @@ +ckanext diff --git a/dev-requirements.txt b/dev-requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..54a747d --- /dev/null +++ b/setup.cfg @@ -0,0 +1,21 @@ +[extract_messages] +keywords = translate isPlural +add_comments = TRANSLATORS: +output_file = i18n/ckanext-d4science_theme.pot +width = 80 + +[init_catalog] +domain = ckanext-d4science_theme +input_file = i18n/ckanext-d4science_theme.pot +output_dir = i18n + +[update_catalog] +domain = ckanext-d4science_theme +input_file = i18n/ckanext-d4science_theme.pot +output_dir = i18n +previous = true + +[compile_catalog] +domain = ckanext-d4science_theme +directory = i18n +statistics = true \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..d3a3ba1 --- /dev/null +++ b/setup.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +from setuptools import setup, find_packages # Always prefer setuptools over distutils +from codecs import open # To use a consistent encoding +from os import path + +here = path.abspath(path.dirname(__file__)) + +# Get the long description from the relevant file +with open(path.join(here, 'README.rst'), encoding='utf-8') as f: + long_description = f.read() + +setup( + name='''ckanext-d4science_theme''', + + # Versions should comply with PEP440. For a discussion on single-sourcing + # the version across setup.py and the project code, see + # http://packaging.python.org/en/latest/tutorial.html#version + version='0.0.1', + + description='''"D4Science Data Catalog extension for CKAN", + D4Science offers services for seamless access and analysis to a wide spectrum of data including biological and ecological data, + geospatial data, statistical data and semi-structured data from multiple authoritative data providers and information systems. + These services can be exploited both via web based graphical user interfaces and web based protocols for programmatic access, + e.g. OAI-PMH, CSW, WFS, SDMX. This offering nicely complements specific and community-specific applications.''', + long_description=long_description, + + # The project's main homepage. + url='https://github.com//ckanext-d4science_theme', + + # Author details + author='''Francesco Mangiacrapa''', + author_email='''francesco.mangiacrapa@isti.cnr.it''', + + # Choose your license + license='AGPL', + + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 4 - Beta', + + # Pick your license as you wish (should match "license" above) + 'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)', + + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + ], + + + # What does your project relate to? + keywords='''CKAN "D4Science Data Catalogue" gCube''', + + # You can just specify the packages manually here if your project is + # simple. Or you can use find_packages(). + packages=find_packages(exclude=['contrib', 'docs', 'tests*']), + + # List run-time dependencies here. These will be installed by pip when your + # project is installed. For an analysis of "install_requires" vs pip's + # requirements files see: + # https://packaging.python.org/en/latest/technical.html#install-requires-vs-requirements-files + install_requires=[], + + # If there are data files included in your packages that need to be + # installed, specify them here. If using Python 2.6 or less, then these + # have to be included in MANIFEST.in as well. + include_package_data=True, + package_data={ + }, + + # Although 'package_data' is the preferred approach, in some case you may + # need to place data files outside of your packages. + # see http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files + # In this case, 'data_file' will be installed into '/my_data' + data_files=[], + + # To provide executable scripts, use entry points in preference to the + # "scripts" keyword. Entry points provide cross-platform support and allow + # pip to create the appropriate form of executable for the target platform. + entry_points=''' + [ckan.plugins] + d4science_theme=ckanext.d4science_theme.plugin:D4Science_ThemePlugin + [babel.extractors] + ckan = ckan.lib.extract:extract_ckan + ''', + + # If you are changing from the default layout of your extension, you may + # have to change the message extractors, you can read more about babel + # message extraction at + # http://babel.pocoo.org/docs/messages/#extraction-method-mapping-and-configuration + message_extractors={ + 'ckanext': [ + ('**.py', 'python', None), + ('**.js', 'javascript', None), + ('**/templates/**.html', 'ckan', None), + ], + } +) diff --git a/test.ini b/test.ini new file mode 100644 index 0000000..c7c70e7 --- /dev/null +++ b/test.ini @@ -0,0 +1,49 @@ +[DEFAULT] +debug = false +smtp_server = localhost +error_email_from = paste@localhost + +[server:main] +use = egg:Paste#http +host = 0.0.0.0 +port = 5000 + +[app:main] +use = config:../ckan/test-core.ini + +# Insert any custom config settings to be used when running your extension's +# tests here. + + +# Logging configuration +[loggers] +keys = root, ckan, sqlalchemy + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console + +[logger_ckan] +qualname = ckan +handlers = +level = INFO + +[logger_sqlalchemy] +handlers = +qualname = sqlalchemy.engine +level = WARN + +[handler_console] +class = StreamHandler +args = (sys.stdout,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s] %(message)s \ No newline at end of file